File Index
Files and directories
Sign in
FILE

st-dma-fence-unwrap.c

File preview with syntax highlighting.

linux-6.19.14/drivers/dma-buf/st-dma-fence-unwrap.c C
  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}
~/ Read-only file preview.