drm/nouveau: fix kernel-doc comments
[drm/drm-misc.git] / drivers / dma-buf / st-dma-fence-unwrap.c
bloba3be888ae2e87c0fa3d1ec14ab4070a68c44d7f8
1 // SPDX-License-Identifier: MIT
3 /*
4 * Copyright (C) 2022 Advanced Micro Devices, Inc.
5 */
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>
12 #include "selftest.h"
14 #define CHAIN_SZ (4 << 10)
16 struct mock_fence {
17 struct dma_fence base;
18 spinlock_t lock;
21 static const char *mock_name(struct dma_fence *f)
23 return "mock";
26 static const struct dma_fence_ops mock_ops = {
27 .get_driver_name = mock_name,
28 .get_timeline_name = mock_name,
31 static struct dma_fence *__mock_fence(u64 context, u64 seqno)
33 struct mock_fence *f;
35 f = kmalloc(sizeof(*f), GFP_KERNEL);
36 if (!f)
37 return NULL;
39 spin_lock_init(&f->lock);
40 dma_fence_init(&f->base, &mock_ops, &f->lock, context, seqno);
42 return &f->base;
45 static struct dma_fence *mock_fence(void)
47 return __mock_fence(dma_fence_context_alloc(1), 1);
50 static struct dma_fence *mock_array(unsigned int num_fences, ...)
52 struct dma_fence_array *array;
53 struct dma_fence **fences;
54 va_list valist;
55 int i;
57 fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
58 if (!fences)
59 goto error_put;
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);
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;
73 error_free:
74 kfree(fences);
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;
84 static struct dma_fence *mock_chain(struct dma_fence *prev,
85 struct dma_fence *fence)
87 struct dma_fence_chain *f;
89 f = dma_fence_chain_alloc();
90 if (!f) {
91 dma_fence_put(prev);
92 dma_fence_put(fence);
93 return NULL;
96 dma_fence_chain_init(f, prev, fence, 1);
97 return &f->base;
100 static int sanitycheck(void *arg)
102 struct dma_fence *f, *chain, *array;
103 int err = 0;
105 f = mock_fence();
106 if (!f)
107 return -ENOMEM;
109 dma_fence_enable_sw_signaling(f);
111 array = mock_array(1, f);
112 if (!array)
113 return -ENOMEM;
115 chain = mock_chain(NULL, array);
116 if (!chain)
117 return -ENOMEM;
119 dma_fence_put(chain);
120 return err;
123 static int unwrap_array(void *arg)
125 struct dma_fence *fence, *f1, *f2, *array;
126 struct dma_fence_unwrap iter;
127 int err = 0;
129 f1 = mock_fence();
130 if (!f1)
131 return -ENOMEM;
133 dma_fence_enable_sw_signaling(f1);
135 f2 = mock_fence();
136 if (!f2) {
137 dma_fence_put(f1);
138 return -ENOMEM;
141 dma_fence_enable_sw_signaling(f2);
143 array = mock_array(2, f1, f2);
144 if (!array)
145 return -ENOMEM;
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;
158 if (f1 || f2) {
159 pr_err("Not all fences seen!\n");
160 err = -EINVAL;
163 dma_fence_put(array);
164 return err;
167 static int unwrap_chain(void *arg)
169 struct dma_fence *fence, *f1, *f2, *chain;
170 struct dma_fence_unwrap iter;
171 int err = 0;
173 f1 = mock_fence();
174 if (!f1)
175 return -ENOMEM;
177 dma_fence_enable_sw_signaling(f1);
179 f2 = mock_fence();
180 if (!f2) {
181 dma_fence_put(f1);
182 return -ENOMEM;
185 dma_fence_enable_sw_signaling(f2);
187 chain = mock_chain(f1, f2);
188 if (!chain)
189 return -ENOMEM;
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;
202 if (f1 || f2) {
203 pr_err("Not all fences seen!\n");
204 err = -EINVAL;
207 dma_fence_put(chain);
208 return err;
211 static int unwrap_chain_array(void *arg)
213 struct dma_fence *fence, *f1, *f2, *array, *chain;
214 struct dma_fence_unwrap iter;
215 int err = 0;
217 f1 = mock_fence();
218 if (!f1)
219 return -ENOMEM;
221 dma_fence_enable_sw_signaling(f1);
223 f2 = mock_fence();
224 if (!f2) {
225 dma_fence_put(f1);
226 return -ENOMEM;
229 dma_fence_enable_sw_signaling(f2);
231 array = mock_array(2, f1, f2);
232 if (!array)
233 return -ENOMEM;
235 chain = mock_chain(NULL, array);
236 if (!chain)
237 return -ENOMEM;
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;
250 if (f1 || f2) {
251 pr_err("Not all fences seen!\n");
252 err = -EINVAL;
255 dma_fence_put(chain);
256 return err;
259 static int unwrap_merge(void *arg)
261 struct dma_fence *fence, *f1, *f2, *f3;
262 struct dma_fence_unwrap iter;
263 int err = 0;
265 f1 = mock_fence();
266 if (!f1)
267 return -ENOMEM;
269 dma_fence_enable_sw_signaling(f1);
271 f2 = mock_fence();
272 if (!f2) {
273 err = -ENOMEM;
274 goto error_put_f1;
277 dma_fence_enable_sw_signaling(f2);
279 f3 = dma_fence_unwrap_merge(f1, f2);
280 if (!f3) {
281 err = -ENOMEM;
282 goto error_put_f2;
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;
298 if (f1 || f2) {
299 pr_err("Not all fences seen!\n");
300 err = -EINVAL;
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;
311 static int unwrap_merge_duplicate(void *arg)
313 struct dma_fence *fence, *f1, *f2;
314 struct dma_fence_unwrap iter;
315 int err = 0;
317 f1 = mock_fence();
318 if (!f1)
319 return -ENOMEM;
321 dma_fence_enable_sw_signaling(f1);
323 f2 = dma_fence_unwrap_merge(f1, f1);
324 if (!f2) {
325 err = -ENOMEM;
326 goto error_put_f1;
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;
339 if (f1) {
340 pr_err("Not all fences seen!\n");
341 err = -EINVAL;
344 dma_fence_put(f2);
345 error_put_f1:
346 dma_fence_put(f1);
347 return err;
350 static int unwrap_merge_seqno(void *arg)
352 struct dma_fence *fence, *f1, *f2, *f3, *f4;
353 struct dma_fence_unwrap iter;
354 int err = 0;
355 u64 ctx[2];
357 ctx[0] = dma_fence_context_alloc(1);
358 ctx[1] = dma_fence_context_alloc(1);
360 f1 = __mock_fence(ctx[1], 1);
361 if (!f1)
362 return -ENOMEM;
364 dma_fence_enable_sw_signaling(f1);
366 f2 = __mock_fence(ctx[1], 2);
367 if (!f2) {
368 err = -ENOMEM;
369 goto error_put_f1;
372 dma_fence_enable_sw_signaling(f2);
374 f3 = __mock_fence(ctx[0], 1);
375 if (!f3) {
376 err = -ENOMEM;
377 goto error_put_f2;
380 dma_fence_enable_sw_signaling(f3);
382 f4 = dma_fence_unwrap_merge(f1, f2, f3);
383 if (!f4) {
384 err = -ENOMEM;
385 goto error_put_f3;
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;
401 if (f2 || f3) {
402 pr_err("Not all fences seen!\n");
403 err = -EINVAL;
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;
416 static int unwrap_merge_order(void *arg)
418 struct dma_fence *fence, *f1, *f2, *a1, *a2, *c1, *c2;
419 struct dma_fence_unwrap iter;
420 int err = 0;
422 f1 = mock_fence();
423 if (!f1)
424 return -ENOMEM;
426 dma_fence_enable_sw_signaling(f1);
428 f2 = mock_fence();
429 if (!f2) {
430 dma_fence_put(f1);
431 return -ENOMEM;
434 dma_fence_enable_sw_signaling(f2);
436 a1 = mock_array(2, f1, f2);
437 if (!a1)
438 return -ENOMEM;
440 c1 = mock_chain(NULL, dma_fence_get(f1));
441 if (!c1)
442 goto error_put_a1;
444 c2 = mock_chain(c1, dma_fence_get(f2));
445 if (!c2)
446 goto error_put_a1;
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.
452 a2 = dma_fence_unwrap_merge(a1, c2);
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;
469 if (f1 || f2) {
470 pr_err("Not all fences seen!\n");
471 err = -EINVAL;
474 dma_fence_put(a2);
475 return err;
477 error_put_a1:
478 dma_fence_put(a1);
479 return -ENOMEM;
482 static int unwrap_merge_complex(void *arg)
484 struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5;
485 struct dma_fence_unwrap iter;
486 int err = -ENOMEM;
488 f1 = mock_fence();
489 if (!f1)
490 return -ENOMEM;
492 dma_fence_enable_sw_signaling(f1);
494 f2 = mock_fence();
495 if (!f2)
496 goto error_put_f1;
498 dma_fence_enable_sw_signaling(f2);
500 f3 = dma_fence_unwrap_merge(f1, f2);
501 if (!f3)
502 goto error_put_f2;
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;
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;
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;
528 if (f1 || f2) {
529 pr_err("Not all fences seen!\n");
530 err = -EINVAL;
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;
545 static int unwrap_merge_complex_seqno(void *arg)
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];
552 ctx[0] = dma_fence_context_alloc(1);
553 ctx[1] = dma_fence_context_alloc(1);
555 f1 = __mock_fence(ctx[0], 2);
556 if (!f1)
557 return -ENOMEM;
559 dma_fence_enable_sw_signaling(f1);
561 f2 = __mock_fence(ctx[1], 1);
562 if (!f2)
563 goto error_put_f1;
565 dma_fence_enable_sw_signaling(f2);
567 f3 = __mock_fence(ctx[0], 1);
568 if (!f3)
569 goto error_put_f2;
571 dma_fence_enable_sw_signaling(f3);
573 f4 = __mock_fence(ctx[1], 2);
574 if (!f4)
575 goto error_put_f3;
577 dma_fence_enable_sw_signaling(f4);
579 f5 = mock_array(2, dma_fence_get(f1), dma_fence_get(f2));
580 if (!f5)
581 goto error_put_f4;
583 f6 = mock_array(2, dma_fence_get(f3), dma_fence_get(f4));
584 if (!f6)
585 goto error_put_f5;
587 f7 = dma_fence_unwrap_merge(f5, f6);
588 if (!f7)
589 goto error_put_f6;
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;
605 if (f1 || f4) {
606 pr_err("Not all fences seen!\n");
607 err = -EINVAL;
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;
626 int dma_fence_unwrap(void)
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),
641 return subtests(tests, NULL);