Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/dma-buf/st-dma-fence.c
26278 views
1
/* SPDX-License-Identifier: MIT */
2
3
/*
4
* Copyright © 2019 Intel Corporation
5
*/
6
7
#include <linux/delay.h>
8
#include <linux/dma-fence.h>
9
#include <linux/kernel.h>
10
#include <linux/kthread.h>
11
#include <linux/sched/signal.h>
12
#include <linux/slab.h>
13
#include <linux/spinlock.h>
14
15
#include "selftest.h"
16
17
static struct kmem_cache *slab_fences;
18
19
static struct mock_fence {
20
struct dma_fence base;
21
struct spinlock lock;
22
} *to_mock_fence(struct dma_fence *f) {
23
return container_of(f, struct mock_fence, base);
24
}
25
26
static const char *mock_name(struct dma_fence *f)
27
{
28
return "mock";
29
}
30
31
static void mock_fence_release(struct dma_fence *f)
32
{
33
kmem_cache_free(slab_fences, to_mock_fence(f));
34
}
35
36
struct wait_cb {
37
struct dma_fence_cb cb;
38
struct task_struct *task;
39
};
40
41
static void mock_wakeup(struct dma_fence *f, struct dma_fence_cb *cb)
42
{
43
wake_up_process(container_of(cb, struct wait_cb, cb)->task);
44
}
45
46
static long mock_wait(struct dma_fence *f, bool intr, long timeout)
47
{
48
const int state = intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
49
struct wait_cb cb = { .task = current };
50
51
if (dma_fence_add_callback(f, &cb.cb, mock_wakeup))
52
return timeout;
53
54
while (timeout) {
55
set_current_state(state);
56
57
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags))
58
break;
59
60
if (signal_pending_state(state, current))
61
break;
62
63
timeout = schedule_timeout(timeout);
64
}
65
__set_current_state(TASK_RUNNING);
66
67
if (!dma_fence_remove_callback(f, &cb.cb))
68
return timeout;
69
70
if (signal_pending_state(state, current))
71
return -ERESTARTSYS;
72
73
return -ETIME;
74
}
75
76
static const struct dma_fence_ops mock_ops = {
77
.get_driver_name = mock_name,
78
.get_timeline_name = mock_name,
79
.wait = mock_wait,
80
.release = mock_fence_release,
81
};
82
83
static struct dma_fence *mock_fence(void)
84
{
85
struct mock_fence *f;
86
87
f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
88
if (!f)
89
return NULL;
90
91
spin_lock_init(&f->lock);
92
dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
93
94
return &f->base;
95
}
96
97
static int sanitycheck(void *arg)
98
{
99
struct dma_fence *f;
100
101
f = mock_fence();
102
if (!f)
103
return -ENOMEM;
104
105
dma_fence_enable_sw_signaling(f);
106
107
dma_fence_signal(f);
108
dma_fence_put(f);
109
110
return 0;
111
}
112
113
static int test_signaling(void *arg)
114
{
115
struct dma_fence *f;
116
int err = -EINVAL;
117
118
f = mock_fence();
119
if (!f)
120
return -ENOMEM;
121
122
dma_fence_enable_sw_signaling(f);
123
124
if (dma_fence_is_signaled(f)) {
125
pr_err("Fence unexpectedly signaled on creation\n");
126
goto err_free;
127
}
128
129
if (dma_fence_signal(f)) {
130
pr_err("Fence reported being already signaled\n");
131
goto err_free;
132
}
133
134
if (!dma_fence_is_signaled(f)) {
135
pr_err("Fence not reporting signaled\n");
136
goto err_free;
137
}
138
139
if (!dma_fence_signal(f)) {
140
pr_err("Fence reported not being already signaled\n");
141
goto err_free;
142
}
143
144
err = 0;
145
err_free:
146
dma_fence_put(f);
147
return err;
148
}
149
150
struct simple_cb {
151
struct dma_fence_cb cb;
152
bool seen;
153
};
154
155
static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb)
156
{
157
smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true);
158
}
159
160
static int test_add_callback(void *arg)
161
{
162
struct simple_cb cb = {};
163
struct dma_fence *f;
164
int err = -EINVAL;
165
166
f = mock_fence();
167
if (!f)
168
return -ENOMEM;
169
170
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
171
pr_err("Failed to add callback, fence already signaled!\n");
172
goto err_free;
173
}
174
175
dma_fence_signal(f);
176
if (!cb.seen) {
177
pr_err("Callback failed!\n");
178
goto err_free;
179
}
180
181
err = 0;
182
err_free:
183
dma_fence_put(f);
184
return err;
185
}
186
187
static int test_late_add_callback(void *arg)
188
{
189
struct simple_cb cb = {};
190
struct dma_fence *f;
191
int err = -EINVAL;
192
193
f = mock_fence();
194
if (!f)
195
return -ENOMEM;
196
197
dma_fence_enable_sw_signaling(f);
198
199
dma_fence_signal(f);
200
201
if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) {
202
pr_err("Added callback, but fence was already signaled!\n");
203
goto err_free;
204
}
205
206
dma_fence_signal(f);
207
if (cb.seen) {
208
pr_err("Callback called after failed attachment !\n");
209
goto err_free;
210
}
211
212
err = 0;
213
err_free:
214
dma_fence_put(f);
215
return err;
216
}
217
218
static int test_rm_callback(void *arg)
219
{
220
struct simple_cb cb = {};
221
struct dma_fence *f;
222
int err = -EINVAL;
223
224
f = mock_fence();
225
if (!f)
226
return -ENOMEM;
227
228
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
229
pr_err("Failed to add callback, fence already signaled!\n");
230
goto err_free;
231
}
232
233
if (!dma_fence_remove_callback(f, &cb.cb)) {
234
pr_err("Failed to remove callback!\n");
235
goto err_free;
236
}
237
238
dma_fence_signal(f);
239
if (cb.seen) {
240
pr_err("Callback still signaled after removal!\n");
241
goto err_free;
242
}
243
244
err = 0;
245
err_free:
246
dma_fence_put(f);
247
return err;
248
}
249
250
static int test_late_rm_callback(void *arg)
251
{
252
struct simple_cb cb = {};
253
struct dma_fence *f;
254
int err = -EINVAL;
255
256
f = mock_fence();
257
if (!f)
258
return -ENOMEM;
259
260
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
261
pr_err("Failed to add callback, fence already signaled!\n");
262
goto err_free;
263
}
264
265
dma_fence_signal(f);
266
if (!cb.seen) {
267
pr_err("Callback failed!\n");
268
goto err_free;
269
}
270
271
if (dma_fence_remove_callback(f, &cb.cb)) {
272
pr_err("Callback removal succeed after being executed!\n");
273
goto err_free;
274
}
275
276
err = 0;
277
err_free:
278
dma_fence_put(f);
279
return err;
280
}
281
282
static int test_status(void *arg)
283
{
284
struct dma_fence *f;
285
int err = -EINVAL;
286
287
f = mock_fence();
288
if (!f)
289
return -ENOMEM;
290
291
dma_fence_enable_sw_signaling(f);
292
293
if (dma_fence_get_status(f)) {
294
pr_err("Fence unexpectedly has signaled status on creation\n");
295
goto err_free;
296
}
297
298
dma_fence_signal(f);
299
if (!dma_fence_get_status(f)) {
300
pr_err("Fence not reporting signaled status\n");
301
goto err_free;
302
}
303
304
err = 0;
305
err_free:
306
dma_fence_put(f);
307
return err;
308
}
309
310
static int test_error(void *arg)
311
{
312
struct dma_fence *f;
313
int err = -EINVAL;
314
315
f = mock_fence();
316
if (!f)
317
return -ENOMEM;
318
319
dma_fence_enable_sw_signaling(f);
320
321
dma_fence_set_error(f, -EIO);
322
323
if (dma_fence_get_status(f)) {
324
pr_err("Fence unexpectedly has error status before signal\n");
325
goto err_free;
326
}
327
328
dma_fence_signal(f);
329
if (dma_fence_get_status(f) != -EIO) {
330
pr_err("Fence not reporting error status, got %d\n",
331
dma_fence_get_status(f));
332
goto err_free;
333
}
334
335
err = 0;
336
err_free:
337
dma_fence_put(f);
338
return err;
339
}
340
341
static int test_wait(void *arg)
342
{
343
struct dma_fence *f;
344
int err = -EINVAL;
345
346
f = mock_fence();
347
if (!f)
348
return -ENOMEM;
349
350
dma_fence_enable_sw_signaling(f);
351
352
if (dma_fence_wait_timeout(f, false, 0) != -ETIME) {
353
pr_err("Wait reported complete before being signaled\n");
354
goto err_free;
355
}
356
357
dma_fence_signal(f);
358
359
if (dma_fence_wait_timeout(f, false, 0) != 0) {
360
pr_err("Wait reported incomplete after being signaled\n");
361
goto err_free;
362
}
363
364
err = 0;
365
err_free:
366
dma_fence_signal(f);
367
dma_fence_put(f);
368
return err;
369
}
370
371
struct wait_timer {
372
struct timer_list timer;
373
struct dma_fence *f;
374
};
375
376
static void wait_timer(struct timer_list *timer)
377
{
378
struct wait_timer *wt = timer_container_of(wt, timer, timer);
379
380
dma_fence_signal(wt->f);
381
}
382
383
static int test_wait_timeout(void *arg)
384
{
385
struct wait_timer wt;
386
int err = -EINVAL;
387
388
timer_setup_on_stack(&wt.timer, wait_timer, 0);
389
390
wt.f = mock_fence();
391
if (!wt.f)
392
return -ENOMEM;
393
394
dma_fence_enable_sw_signaling(wt.f);
395
396
if (dma_fence_wait_timeout(wt.f, false, 1) != -ETIME) {
397
pr_err("Wait reported complete before being signaled\n");
398
goto err_free;
399
}
400
401
mod_timer(&wt.timer, jiffies + 1);
402
403
if (dma_fence_wait_timeout(wt.f, false, 2) == -ETIME) {
404
if (timer_pending(&wt.timer)) {
405
pr_notice("Timer did not fire within the jiffy!\n");
406
err = 0; /* not our fault! */
407
} else {
408
pr_err("Wait reported incomplete after timeout\n");
409
}
410
goto err_free;
411
}
412
413
err = 0;
414
err_free:
415
timer_delete_sync(&wt.timer);
416
timer_destroy_on_stack(&wt.timer);
417
dma_fence_signal(wt.f);
418
dma_fence_put(wt.f);
419
return err;
420
}
421
422
static int test_stub(void *arg)
423
{
424
struct dma_fence *f[64];
425
int err = -EINVAL;
426
int i;
427
428
for (i = 0; i < ARRAY_SIZE(f); i++) {
429
f[i] = dma_fence_get_stub();
430
if (!dma_fence_is_signaled(f[i])) {
431
pr_err("Obtained unsignaled stub fence!\n");
432
goto err;
433
}
434
}
435
436
err = 0;
437
err:
438
while (i--)
439
dma_fence_put(f[i]);
440
return err;
441
}
442
443
/* Now off to the races! */
444
445
struct race_thread {
446
struct dma_fence __rcu **fences;
447
struct task_struct *task;
448
bool before;
449
int id;
450
};
451
452
static void __wait_for_callbacks(struct dma_fence *f)
453
{
454
spin_lock_irq(f->lock);
455
spin_unlock_irq(f->lock);
456
}
457
458
static int thread_signal_callback(void *arg)
459
{
460
const struct race_thread *t = arg;
461
unsigned long pass = 0;
462
unsigned long miss = 0;
463
int err = 0;
464
465
while (!err && !kthread_should_stop()) {
466
struct dma_fence *f1, *f2;
467
struct simple_cb cb;
468
469
f1 = mock_fence();
470
if (!f1) {
471
err = -ENOMEM;
472
break;
473
}
474
475
dma_fence_enable_sw_signaling(f1);
476
477
rcu_assign_pointer(t->fences[t->id], f1);
478
smp_wmb();
479
480
rcu_read_lock();
481
do {
482
f2 = dma_fence_get_rcu_safe(&t->fences[!t->id]);
483
} while (!f2 && !kthread_should_stop());
484
rcu_read_unlock();
485
486
if (t->before)
487
dma_fence_signal(f1);
488
489
smp_store_mb(cb.seen, false);
490
if (!f2 ||
491
dma_fence_add_callback(f2, &cb.cb, simple_callback)) {
492
miss++;
493
cb.seen = true;
494
}
495
496
if (!t->before)
497
dma_fence_signal(f1);
498
499
if (!cb.seen) {
500
dma_fence_wait(f2, false);
501
__wait_for_callbacks(f2);
502
}
503
504
if (!READ_ONCE(cb.seen)) {
505
pr_err("Callback not seen on thread %d, pass %lu (%lu misses), signaling %s add_callback; fence signaled? %s\n",
506
t->id, pass, miss,
507
t->before ? "before" : "after",
508
dma_fence_is_signaled(f2) ? "yes" : "no");
509
err = -EINVAL;
510
}
511
512
dma_fence_put(f2);
513
514
rcu_assign_pointer(t->fences[t->id], NULL);
515
smp_wmb();
516
517
dma_fence_put(f1);
518
519
pass++;
520
}
521
522
pr_info("%s[%d] completed %lu passes, %lu misses\n",
523
__func__, t->id, pass, miss);
524
return err;
525
}
526
527
static int race_signal_callback(void *arg)
528
{
529
struct dma_fence __rcu *f[2] = {};
530
int ret = 0;
531
int pass;
532
533
for (pass = 0; !ret && pass <= 1; pass++) {
534
struct race_thread t[2];
535
int i;
536
537
for (i = 0; i < ARRAY_SIZE(t); i++) {
538
t[i].fences = f;
539
t[i].id = i;
540
t[i].before = pass;
541
t[i].task = kthread_run(thread_signal_callback, &t[i],
542
"dma-fence:%d", i);
543
if (IS_ERR(t[i].task)) {
544
ret = PTR_ERR(t[i].task);
545
while (--i >= 0)
546
kthread_stop_put(t[i].task);
547
return ret;
548
}
549
get_task_struct(t[i].task);
550
}
551
552
msleep(50);
553
554
for (i = 0; i < ARRAY_SIZE(t); i++) {
555
int err;
556
557
err = kthread_stop_put(t[i].task);
558
if (err && !ret)
559
ret = err;
560
}
561
}
562
563
return ret;
564
}
565
566
int dma_fence(void)
567
{
568
static const struct subtest tests[] = {
569
SUBTEST(sanitycheck),
570
SUBTEST(test_signaling),
571
SUBTEST(test_add_callback),
572
SUBTEST(test_late_add_callback),
573
SUBTEST(test_rm_callback),
574
SUBTEST(test_late_rm_callback),
575
SUBTEST(test_status),
576
SUBTEST(test_error),
577
SUBTEST(test_wait),
578
SUBTEST(test_wait_timeout),
579
SUBTEST(test_stub),
580
SUBTEST(race_signal_callback),
581
};
582
int ret;
583
584
pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence));
585
586
slab_fences = KMEM_CACHE(mock_fence,
587
SLAB_TYPESAFE_BY_RCU |
588
SLAB_HWCACHE_ALIGN);
589
if (!slab_fences)
590
return -ENOMEM;
591
592
ret = subtests(tests, NULL);
593
594
kmem_cache_destroy(slab_fences);
595
596
return ret;
597
}
598
599