Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/dma-buf/st-dma-resv.c
26278 views
1
/* SPDX-License-Identifier: MIT */
2
3
/*
4
* Copyright © 2019 Intel Corporation
5
* Copyright © 2021 Advanced Micro Devices, Inc.
6
*/
7
8
#include <linux/slab.h>
9
#include <linux/spinlock.h>
10
#include <linux/dma-resv.h>
11
12
#include "selftest.h"
13
14
static struct spinlock fence_lock;
15
16
static const char *fence_name(struct dma_fence *f)
17
{
18
return "selftest";
19
}
20
21
static const struct dma_fence_ops fence_ops = {
22
.get_driver_name = fence_name,
23
.get_timeline_name = fence_name,
24
};
25
26
static struct dma_fence *alloc_fence(void)
27
{
28
struct dma_fence *f;
29
30
f = kmalloc(sizeof(*f), GFP_KERNEL);
31
if (!f)
32
return NULL;
33
34
dma_fence_init(f, &fence_ops, &fence_lock, 0, 0);
35
return f;
36
}
37
38
static int sanitycheck(void *arg)
39
{
40
struct dma_resv resv;
41
struct dma_fence *f;
42
int r;
43
44
f = alloc_fence();
45
if (!f)
46
return -ENOMEM;
47
48
dma_fence_enable_sw_signaling(f);
49
50
dma_fence_signal(f);
51
dma_fence_put(f);
52
53
dma_resv_init(&resv);
54
r = dma_resv_lock(&resv, NULL);
55
if (r)
56
pr_err("Resv locking failed\n");
57
else
58
dma_resv_unlock(&resv);
59
dma_resv_fini(&resv);
60
return r;
61
}
62
63
static int test_signaling(void *arg)
64
{
65
enum dma_resv_usage usage = (unsigned long)arg;
66
struct dma_resv resv;
67
struct dma_fence *f;
68
int r;
69
70
f = alloc_fence();
71
if (!f)
72
return -ENOMEM;
73
74
dma_fence_enable_sw_signaling(f);
75
76
dma_resv_init(&resv);
77
r = dma_resv_lock(&resv, NULL);
78
if (r) {
79
pr_err("Resv locking failed\n");
80
goto err_free;
81
}
82
83
r = dma_resv_reserve_fences(&resv, 1);
84
if (r) {
85
pr_err("Resv shared slot allocation failed\n");
86
goto err_unlock;
87
}
88
89
dma_resv_add_fence(&resv, f, usage);
90
if (dma_resv_test_signaled(&resv, usage)) {
91
pr_err("Resv unexpectedly signaled\n");
92
r = -EINVAL;
93
goto err_unlock;
94
}
95
dma_fence_signal(f);
96
if (!dma_resv_test_signaled(&resv, usage)) {
97
pr_err("Resv not reporting signaled\n");
98
r = -EINVAL;
99
goto err_unlock;
100
}
101
err_unlock:
102
dma_resv_unlock(&resv);
103
err_free:
104
dma_resv_fini(&resv);
105
dma_fence_put(f);
106
return r;
107
}
108
109
static int test_for_each(void *arg)
110
{
111
enum dma_resv_usage usage = (unsigned long)arg;
112
struct dma_resv_iter cursor;
113
struct dma_fence *f, *fence;
114
struct dma_resv resv;
115
int r;
116
117
f = alloc_fence();
118
if (!f)
119
return -ENOMEM;
120
121
dma_fence_enable_sw_signaling(f);
122
123
dma_resv_init(&resv);
124
r = dma_resv_lock(&resv, NULL);
125
if (r) {
126
pr_err("Resv locking failed\n");
127
goto err_free;
128
}
129
130
r = dma_resv_reserve_fences(&resv, 1);
131
if (r) {
132
pr_err("Resv shared slot allocation failed\n");
133
goto err_unlock;
134
}
135
136
dma_resv_add_fence(&resv, f, usage);
137
138
r = -ENOENT;
139
dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
140
if (!r) {
141
pr_err("More than one fence found\n");
142
r = -EINVAL;
143
goto err_unlock;
144
}
145
if (f != fence) {
146
pr_err("Unexpected fence\n");
147
r = -EINVAL;
148
goto err_unlock;
149
}
150
if (dma_resv_iter_usage(&cursor) != usage) {
151
pr_err("Unexpected fence usage\n");
152
r = -EINVAL;
153
goto err_unlock;
154
}
155
r = 0;
156
}
157
if (r) {
158
pr_err("No fence found\n");
159
goto err_unlock;
160
}
161
dma_fence_signal(f);
162
err_unlock:
163
dma_resv_unlock(&resv);
164
err_free:
165
dma_resv_fini(&resv);
166
dma_fence_put(f);
167
return r;
168
}
169
170
static int test_for_each_unlocked(void *arg)
171
{
172
enum dma_resv_usage usage = (unsigned long)arg;
173
struct dma_resv_iter cursor;
174
struct dma_fence *f, *fence;
175
struct dma_resv resv;
176
int r;
177
178
f = alloc_fence();
179
if (!f)
180
return -ENOMEM;
181
182
dma_fence_enable_sw_signaling(f);
183
184
dma_resv_init(&resv);
185
r = dma_resv_lock(&resv, NULL);
186
if (r) {
187
pr_err("Resv locking failed\n");
188
goto err_free;
189
}
190
191
r = dma_resv_reserve_fences(&resv, 1);
192
if (r) {
193
pr_err("Resv shared slot allocation failed\n");
194
dma_resv_unlock(&resv);
195
goto err_free;
196
}
197
198
dma_resv_add_fence(&resv, f, usage);
199
dma_resv_unlock(&resv);
200
201
r = -ENOENT;
202
dma_resv_iter_begin(&cursor, &resv, usage);
203
dma_resv_for_each_fence_unlocked(&cursor, fence) {
204
if (!r) {
205
pr_err("More than one fence found\n");
206
r = -EINVAL;
207
goto err_iter_end;
208
}
209
if (!dma_resv_iter_is_restarted(&cursor)) {
210
pr_err("No restart flag\n");
211
goto err_iter_end;
212
}
213
if (f != fence) {
214
pr_err("Unexpected fence\n");
215
r = -EINVAL;
216
goto err_iter_end;
217
}
218
if (dma_resv_iter_usage(&cursor) != usage) {
219
pr_err("Unexpected fence usage\n");
220
r = -EINVAL;
221
goto err_iter_end;
222
}
223
224
/* We use r as state here */
225
if (r == -ENOENT) {
226
r = -EINVAL;
227
/* That should trigger an restart */
228
cursor.fences = (void*)~0;
229
} else if (r == -EINVAL) {
230
r = 0;
231
}
232
}
233
if (r)
234
pr_err("No fence found\n");
235
err_iter_end:
236
dma_resv_iter_end(&cursor);
237
dma_fence_signal(f);
238
err_free:
239
dma_resv_fini(&resv);
240
dma_fence_put(f);
241
return r;
242
}
243
244
static int test_get_fences(void *arg)
245
{
246
enum dma_resv_usage usage = (unsigned long)arg;
247
struct dma_fence *f, **fences = NULL;
248
struct dma_resv resv;
249
int r, i;
250
251
f = alloc_fence();
252
if (!f)
253
return -ENOMEM;
254
255
dma_fence_enable_sw_signaling(f);
256
257
dma_resv_init(&resv);
258
r = dma_resv_lock(&resv, NULL);
259
if (r) {
260
pr_err("Resv locking failed\n");
261
goto err_resv;
262
}
263
264
r = dma_resv_reserve_fences(&resv, 1);
265
if (r) {
266
pr_err("Resv shared slot allocation failed\n");
267
dma_resv_unlock(&resv);
268
goto err_resv;
269
}
270
271
dma_resv_add_fence(&resv, f, usage);
272
dma_resv_unlock(&resv);
273
274
r = dma_resv_get_fences(&resv, usage, &i, &fences);
275
if (r) {
276
pr_err("get_fences failed\n");
277
goto err_free;
278
}
279
280
if (i != 1 || fences[0] != f) {
281
pr_err("get_fences returned unexpected fence\n");
282
goto err_free;
283
}
284
285
dma_fence_signal(f);
286
err_free:
287
while (i--)
288
dma_fence_put(fences[i]);
289
kfree(fences);
290
err_resv:
291
dma_resv_fini(&resv);
292
dma_fence_put(f);
293
return r;
294
}
295
296
int dma_resv(void)
297
{
298
static const struct subtest tests[] = {
299
SUBTEST(sanitycheck),
300
SUBTEST(test_signaling),
301
SUBTEST(test_for_each),
302
SUBTEST(test_for_each_unlocked),
303
SUBTEST(test_get_fences),
304
};
305
enum dma_resv_usage usage;
306
int r;
307
308
spin_lock_init(&fence_lock);
309
for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
310
++usage) {
311
r = subtests(tests, (void *)(unsigned long)usage);
312
if (r)
313
return r;
314
}
315
return 0;
316
}
317
318