xref: /linux/drivers/dma-buf/st-dma-fence-unwrap.c (revision 7a9b709e7cc5ce1ffb84ce07bf6d157e1de758df)
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 
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 
31 static 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 
45 static struct dma_fence *mock_fence(void)
46 {
47 	return __mock_fence(dma_fence_context_alloc(1), 1);
48 }
49 
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 = 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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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