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