xref: /linux/drivers/dma-buf/st-dma-fence.c (revision 1fc5a74b108fc90951890ec513ac81869f5eaff1)
1 /* SPDX-License-Identifier: MIT */
2 
3 /*
4  * Copyright © 2019 Intel Corporation
5  */
6 
7 #include <kunit/test.h>
8 #include <linux/delay.h>
9 #include <linux/dma-fence.h>
10 #include <linux/kernel.h>
11 #include <linux/kthread.h>
12 #include <linux/sched/signal.h>
13 #include <linux/slab.h>
14 #include <linux/spinlock.h>
15 
mock_name(struct dma_fence * f)16 static const char *mock_name(struct dma_fence *f)
17 {
18 	return "mock";
19 }
20 
21 static const struct dma_fence_ops mock_ops = {
22 	.get_driver_name = mock_name,
23 	.get_timeline_name = mock_name,
24 };
25 
mock_fence(void)26 static struct dma_fence *mock_fence(void)
27 {
28 	struct dma_fence *f;
29 
30 	f = kmalloc_obj(*f);
31 	if (!f)
32 		return NULL;
33 
34 	dma_fence_init(f, &mock_ops, NULL, 0, 0);
35 	return f;
36 }
37 
test_sanitycheck(struct kunit * test)38 static void test_sanitycheck(struct kunit *test)
39 {
40 	struct dma_fence *f;
41 
42 	f = mock_fence();
43 	KUNIT_ASSERT_NOT_NULL(test, f);
44 
45 	dma_fence_enable_signaling(f);
46 
47 	dma_fence_signal(f);
48 	dma_fence_put(f);
49 }
50 
test_signaling(struct kunit * test)51 static void test_signaling(struct kunit *test)
52 {
53 	struct dma_fence *f;
54 
55 	f = mock_fence();
56 	KUNIT_ASSERT_NOT_NULL(test, f);
57 
58 	dma_fence_enable_signaling(f);
59 
60 	if (dma_fence_is_signaled(f)) {
61 		KUNIT_FAIL(test, "Fence unexpectedly signaled on creation");
62 		goto err_free;
63 	}
64 
65 	if (dma_fence_check_and_signal(f)) {
66 		KUNIT_FAIL(test, "Fence reported being already signaled");
67 		goto err_free;
68 	}
69 
70 	if (!dma_fence_is_signaled(f)) {
71 		KUNIT_FAIL(test, "Fence not reporting signaled");
72 		goto err_free;
73 	}
74 
75 	if (!dma_fence_test_signaled_flag(f)) {
76 		KUNIT_FAIL(test, "Fence reported not being already signaled");
77 		goto err_free;
78 	}
79 
80 	if (rcu_dereference_protected(f->ops, true)) {
81 		KUNIT_FAIL(test, "Fence ops not cleared on signal");
82 		goto err_free;
83 	}
84 
85 err_free:
86 	dma_fence_put(f);
87 }
88 
89 struct simple_cb {
90 	struct dma_fence_cb cb;
91 	bool seen;
92 };
93 
simple_callback(struct dma_fence * f,struct dma_fence_cb * cb)94 static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb)
95 {
96 	smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true);
97 }
98 
test_add_callback(struct kunit * test)99 static void test_add_callback(struct kunit *test)
100 {
101 	struct simple_cb cb = {};
102 	struct dma_fence *f;
103 
104 	f = mock_fence();
105 	KUNIT_ASSERT_NOT_NULL(test, f);
106 
107 	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
108 		KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
109 		goto err_free;
110 	}
111 
112 	dma_fence_signal(f);
113 	if (!cb.seen) {
114 		KUNIT_FAIL(test, "Callback failed!");
115 		goto err_free;
116 	}
117 
118 err_free:
119 	dma_fence_put(f);
120 }
121 
test_late_add_callback(struct kunit * test)122 static void test_late_add_callback(struct kunit *test)
123 {
124 	struct simple_cb cb = {};
125 	struct dma_fence *f;
126 
127 	f = mock_fence();
128 	KUNIT_ASSERT_NOT_NULL(test, f);
129 
130 	dma_fence_enable_signaling(f);
131 
132 	dma_fence_signal(f);
133 
134 	if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) {
135 		KUNIT_FAIL(test, "Added callback, but fence was already signaled!");
136 		goto err_free;
137 	}
138 
139 	dma_fence_signal(f);
140 	if (cb.seen) {
141 		KUNIT_FAIL(test, "Callback called after failed attachment!");
142 		goto err_free;
143 	}
144 
145 err_free:
146 	dma_fence_put(f);
147 }
148 
test_rm_callback(struct kunit * test)149 static void test_rm_callback(struct kunit *test)
150 {
151 	struct simple_cb cb = {};
152 	struct dma_fence *f;
153 
154 	f = mock_fence();
155 	KUNIT_ASSERT_NOT_NULL(test, f);
156 
157 	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
158 		KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
159 		goto err_free;
160 	}
161 
162 	if (!dma_fence_remove_callback(f, &cb.cb)) {
163 		KUNIT_FAIL(test, "Failed to remove callback!");
164 		goto err_free;
165 	}
166 
167 	dma_fence_signal(f);
168 	if (cb.seen) {
169 		KUNIT_FAIL(test, "Callback still signaled after removal!");
170 		goto err_free;
171 	}
172 
173 err_free:
174 	dma_fence_put(f);
175 }
176 
test_late_rm_callback(struct kunit * test)177 static void test_late_rm_callback(struct kunit *test)
178 {
179 	struct simple_cb cb = {};
180 	struct dma_fence *f;
181 
182 	f = mock_fence();
183 	KUNIT_ASSERT_NOT_NULL(test, f);
184 
185 	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
186 		KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
187 		goto err_free;
188 	}
189 
190 	dma_fence_signal(f);
191 	if (!cb.seen) {
192 		KUNIT_FAIL(test, "Callback failed!");
193 		goto err_free;
194 	}
195 
196 	if (dma_fence_remove_callback(f, &cb.cb)) {
197 		KUNIT_FAIL(test, "Callback removal succeeded after being executed!");
198 		goto err_free;
199 	}
200 
201 err_free:
202 	dma_fence_put(f);
203 }
204 
test_status(struct kunit * test)205 static void test_status(struct kunit *test)
206 {
207 	struct dma_fence *f;
208 
209 	f = mock_fence();
210 	KUNIT_ASSERT_NOT_NULL(test, f);
211 
212 	dma_fence_enable_signaling(f);
213 
214 	if (dma_fence_get_status(f)) {
215 		KUNIT_FAIL(test, "Fence unexpectedly has signaled status on creation");
216 		goto err_free;
217 	}
218 
219 	dma_fence_signal(f);
220 	if (!dma_fence_get_status(f)) {
221 		KUNIT_FAIL(test, "Fence not reporting signaled status");
222 		goto err_free;
223 	}
224 
225 err_free:
226 	dma_fence_put(f);
227 }
228 
test_error(struct kunit * test)229 static void test_error(struct kunit *test)
230 {
231 	struct dma_fence *f;
232 
233 	f = mock_fence();
234 	KUNIT_ASSERT_NOT_NULL(test, f);
235 
236 	dma_fence_enable_signaling(f);
237 
238 	dma_fence_set_error(f, -EIO);
239 
240 	if (dma_fence_get_status(f)) {
241 		KUNIT_FAIL(test, "Fence unexpectedly has error status before signal");
242 		goto err_free;
243 	}
244 
245 	dma_fence_signal(f);
246 	if (dma_fence_get_status(f) != -EIO) {
247 		KUNIT_FAIL(test, "Fence not reporting error status, got %d",
248 			   dma_fence_get_status(f));
249 		goto err_free;
250 	}
251 
252 err_free:
253 	dma_fence_put(f);
254 }
255 
test_wait(struct kunit * test)256 static void test_wait(struct kunit *test)
257 {
258 	struct dma_fence *f;
259 
260 	f = mock_fence();
261 	KUNIT_ASSERT_NOT_NULL(test, f);
262 
263 	dma_fence_enable_signaling(f);
264 
265 	if (dma_fence_wait_timeout(f, false, 0) != 0) {
266 		KUNIT_FAIL(test, "Wait reported complete before being signaled");
267 		goto err_free;
268 	}
269 
270 	dma_fence_signal(f);
271 
272 	if (dma_fence_wait_timeout(f, false, 0) != 1) {
273 		KUNIT_FAIL(test, "Wait reported incomplete after being signaled");
274 		goto err_free;
275 	}
276 
277 err_free:
278 	dma_fence_signal(f);
279 	dma_fence_put(f);
280 }
281 
282 struct wait_timer {
283 	struct timer_list timer;
284 	struct dma_fence *f;
285 };
286 
wait_timer(struct timer_list * timer)287 static void wait_timer(struct timer_list *timer)
288 {
289 	struct wait_timer *wt = timer_container_of(wt, timer, timer);
290 
291 	dma_fence_signal(wt->f);
292 }
293 
test_wait_timeout(struct kunit * test)294 static void test_wait_timeout(struct kunit *test)
295 {
296 	struct wait_timer wt;
297 
298 	timer_setup_on_stack(&wt.timer, wait_timer, 0);
299 
300 	wt.f = mock_fence();
301 	KUNIT_ASSERT_NOT_NULL(test, wt.f);
302 
303 	dma_fence_enable_signaling(wt.f);
304 
305 	if (dma_fence_wait_timeout(wt.f, false, 1) != 0) {
306 		KUNIT_FAIL(test, "Wait reported complete before being signaled");
307 		goto err_free;
308 	}
309 
310 	mod_timer(&wt.timer, jiffies + 1);
311 
312 	if (dma_fence_wait_timeout(wt.f, false, HZ) == 0) {
313 		if (timer_pending(&wt.timer)) {
314 			kunit_mark_skipped(
315 				test, "Timer did not fire within on HZ!\n");
316 		} else {
317 			KUNIT_FAIL(test,
318 				   "Wait reported incomplete after timeout");
319 		}
320 		goto err_free;
321 	}
322 
323 err_free:
324 	timer_delete_sync(&wt.timer);
325 	timer_destroy_on_stack(&wt.timer);
326 	dma_fence_signal(wt.f);
327 	dma_fence_put(wt.f);
328 }
329 
test_stub(struct kunit * test)330 static void test_stub(struct kunit *test)
331 {
332 	struct dma_fence *f[64];
333 	int i;
334 
335 	for (i = 0; i < ARRAY_SIZE(f); i++) {
336 		f[i] = dma_fence_get_stub();
337 		if (!dma_fence_is_signaled(f[i])) {
338 			KUNIT_FAIL(test, "Obtained unsignaled stub fence!");
339 			goto err;
340 		}
341 	}
342 
343 err:
344 	while (i--)
345 		dma_fence_put(f[i]);
346 }
347 
348 /* Now off to the races! */
349 
350 struct race_thread {
351 	struct dma_fence __rcu **fences;
352 	struct task_struct *task;
353 	bool before;
354 	int id;
355 };
356 
__wait_for_callbacks(struct dma_fence * f)357 static void __wait_for_callbacks(struct dma_fence *f)
358 {
359 	unsigned long flags;
360 
361 	dma_fence_lock_irqsave(f, flags);
362 	dma_fence_unlock_irqrestore(f, flags);
363 }
364 
thread_signal_callback(void * arg)365 static int thread_signal_callback(void *arg)
366 {
367 	const struct race_thread *t = arg;
368 	unsigned long pass = 0;
369 	unsigned long miss = 0;
370 	int err = 0;
371 
372 	while (!err && !kthread_should_stop()) {
373 		struct dma_fence *f1, *f2;
374 		struct simple_cb cb;
375 
376 		f1 = mock_fence();
377 		if (!f1) {
378 			err = -ENOMEM;
379 			break;
380 		}
381 
382 		dma_fence_enable_signaling(f1);
383 
384 		rcu_assign_pointer(t->fences[t->id], f1);
385 		smp_wmb();
386 
387 		rcu_read_lock();
388 		do {
389 			f2 = dma_fence_get_rcu_safe(&t->fences[!t->id]);
390 		} while (!f2 && !kthread_should_stop());
391 		rcu_read_unlock();
392 
393 		if (t->before)
394 			dma_fence_signal(f1);
395 
396 		smp_store_mb(cb.seen, false);
397 		if (!f2 ||
398 		    dma_fence_add_callback(f2, &cb.cb, simple_callback)) {
399 			miss++;
400 			cb.seen = true;
401 		}
402 
403 		if (!t->before)
404 			dma_fence_signal(f1);
405 
406 		if (!cb.seen) {
407 			dma_fence_wait(f2, false);
408 			__wait_for_callbacks(f2);
409 		}
410 
411 		if (!READ_ONCE(cb.seen)) {
412 			pr_err("Callback not seen on thread %d, pass %lu (%lu misses), signaling %s add_callback; fence signaled? %s\n",
413 			       t->id, pass, miss,
414 			       t->before ? "before" : "after",
415 			       dma_fence_is_signaled(f2) ? "yes" : "no");
416 			err = -EINVAL;
417 		}
418 
419 		dma_fence_put(f2);
420 
421 		rcu_assign_pointer(t->fences[t->id], NULL);
422 		smp_wmb();
423 
424 		dma_fence_put(f1);
425 
426 		pass++;
427 	}
428 
429 	pr_info("%s[%d] completed %lu passes, %lu misses\n",
430 		__func__, t->id, pass, miss);
431 	return err;
432 }
433 
test_race_signal_callback(struct kunit * test)434 static void test_race_signal_callback(struct kunit *test)
435 {
436 	struct dma_fence __rcu *f[2] = {};
437 	int ret = 0;
438 	int pass;
439 
440 	/*
441 	 * thread_signal_callback() spins under RCU and it cannot make forward
442 	 * progress unless the threads are truly running concurrently.
443 	 */
444 	if (num_online_cpus() < 2)
445 		kunit_skip(test, "requires at least 2 CPUs");
446 
447 	for (pass = 0; !ret && pass <= 1; pass++) {
448 		struct race_thread t[2];
449 		int i;
450 
451 		for (i = 0; i < ARRAY_SIZE(t); i++) {
452 			t[i].fences = f;
453 			t[i].id = i;
454 			t[i].before = pass;
455 			t[i].task = kthread_run(thread_signal_callback, &t[i],
456 						"dma-fence:%d", i);
457 			if (IS_ERR(t[i].task)) {
458 				KUNIT_FAIL(test, "Failed to create kthread");
459 				while (--i >= 0)
460 					kthread_stop_put(t[i].task);
461 				return;
462 			}
463 			get_task_struct(t[i].task);
464 		}
465 
466 		msleep(50);
467 
468 		for (i = 0; i < ARRAY_SIZE(t); i++) {
469 			int err;
470 
471 			err = kthread_stop_put(t[i].task);
472 			if (err && !ret)
473 				ret = err;
474 		}
475 	}
476 
477 	KUNIT_EXPECT_EQ(test, ret, 0);
478 }
479 
dma_fence_suite_init(struct kunit_suite * suite)480 static int dma_fence_suite_init(struct kunit_suite *suite)
481 {
482 	pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence));
483 	return 0;
484 }
485 
486 static struct kunit_case dma_fence_cases[] = {
487 	KUNIT_CASE(test_sanitycheck),
488 	KUNIT_CASE(test_signaling),
489 	KUNIT_CASE(test_add_callback),
490 	KUNIT_CASE(test_late_add_callback),
491 	KUNIT_CASE(test_rm_callback),
492 	KUNIT_CASE(test_late_rm_callback),
493 	KUNIT_CASE(test_status),
494 	KUNIT_CASE(test_error),
495 	KUNIT_CASE(test_wait),
496 	KUNIT_CASE(test_wait_timeout),
497 	KUNIT_CASE(test_stub),
498 	KUNIT_CASE(test_race_signal_callback),
499 	{}
500 };
501 
502 static struct kunit_suite dma_fence_test_suite = {
503 	.name = "dma-buf-fence",
504 	.suite_init = dma_fence_suite_init,
505 	.test_cases = dma_fence_cases,
506 };
507 
508 kunit_test_suite(dma_fence_test_suite);
509