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
fence_name(struct dma_fence * f)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
alloc_fence(void)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
sanitycheck(void * arg)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
test_signaling(void * arg)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
test_for_each(void * arg)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
test_for_each_unlocked(void * arg)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
test_get_fences(void * arg)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
dma_resv(void)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