1 // SPDX-License-Identifier: MIT
2
3 /*
4 * Copyright (C) 2022 Advanced Micro Devices, Inc.
5 */
6
7 #include <linux/dma-fence.h>
8 #include <linux/dma-fence-array.h>
9 #include <linux/dma-fence-chain.h>
10 #include <linux/dma-fence-unwrap.h>
11
12 #include "selftest.h"
13
14 #define CHAIN_SZ (4 << 10)
15
16 struct mock_fence {
17 struct dma_fence base;
18 spinlock_t lock;
19 };
20
mock_name(struct dma_fence * f)21 static const char *mock_name(struct dma_fence *f)
22 {
23 return "mock";
24 }
25
26 static const struct dma_fence_ops mock_ops = {
27 .get_driver_name = mock_name,
28 .get_timeline_name = mock_name,
29 };
30
__mock_fence(u64 context,u64 seqno)31 static struct dma_fence *__mock_fence(u64 context, u64 seqno)
32 {
33 struct mock_fence *f;
34
35 f = kmalloc_obj(*f);
36 if (!f)
37 return NULL;
38
39 spin_lock_init(&f->lock);
40 dma_fence_init(&f->base, &mock_ops, &f->lock, context, seqno);
41
42 return &f->base;
43 }
44
mock_fence(void)45 static struct dma_fence *mock_fence(void)
46 {
47 return __mock_fence(dma_fence_context_alloc(1), 1);
48 }
49
mock_array(unsigned int num_fences,...)50 static struct dma_fence *mock_array(unsigned int num_fences, ...)
51 {
52 struct dma_fence_array *array;
53 struct dma_fence **fences;
54 va_list valist;
55 int i;
56
57 fences = kzalloc_objs(*fences, num_fences);
58 if (!fences)
59 goto error_put;
60
61 va_start(valist, num_fences);
62 for (i = 0; i < num_fences; ++i)
63 fences[i] = va_arg(valist, typeof(*fences));
64 va_end(valist);
65
66 array = dma_fence_array_create(num_fences, fences,
67 dma_fence_context_alloc(1),
68 1, false);
69 if (!array)
70 goto error_free;
71 return &array->base;
72
73 error_free:
74 kfree(fences);
75
76 error_put:
77 va_start(valist, num_fences);
78 for (i = 0; i < num_fences; ++i)
79 dma_fence_put(va_arg(valist, typeof(*fences)));
80 va_end(valist);
81 return NULL;
82 }
83
mock_chain(struct dma_fence * prev,struct dma_fence * fence)84 static struct dma_fence *mock_chain(struct dma_fence *prev,
85 struct dma_fence *fence)
86 {
87 struct dma_fence_chain *f;
88
89 f = dma_fence_chain_alloc();
90 if (!f) {
91 dma_fence_put(prev);
92 dma_fence_put(fence);
93 return NULL;
94 }
95
96 dma_fence_chain_init(f, prev, fence, 1);
97 return &f->base;
98 }
99
sanitycheck(void * arg)100 static int sanitycheck(void *arg)
101 {
102 struct dma_fence *f, *chain, *array;
103 int err = 0;
104
105 f = mock_fence();
106 if (!f)
107 return -ENOMEM;
108
109 dma_fence_enable_sw_signaling(f);
110
111 array = mock_array(1, f);
112 if (!array)
113 return -ENOMEM;
114
115 chain = mock_chain(NULL, array);
116 if (!chain)
117 return -ENOMEM;
118
119 dma_fence_put(chain);
120 return err;
121 }
122
unwrap_array(void * arg)123 static int unwrap_array(void *arg)
124 {
125 struct dma_fence *fence, *f1, *f2, *array;
126 struct dma_fence_unwrap iter;
127 int err = 0;
128
129 f1 = mock_fence();
130 if (!f1)
131 return -ENOMEM;
132
133 dma_fence_enable_sw_signaling(f1);
134
135 f2 = mock_fence();
136 if (!f2) {
137 dma_fence_put(f1);
138 return -ENOMEM;
139 }
140
141 dma_fence_enable_sw_signaling(f2);
142
143 array = mock_array(2, f1, f2);
144 if (!array)
145 return -ENOMEM;
146
147 dma_fence_unwrap_for_each(fence, &iter, array) {
148 if (fence == f1) {
149 f1 = NULL;
150 } else if (fence == f2) {
151 f2 = NULL;
152 } else {
153 pr_err("Unexpected fence!\n");
154 err = -EINVAL;
155 }
156 }
157
158 if (f1 || f2) {
159 pr_err("Not all fences seen!\n");
160 err = -EINVAL;
161 }
162
163 dma_fence_put(array);
164 return err;
165 }
166
unwrap_chain(void * arg)167 static int unwrap_chain(void *arg)
168 {
169 struct dma_fence *fence, *f1, *f2, *chain;
170 struct dma_fence_unwrap iter;
171 int err = 0;
172
173 f1 = mock_fence();
174 if (!f1)
175 return -ENOMEM;
176
177 dma_fence_enable_sw_signaling(f1);
178
179 f2 = mock_fence();
180 if (!f2) {
181 dma_fence_put(f1);
182 return -ENOMEM;
183 }
184
185 dma_fence_enable_sw_signaling(f2);
186
187 chain = mock_chain(f1, f2);
188 if (!chain)
189 return -ENOMEM;
190
191 dma_fence_unwrap_for_each(fence, &iter, chain) {
192 if (fence == f1) {
193 f1 = NULL;
194 } else if (fence == f2) {
195 f2 = NULL;
196 } else {
197 pr_err("Unexpected fence!\n");
198 err = -EINVAL;
199 }
200 }
201
202 if (f1 || f2) {
203 pr_err("Not all fences seen!\n");
204 err = -EINVAL;
205 }
206
207 dma_fence_put(chain);
208 return err;
209 }
210
unwrap_chain_array(void * arg)211 static int unwrap_chain_array(void *arg)
212 {
213 struct dma_fence *fence, *f1, *f2, *array, *chain;
214 struct dma_fence_unwrap iter;
215 int err = 0;
216
217 f1 = mock_fence();
218 if (!f1)
219 return -ENOMEM;
220
221 dma_fence_enable_sw_signaling(f1);
222
223 f2 = mock_fence();
224 if (!f2) {
225 dma_fence_put(f1);
226 return -ENOMEM;
227 }
228
229 dma_fence_enable_sw_signaling(f2);
230
231 array = mock_array(2, f1, f2);
232 if (!array)
233 return -ENOMEM;
234
235 chain = mock_chain(NULL, array);
236 if (!chain)
237 return -ENOMEM;
238
239 dma_fence_unwrap_for_each(fence, &iter, chain) {
240 if (fence == f1) {
241 f1 = NULL;
242 } else if (fence == f2) {
243 f2 = NULL;
244 } else {
245 pr_err("Unexpected fence!\n");
246 err = -EINVAL;
247 }
248 }
249
250 if (f1 || f2) {
251 pr_err("Not all fences seen!\n");
252 err = -EINVAL;
253 }
254
255 dma_fence_put(chain);
256 return err;
257 }
258
unwrap_merge(void * arg)259 static int unwrap_merge(void *arg)
260 {
261 struct dma_fence *fence, *f1, *f2, *f3;
262 struct dma_fence_unwrap iter;
263 int err = 0;
264
265 f1 = mock_fence();
266 if (!f1)
267 return -ENOMEM;
268
269 dma_fence_enable_sw_signaling(f1);
270
271 f2 = mock_fence();
272 if (!f2) {
273 err = -ENOMEM;
274 goto error_put_f1;
275 }
276
277 dma_fence_enable_sw_signaling(f2);
278
279 f3 = dma_fence_unwrap_merge(f1, f2);
280 if (!f3) {
281 err = -ENOMEM;
282 goto error_put_f2;
283 }
284
285 dma_fence_unwrap_for_each(fence, &iter, f3) {
286 if (fence == f1) {
287 dma_fence_put(f1);
288 f1 = NULL;
289 } else if (fence == f2) {
290 dma_fence_put(f2);
291 f2 = NULL;
292 } else {
293 pr_err("Unexpected fence!\n");
294 err = -EINVAL;
295 }
296 }
297
298 if (f1 || f2) {
299 pr_err("Not all fences seen!\n");
300 err = -EINVAL;
301 }
302
303 dma_fence_put(f3);
304 error_put_f2:
305 dma_fence_put(f2);
306 error_put_f1:
307 dma_fence_put(f1);
308 return err;
309 }
310
unwrap_merge_duplicate(void * arg)311 static int unwrap_merge_duplicate(void *arg)
312 {
313 struct dma_fence *fence, *f1, *f2;
314 struct dma_fence_unwrap iter;
315 int err = 0;
316
317 f1 = mock_fence();
318 if (!f1)
319 return -ENOMEM;
320
321 dma_fence_enable_sw_signaling(f1);
322
323 f2 = dma_fence_unwrap_merge(f1, f1);
324 if (!f2) {
325 err = -ENOMEM;
326 goto error_put_f1;
327 }
328
329 dma_fence_unwrap_for_each(fence, &iter, f2) {
330 if (fence == f1) {
331 dma_fence_put(f1);
332 f1 = NULL;
333 } else {
334 pr_err("Unexpected fence!\n");
335 err = -EINVAL;
336 }
337 }
338
339 if (f1) {
340 pr_err("Not all fences seen!\n");
341 err = -EINVAL;
342 }
343
344 dma_fence_put(f2);
345 error_put_f1:
346 dma_fence_put(f1);
347 return err;
348 }
349
unwrap_merge_seqno(void * arg)350 static int unwrap_merge_seqno(void *arg)
351 {
352 struct dma_fence *fence, *f1, *f2, *f3, *f4;
353 struct dma_fence_unwrap iter;
354 int err = 0;
355 u64 ctx[2];
356
357 ctx[0] = dma_fence_context_alloc(1);
358 ctx[1] = dma_fence_context_alloc(1);
359
360 f1 = __mock_fence(ctx[1], 1);
361 if (!f1)
362 return -ENOMEM;
363
364 dma_fence_enable_sw_signaling(f1);
365
366 f2 = __mock_fence(ctx[1], 2);
367 if (!f2) {
368 err = -ENOMEM;
369 goto error_put_f1;
370 }
371
372 dma_fence_enable_sw_signaling(f2);
373
374 f3 = __mock_fence(ctx[0], 1);
375 if (!f3) {
376 err = -ENOMEM;
377 goto error_put_f2;
378 }
379
380 dma_fence_enable_sw_signaling(f3);
381
382 f4 = dma_fence_unwrap_merge(f1, f2, f3);
383 if (!f4) {
384 err = -ENOMEM;
385 goto error_put_f3;
386 }
387
388 dma_fence_unwrap_for_each(fence, &iter, f4) {
389 if (fence == f3 && f2) {
390 dma_fence_put(f3);
391 f3 = NULL;
392 } else if (fence == f2 && !f3) {
393 dma_fence_put(f2);
394 f2 = NULL;
395 } else {
396 pr_err("Unexpected fence!\n");
397 err = -EINVAL;
398 }
399 }
400
401 if (f2 || f3) {
402 pr_err("Not all fences seen!\n");
403 err = -EINVAL;
404 }
405
406 dma_fence_put(f4);
407 error_put_f3:
408 dma_fence_put(f3);
409 error_put_f2:
410 dma_fence_put(f2);
411 error_put_f1:
412 dma_fence_put(f1);
413 return err;
414 }
415
unwrap_merge_order(void * arg)416 static int unwrap_merge_order(void *arg)
417 {
418 struct dma_fence *fence, *f1, *f2, *a1, *a2, *c1, *c2;
419 struct dma_fence_unwrap iter;
420 int err = 0;
421
422 f1 = mock_fence();
423 if (!f1)
424 return -ENOMEM;
425
426 dma_fence_enable_sw_signaling(f1);
427
428 f2 = mock_fence();
429 if (!f2) {
430 dma_fence_put(f1);
431 return -ENOMEM;
432 }
433
434 dma_fence_enable_sw_signaling(f2);
435
436 a1 = mock_array(2, f1, f2);
437 if (!a1)
438 return -ENOMEM;
439
440 c1 = mock_chain(NULL, dma_fence_get(f1));
441 if (!c1)
442 goto error_put_a1;
443
444 c2 = mock_chain(c1, dma_fence_get(f2));
445 if (!c2)
446 goto error_put_a1;
447
448 /*
449 * The fences in the chain are the same as in a1 but in oposite order,
450 * the dma_fence_merge() function should be able to handle that.
451 */
452 a2 = dma_fence_unwrap_merge(a1, c2);
453
454 dma_fence_unwrap_for_each(fence, &iter, a2) {
455 if (fence == f1) {
456 f1 = NULL;
457 if (!f2)
458 pr_err("Unexpected order!\n");
459 } else if (fence == f2) {
460 f2 = NULL;
461 if (f1)
462 pr_err("Unexpected order!\n");
463 } else {
464 pr_err("Unexpected fence!\n");
465 err = -EINVAL;
466 }
467 }
468
469 if (f1 || f2) {
470 pr_err("Not all fences seen!\n");
471 err = -EINVAL;
472 }
473
474 dma_fence_put(a2);
475 return err;
476
477 error_put_a1:
478 dma_fence_put(a1);
479 return -ENOMEM;
480 }
481
unwrap_merge_complex(void * arg)482 static int unwrap_merge_complex(void *arg)
483 {
484 struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5;
485 struct dma_fence_unwrap iter;
486 int err = -ENOMEM;
487
488 f1 = mock_fence();
489 if (!f1)
490 return -ENOMEM;
491
492 dma_fence_enable_sw_signaling(f1);
493
494 f2 = mock_fence();
495 if (!f2)
496 goto error_put_f1;
497
498 dma_fence_enable_sw_signaling(f2);
499
500 f3 = dma_fence_unwrap_merge(f1, f2);
501 if (!f3)
502 goto error_put_f2;
503
504 /* The resulting array has the fences in reverse */
505 f4 = mock_array(2, dma_fence_get(f2), dma_fence_get(f1));
506 if (!f4)
507 goto error_put_f3;
508
509 /* Signaled fences should be filtered, the two arrays merged. */
510 f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub());
511 if (!f5)
512 goto error_put_f4;
513
514 err = 0;
515 dma_fence_unwrap_for_each(fence, &iter, f5) {
516 if (fence == f1) {
517 dma_fence_put(f1);
518 f1 = NULL;
519 } else if (fence == f2) {
520 dma_fence_put(f2);
521 f2 = NULL;
522 } else {
523 pr_err("Unexpected fence!\n");
524 err = -EINVAL;
525 }
526 }
527
528 if (f1 || f2) {
529 pr_err("Not all fences seen!\n");
530 err = -EINVAL;
531 }
532
533 dma_fence_put(f5);
534 error_put_f4:
535 dma_fence_put(f4);
536 error_put_f3:
537 dma_fence_put(f3);
538 error_put_f2:
539 dma_fence_put(f2);
540 error_put_f1:
541 dma_fence_put(f1);
542 return err;
543 }
544
unwrap_merge_complex_seqno(void * arg)545 static int unwrap_merge_complex_seqno(void *arg)
546 {
547 struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5, *f6, *f7;
548 struct dma_fence_unwrap iter;
549 int err = -ENOMEM;
550 u64 ctx[2];
551
552 ctx[0] = dma_fence_context_alloc(1);
553 ctx[1] = dma_fence_context_alloc(1);
554
555 f1 = __mock_fence(ctx[0], 2);
556 if (!f1)
557 return -ENOMEM;
558
559 dma_fence_enable_sw_signaling(f1);
560
561 f2 = __mock_fence(ctx[1], 1);
562 if (!f2)
563 goto error_put_f1;
564
565 dma_fence_enable_sw_signaling(f2);
566
567 f3 = __mock_fence(ctx[0], 1);
568 if (!f3)
569 goto error_put_f2;
570
571 dma_fence_enable_sw_signaling(f3);
572
573 f4 = __mock_fence(ctx[1], 2);
574 if (!f4)
575 goto error_put_f3;
576
577 dma_fence_enable_sw_signaling(f4);
578
579 f5 = mock_array(2, dma_fence_get(f1), dma_fence_get(f2));
580 if (!f5)
581 goto error_put_f4;
582
583 f6 = mock_array(2, dma_fence_get(f3), dma_fence_get(f4));
584 if (!f6)
585 goto error_put_f5;
586
587 f7 = dma_fence_unwrap_merge(f5, f6);
588 if (!f7)
589 goto error_put_f6;
590
591 err = 0;
592 dma_fence_unwrap_for_each(fence, &iter, f7) {
593 if (fence == f1 && f4) {
594 dma_fence_put(f1);
595 f1 = NULL;
596 } else if (fence == f4 && !f1) {
597 dma_fence_put(f4);
598 f4 = NULL;
599 } else {
600 pr_err("Unexpected fence!\n");
601 err = -EINVAL;
602 }
603 }
604
605 if (f1 || f4) {
606 pr_err("Not all fences seen!\n");
607 err = -EINVAL;
608 }
609
610 dma_fence_put(f7);
611 error_put_f6:
612 dma_fence_put(f6);
613 error_put_f5:
614 dma_fence_put(f5);
615 error_put_f4:
616 dma_fence_put(f4);
617 error_put_f3:
618 dma_fence_put(f3);
619 error_put_f2:
620 dma_fence_put(f2);
621 error_put_f1:
622 dma_fence_put(f1);
623 return err;
624 }
625
dma_fence_unwrap(void)626 int dma_fence_unwrap(void)
627 {
628 static const struct subtest tests[] = {
629 SUBTEST(sanitycheck),
630 SUBTEST(unwrap_array),
631 SUBTEST(unwrap_chain),
632 SUBTEST(unwrap_chain_array),
633 SUBTEST(unwrap_merge),
634 SUBTEST(unwrap_merge_duplicate),
635 SUBTEST(unwrap_merge_seqno),
636 SUBTEST(unwrap_merge_order),
637 SUBTEST(unwrap_merge_complex),
638 SUBTEST(unwrap_merge_complex_seqno),
639 };
640
641 return subtests(tests, NULL);
642 }
643