xref: /linux/drivers/dma-buf/st-dma-fence.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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;
to_mock_fence(struct dma_fence * f)22 } *to_mock_fence(struct dma_fence *f) {
23 	return container_of(f, struct mock_fence, base);
24 }
25 
mock_name(struct dma_fence * f)26 static const char *mock_name(struct dma_fence *f)
27 {
28 	return "mock";
29 }
30 
mock_fence_release(struct dma_fence * f)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 
mock_wakeup(struct dma_fence * f,struct dma_fence_cb * cb)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 
mock_wait(struct dma_fence * f,bool intr,long timeout)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 
mock_fence(void)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 
sanitycheck(void * arg)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 
test_signaling(void * arg)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 
simple_callback(struct dma_fence * f,struct dma_fence_cb * cb)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 
test_add_callback(void * arg)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 
test_late_add_callback(void * arg)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 
test_rm_callback(void * arg)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 
test_late_rm_callback(void * arg)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 
test_status(void * arg)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 
test_error(void * arg)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 
test_wait(void * arg)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 
wait_timer(struct timer_list * timer)376 static void wait_timer(struct timer_list *timer)
377 {
378 	struct wait_timer *wt = from_timer(wt, timer, timer);
379 
380 	dma_fence_signal(wt->f);
381 }
382 
test_wait_timeout(void * arg)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 	del_timer_sync(&wt.timer);
416 	destroy_timer_on_stack(&wt.timer);
417 	dma_fence_signal(wt.f);
418 	dma_fence_put(wt.f);
419 	return err;
420 }
421 
test_stub(void * arg)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 
__wait_for_callbacks(struct dma_fence * f)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 
thread_signal_callback(void * arg)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 
race_signal_callback(void * arg)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 
dma_fence(void)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