Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
16struct mock_fence {
17 struct dma_fence base;
18 spinlock_t lock;
19};
20
21static const char *mock_name(struct dma_fence *f)
22{
23 return "mock";
24}
25
26static const struct dma_fence_ops mock_ops = {
27 .get_driver_name = mock_name,
28 .get_timeline_name = mock_name,
29};
30
31static struct dma_fence *__mock_fence(u64 context, u64 seqno)
32{
33 struct mock_fence *f;
34
35 f = kmalloc(sizeof(*f), GFP_KERNEL);
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
45static struct dma_fence *mock_fence(void)
46{
47 return __mock_fence(dma_fence_context_alloc(1), 1);
48}
49
50static 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 = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
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
73error_free:
74 kfree(fences);
75
76error_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
84static 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
100static 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
123static 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
167static 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
211static 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
259static 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);
304error_put_f2:
305 dma_fence_put(f2);
306error_put_f1:
307 dma_fence_put(f1);
308 return err;
309}
310
311static 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);
345error_put_f1:
346 dma_fence_put(f1);
347 return err;
348}
349
350static 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);
407error_put_f3:
408 dma_fence_put(f3);
409error_put_f2:
410 dma_fence_put(f2);
411error_put_f1:
412 dma_fence_put(f1);
413 return err;
414}
415
416static 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
477error_put_a1:
478 dma_fence_put(a1);
479 return -ENOMEM;
480}
481
482static 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);
534error_put_f4:
535 dma_fence_put(f4);
536error_put_f3:
537 dma_fence_put(f3);
538error_put_f2:
539 dma_fence_put(f2);
540error_put_f1:
541 dma_fence_put(f1);
542 return err;
543}
544
545static 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);
611error_put_f6:
612 dma_fence_put(f6);
613error_put_f5:
614 dma_fence_put(f5);
615error_put_f4:
616 dma_fence_put(f4);
617error_put_f3:
618 dma_fence_put(f3);
619error_put_f2:
620 dma_fence_put(f2);
621error_put_f1:
622 dma_fence_put(f1);
623 return err;
624}
625
626int 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}