Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/dma-buf/st-dma-fence-unwrap.c
26278 views
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
644