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