12989f645SChris Wilson /* SPDX-License-Identifier: MIT */ 22989f645SChris Wilson 32989f645SChris Wilson /* 42989f645SChris Wilson * Copyright © 2019 Intel Corporation 52989f645SChris Wilson */ 62989f645SChris Wilson 72989f645SChris Wilson #include <linux/delay.h> 82989f645SChris Wilson #include <linux/dma-fence.h> 92989f645SChris Wilson #include <linux/kernel.h> 102989f645SChris Wilson #include <linux/kthread.h> 112989f645SChris Wilson #include <linux/sched/signal.h> 122989f645SChris Wilson #include <linux/slab.h> 132989f645SChris Wilson #include <linux/spinlock.h> 142989f645SChris Wilson 152989f645SChris Wilson #include "selftest.h" 162989f645SChris Wilson 172989f645SChris Wilson static struct kmem_cache *slab_fences; 182989f645SChris Wilson 192989f645SChris Wilson static struct mock_fence { 202989f645SChris Wilson struct dma_fence base; 212989f645SChris Wilson struct spinlock lock; 222989f645SChris Wilson } *to_mock_fence(struct dma_fence *f) { 232989f645SChris Wilson return container_of(f, struct mock_fence, base); 242989f645SChris Wilson } 252989f645SChris Wilson 262989f645SChris Wilson static const char *mock_name(struct dma_fence *f) 272989f645SChris Wilson { 282989f645SChris Wilson return "mock"; 292989f645SChris Wilson } 302989f645SChris Wilson 312989f645SChris Wilson static void mock_fence_release(struct dma_fence *f) 322989f645SChris Wilson { 332989f645SChris Wilson kmem_cache_free(slab_fences, to_mock_fence(f)); 342989f645SChris Wilson } 352989f645SChris Wilson 362989f645SChris Wilson struct wait_cb { 372989f645SChris Wilson struct dma_fence_cb cb; 382989f645SChris Wilson struct task_struct *task; 392989f645SChris Wilson }; 402989f645SChris Wilson 412989f645SChris Wilson static void mock_wakeup(struct dma_fence *f, struct dma_fence_cb *cb) 422989f645SChris Wilson { 432989f645SChris Wilson wake_up_process(container_of(cb, struct wait_cb, cb)->task); 442989f645SChris Wilson } 452989f645SChris Wilson 462989f645SChris Wilson static long mock_wait(struct dma_fence *f, bool intr, long timeout) 472989f645SChris Wilson { 482989f645SChris Wilson const int state = intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE; 492989f645SChris Wilson struct wait_cb cb = { .task = current }; 502989f645SChris Wilson 512989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, mock_wakeup)) 522989f645SChris Wilson return timeout; 532989f645SChris Wilson 542989f645SChris Wilson while (timeout) { 552989f645SChris Wilson set_current_state(state); 562989f645SChris Wilson 572989f645SChris Wilson if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags)) 582989f645SChris Wilson break; 592989f645SChris Wilson 602989f645SChris Wilson if (signal_pending_state(state, current)) 612989f645SChris Wilson break; 622989f645SChris Wilson 632989f645SChris Wilson timeout = schedule_timeout(timeout); 642989f645SChris Wilson } 652989f645SChris Wilson __set_current_state(TASK_RUNNING); 662989f645SChris Wilson 672989f645SChris Wilson if (!dma_fence_remove_callback(f, &cb.cb)) 682989f645SChris Wilson return timeout; 692989f645SChris Wilson 702989f645SChris Wilson if (signal_pending_state(state, current)) 712989f645SChris Wilson return -ERESTARTSYS; 722989f645SChris Wilson 732989f645SChris Wilson return -ETIME; 742989f645SChris Wilson } 752989f645SChris Wilson 762989f645SChris Wilson static const struct dma_fence_ops mock_ops = { 772989f645SChris Wilson .get_driver_name = mock_name, 782989f645SChris Wilson .get_timeline_name = mock_name, 792989f645SChris Wilson .wait = mock_wait, 802989f645SChris Wilson .release = mock_fence_release, 812989f645SChris Wilson }; 822989f645SChris Wilson 832989f645SChris Wilson static struct dma_fence *mock_fence(void) 842989f645SChris Wilson { 852989f645SChris Wilson struct mock_fence *f; 862989f645SChris Wilson 872989f645SChris Wilson f = kmem_cache_alloc(slab_fences, GFP_KERNEL); 882989f645SChris Wilson if (!f) 892989f645SChris Wilson return NULL; 902989f645SChris Wilson 912989f645SChris Wilson spin_lock_init(&f->lock); 922989f645SChris Wilson dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0); 932989f645SChris Wilson 942989f645SChris Wilson return &f->base; 952989f645SChris Wilson } 962989f645SChris Wilson 972989f645SChris Wilson static int sanitycheck(void *arg) 982989f645SChris Wilson { 992989f645SChris Wilson struct dma_fence *f; 1002989f645SChris Wilson 1012989f645SChris Wilson f = mock_fence(); 1022989f645SChris Wilson if (!f) 1032989f645SChris Wilson return -ENOMEM; 1042989f645SChris Wilson 1052989f645SChris Wilson dma_fence_signal(f); 1062989f645SChris Wilson dma_fence_put(f); 1072989f645SChris Wilson 1082989f645SChris Wilson return 0; 1092989f645SChris Wilson } 1102989f645SChris Wilson 1112989f645SChris Wilson static int test_signaling(void *arg) 1122989f645SChris Wilson { 1132989f645SChris Wilson struct dma_fence *f; 1142989f645SChris Wilson int err = -EINVAL; 1152989f645SChris Wilson 1162989f645SChris Wilson f = mock_fence(); 1172989f645SChris Wilson if (!f) 1182989f645SChris Wilson return -ENOMEM; 1192989f645SChris Wilson 1202989f645SChris Wilson if (dma_fence_is_signaled(f)) { 1212989f645SChris Wilson pr_err("Fence unexpectedly signaled on creation\n"); 1222989f645SChris Wilson goto err_free; 1232989f645SChris Wilson } 1242989f645SChris Wilson 1252989f645SChris Wilson if (dma_fence_signal(f)) { 1262989f645SChris Wilson pr_err("Fence reported being already signaled\n"); 1272989f645SChris Wilson goto err_free; 1282989f645SChris Wilson } 1292989f645SChris Wilson 1302989f645SChris Wilson if (!dma_fence_is_signaled(f)) { 1312989f645SChris Wilson pr_err("Fence not reporting signaled\n"); 1322989f645SChris Wilson goto err_free; 1332989f645SChris Wilson } 1342989f645SChris Wilson 1352989f645SChris Wilson if (!dma_fence_signal(f)) { 1362989f645SChris Wilson pr_err("Fence reported not being already signaled\n"); 1372989f645SChris Wilson goto err_free; 1382989f645SChris Wilson } 1392989f645SChris Wilson 1402989f645SChris Wilson err = 0; 1412989f645SChris Wilson err_free: 1422989f645SChris Wilson dma_fence_put(f); 1432989f645SChris Wilson return err; 1442989f645SChris Wilson } 1452989f645SChris Wilson 1462989f645SChris Wilson struct simple_cb { 1472989f645SChris Wilson struct dma_fence_cb cb; 1482989f645SChris Wilson bool seen; 1492989f645SChris Wilson }; 1502989f645SChris Wilson 1512989f645SChris Wilson static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb) 1522989f645SChris Wilson { 1532989f645SChris Wilson smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true); 1542989f645SChris Wilson } 1552989f645SChris Wilson 1562989f645SChris Wilson static int test_add_callback(void *arg) 1572989f645SChris Wilson { 1582989f645SChris Wilson struct simple_cb cb = {}; 1592989f645SChris Wilson struct dma_fence *f; 1602989f645SChris Wilson int err = -EINVAL; 1612989f645SChris Wilson 1622989f645SChris Wilson f = mock_fence(); 1632989f645SChris Wilson if (!f) 1642989f645SChris Wilson return -ENOMEM; 1652989f645SChris Wilson 1662989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 1672989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 1682989f645SChris Wilson goto err_free; 1692989f645SChris Wilson } 1702989f645SChris Wilson 1712989f645SChris Wilson dma_fence_signal(f); 1722989f645SChris Wilson if (!cb.seen) { 1732989f645SChris Wilson pr_err("Callback failed!\n"); 1742989f645SChris Wilson goto err_free; 1752989f645SChris Wilson } 1762989f645SChris Wilson 1772989f645SChris Wilson err = 0; 1782989f645SChris Wilson err_free: 1792989f645SChris Wilson dma_fence_put(f); 1802989f645SChris Wilson return err; 1812989f645SChris Wilson } 1822989f645SChris Wilson 1832989f645SChris Wilson static int test_late_add_callback(void *arg) 1842989f645SChris Wilson { 1852989f645SChris Wilson struct simple_cb cb = {}; 1862989f645SChris Wilson struct dma_fence *f; 1872989f645SChris Wilson int err = -EINVAL; 1882989f645SChris Wilson 1892989f645SChris Wilson f = mock_fence(); 1902989f645SChris Wilson if (!f) 1912989f645SChris Wilson return -ENOMEM; 1922989f645SChris Wilson 1932989f645SChris Wilson dma_fence_signal(f); 1942989f645SChris Wilson 1952989f645SChris Wilson if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) { 1962989f645SChris Wilson pr_err("Added callback, but fence was already signaled!\n"); 1972989f645SChris Wilson goto err_free; 1982989f645SChris Wilson } 1992989f645SChris Wilson 2002989f645SChris Wilson dma_fence_signal(f); 2012989f645SChris Wilson if (cb.seen) { 2022989f645SChris Wilson pr_err("Callback called after failed attachment !\n"); 2032989f645SChris Wilson goto err_free; 2042989f645SChris Wilson } 2052989f645SChris Wilson 2062989f645SChris Wilson err = 0; 2072989f645SChris Wilson err_free: 2082989f645SChris Wilson dma_fence_put(f); 2092989f645SChris Wilson return err; 2102989f645SChris Wilson } 2112989f645SChris Wilson 2122989f645SChris Wilson static int test_rm_callback(void *arg) 2132989f645SChris Wilson { 2142989f645SChris Wilson struct simple_cb cb = {}; 2152989f645SChris Wilson struct dma_fence *f; 2162989f645SChris Wilson int err = -EINVAL; 2172989f645SChris Wilson 2182989f645SChris Wilson f = mock_fence(); 2192989f645SChris Wilson if (!f) 2202989f645SChris Wilson return -ENOMEM; 2212989f645SChris Wilson 2222989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 2232989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 2242989f645SChris Wilson goto err_free; 2252989f645SChris Wilson } 2262989f645SChris Wilson 2272989f645SChris Wilson if (!dma_fence_remove_callback(f, &cb.cb)) { 2282989f645SChris Wilson pr_err("Failed to remove callback!\n"); 2292989f645SChris Wilson goto err_free; 2302989f645SChris Wilson } 2312989f645SChris Wilson 2322989f645SChris Wilson dma_fence_signal(f); 2332989f645SChris Wilson if (cb.seen) { 2342989f645SChris Wilson pr_err("Callback still signaled after removal!\n"); 2352989f645SChris Wilson goto err_free; 2362989f645SChris Wilson } 2372989f645SChris Wilson 2382989f645SChris Wilson err = 0; 2392989f645SChris Wilson err_free: 2402989f645SChris Wilson dma_fence_put(f); 2412989f645SChris Wilson return err; 2422989f645SChris Wilson } 2432989f645SChris Wilson 2442989f645SChris Wilson static int test_late_rm_callback(void *arg) 2452989f645SChris Wilson { 2462989f645SChris Wilson struct simple_cb cb = {}; 2472989f645SChris Wilson struct dma_fence *f; 2482989f645SChris Wilson int err = -EINVAL; 2492989f645SChris Wilson 2502989f645SChris Wilson f = mock_fence(); 2512989f645SChris Wilson if (!f) 2522989f645SChris Wilson return -ENOMEM; 2532989f645SChris Wilson 2542989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 2552989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 2562989f645SChris Wilson goto err_free; 2572989f645SChris Wilson } 2582989f645SChris Wilson 2592989f645SChris Wilson dma_fence_signal(f); 2602989f645SChris Wilson if (!cb.seen) { 2612989f645SChris Wilson pr_err("Callback failed!\n"); 2622989f645SChris Wilson goto err_free; 2632989f645SChris Wilson } 2642989f645SChris Wilson 2652989f645SChris Wilson if (dma_fence_remove_callback(f, &cb.cb)) { 2662989f645SChris Wilson pr_err("Callback removal succeed after being executed!\n"); 2672989f645SChris Wilson goto err_free; 2682989f645SChris Wilson } 2692989f645SChris Wilson 2702989f645SChris Wilson err = 0; 2712989f645SChris Wilson err_free: 2722989f645SChris Wilson dma_fence_put(f); 2732989f645SChris Wilson return err; 2742989f645SChris Wilson } 2752989f645SChris Wilson 2762989f645SChris Wilson static int test_status(void *arg) 2772989f645SChris Wilson { 2782989f645SChris Wilson struct dma_fence *f; 2792989f645SChris Wilson int err = -EINVAL; 2802989f645SChris Wilson 2812989f645SChris Wilson f = mock_fence(); 2822989f645SChris Wilson if (!f) 2832989f645SChris Wilson return -ENOMEM; 2842989f645SChris Wilson 2852989f645SChris Wilson if (dma_fence_get_status(f)) { 2862989f645SChris Wilson pr_err("Fence unexpectedly has signaled status on creation\n"); 2872989f645SChris Wilson goto err_free; 2882989f645SChris Wilson } 2892989f645SChris Wilson 2902989f645SChris Wilson dma_fence_signal(f); 2912989f645SChris Wilson if (!dma_fence_get_status(f)) { 2922989f645SChris Wilson pr_err("Fence not reporting signaled status\n"); 2932989f645SChris Wilson goto err_free; 2942989f645SChris Wilson } 2952989f645SChris Wilson 2962989f645SChris Wilson err = 0; 2972989f645SChris Wilson err_free: 2982989f645SChris Wilson dma_fence_put(f); 2992989f645SChris Wilson return err; 3002989f645SChris Wilson } 3012989f645SChris Wilson 3022989f645SChris Wilson static int test_error(void *arg) 3032989f645SChris Wilson { 3042989f645SChris Wilson struct dma_fence *f; 3052989f645SChris Wilson int err = -EINVAL; 3062989f645SChris Wilson 3072989f645SChris Wilson f = mock_fence(); 3082989f645SChris Wilson if (!f) 3092989f645SChris Wilson return -ENOMEM; 3102989f645SChris Wilson 3112989f645SChris Wilson dma_fence_set_error(f, -EIO); 3122989f645SChris Wilson 3132989f645SChris Wilson if (dma_fence_get_status(f)) { 3142989f645SChris Wilson pr_err("Fence unexpectedly has error status before signal\n"); 3152989f645SChris Wilson goto err_free; 3162989f645SChris Wilson } 3172989f645SChris Wilson 3182989f645SChris Wilson dma_fence_signal(f); 3192989f645SChris Wilson if (dma_fence_get_status(f) != -EIO) { 3202989f645SChris Wilson pr_err("Fence not reporting error status, got %d\n", 3212989f645SChris Wilson dma_fence_get_status(f)); 3222989f645SChris Wilson goto err_free; 3232989f645SChris Wilson } 3242989f645SChris Wilson 3252989f645SChris Wilson err = 0; 3262989f645SChris Wilson err_free: 3272989f645SChris Wilson dma_fence_put(f); 3282989f645SChris Wilson return err; 3292989f645SChris Wilson } 3302989f645SChris Wilson 3312989f645SChris Wilson static int test_wait(void *arg) 3322989f645SChris Wilson { 3332989f645SChris Wilson struct dma_fence *f; 3342989f645SChris Wilson int err = -EINVAL; 3352989f645SChris Wilson 3362989f645SChris Wilson f = mock_fence(); 3372989f645SChris Wilson if (!f) 3382989f645SChris Wilson return -ENOMEM; 3392989f645SChris Wilson 3402989f645SChris Wilson if (dma_fence_wait_timeout(f, false, 0) != -ETIME) { 3412989f645SChris Wilson pr_err("Wait reported complete before being signaled\n"); 3422989f645SChris Wilson goto err_free; 3432989f645SChris Wilson } 3442989f645SChris Wilson 3452989f645SChris Wilson dma_fence_signal(f); 3462989f645SChris Wilson 3472989f645SChris Wilson if (dma_fence_wait_timeout(f, false, 0) != 0) { 3482989f645SChris Wilson pr_err("Wait reported incomplete after being signaled\n"); 3492989f645SChris Wilson goto err_free; 3502989f645SChris Wilson } 3512989f645SChris Wilson 3522989f645SChris Wilson err = 0; 3532989f645SChris Wilson err_free: 3542989f645SChris Wilson dma_fence_signal(f); 3552989f645SChris Wilson dma_fence_put(f); 3562989f645SChris Wilson return err; 3572989f645SChris Wilson } 3582989f645SChris Wilson 3592989f645SChris Wilson struct wait_timer { 3602989f645SChris Wilson struct timer_list timer; 3612989f645SChris Wilson struct dma_fence *f; 3622989f645SChris Wilson }; 3632989f645SChris Wilson 3642989f645SChris Wilson static void wait_timer(struct timer_list *timer) 3652989f645SChris Wilson { 3662989f645SChris Wilson struct wait_timer *wt = from_timer(wt, timer, timer); 3672989f645SChris Wilson 3682989f645SChris Wilson dma_fence_signal(wt->f); 3692989f645SChris Wilson } 3702989f645SChris Wilson 3712989f645SChris Wilson static int test_wait_timeout(void *arg) 3722989f645SChris Wilson { 3732989f645SChris Wilson struct wait_timer wt; 3742989f645SChris Wilson int err = -EINVAL; 3752989f645SChris Wilson 376*6ac3a0ebSChris Wilson timer_setup_on_stack(&wt.timer, wait_timer, 0); 3772989f645SChris Wilson 3782989f645SChris Wilson wt.f = mock_fence(); 3792989f645SChris Wilson if (!wt.f) 3802989f645SChris Wilson return -ENOMEM; 3812989f645SChris Wilson 3822989f645SChris Wilson if (dma_fence_wait_timeout(wt.f, false, 1) != -ETIME) { 3832989f645SChris Wilson pr_err("Wait reported complete before being signaled\n"); 3842989f645SChris Wilson goto err_free; 3852989f645SChris Wilson } 3862989f645SChris Wilson 3872989f645SChris Wilson mod_timer(&wt.timer, jiffies + 1); 3882989f645SChris Wilson 3892989f645SChris Wilson if (dma_fence_wait_timeout(wt.f, false, 2) == -ETIME) { 3902989f645SChris Wilson if (timer_pending(&wt.timer)) { 3912989f645SChris Wilson pr_notice("Timer did not fire within the jiffie!\n"); 3922989f645SChris Wilson err = 0; /* not our fault! */ 3932989f645SChris Wilson } else { 3942989f645SChris Wilson pr_err("Wait reported incomplete after timeout\n"); 3952989f645SChris Wilson } 3962989f645SChris Wilson goto err_free; 3972989f645SChris Wilson } 3982989f645SChris Wilson 3992989f645SChris Wilson err = 0; 4002989f645SChris Wilson err_free: 4012989f645SChris Wilson del_timer_sync(&wt.timer); 402*6ac3a0ebSChris Wilson destroy_timer_on_stack(&wt.timer); 4032989f645SChris Wilson dma_fence_signal(wt.f); 4042989f645SChris Wilson dma_fence_put(wt.f); 4052989f645SChris Wilson return err; 4062989f645SChris Wilson } 4072989f645SChris Wilson 4082989f645SChris Wilson static int test_stub(void *arg) 4092989f645SChris Wilson { 4102989f645SChris Wilson struct dma_fence *f[64]; 4112989f645SChris Wilson int err = -EINVAL; 4122989f645SChris Wilson int i; 4132989f645SChris Wilson 4142989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(f); i++) { 4152989f645SChris Wilson f[i] = dma_fence_get_stub(); 4162989f645SChris Wilson if (!dma_fence_is_signaled(f[i])) { 4172989f645SChris Wilson pr_err("Obtained unsignaled stub fence!\n"); 4182989f645SChris Wilson goto err; 4192989f645SChris Wilson } 4202989f645SChris Wilson } 4212989f645SChris Wilson 4222989f645SChris Wilson err = 0; 4232989f645SChris Wilson err: 4242989f645SChris Wilson while (i--) 4252989f645SChris Wilson dma_fence_put(f[i]); 4262989f645SChris Wilson return err; 4272989f645SChris Wilson } 4282989f645SChris Wilson 4292989f645SChris Wilson /* Now off to the races! */ 4302989f645SChris Wilson 4312989f645SChris Wilson struct race_thread { 4322989f645SChris Wilson struct dma_fence __rcu **fences; 4332989f645SChris Wilson struct task_struct *task; 4342989f645SChris Wilson bool before; 4352989f645SChris Wilson int id; 4362989f645SChris Wilson }; 4372989f645SChris Wilson 4382989f645SChris Wilson static void __wait_for_callbacks(struct dma_fence *f) 4392989f645SChris Wilson { 4402989f645SChris Wilson spin_lock_irq(f->lock); 4412989f645SChris Wilson spin_unlock_irq(f->lock); 4422989f645SChris Wilson } 4432989f645SChris Wilson 4442989f645SChris Wilson static int thread_signal_callback(void *arg) 4452989f645SChris Wilson { 4462989f645SChris Wilson const struct race_thread *t = arg; 4472989f645SChris Wilson unsigned long pass = 0; 4482989f645SChris Wilson unsigned long miss = 0; 4492989f645SChris Wilson int err = 0; 4502989f645SChris Wilson 4512989f645SChris Wilson while (!err && !kthread_should_stop()) { 4522989f645SChris Wilson struct dma_fence *f1, *f2; 4532989f645SChris Wilson struct simple_cb cb; 4542989f645SChris Wilson 4552989f645SChris Wilson f1 = mock_fence(); 4562989f645SChris Wilson if (!f1) { 4572989f645SChris Wilson err = -ENOMEM; 4582989f645SChris Wilson break; 4592989f645SChris Wilson } 4602989f645SChris Wilson 4612989f645SChris Wilson rcu_assign_pointer(t->fences[t->id], f1); 4622989f645SChris Wilson smp_wmb(); 4632989f645SChris Wilson 4642989f645SChris Wilson rcu_read_lock(); 4652989f645SChris Wilson do { 4662989f645SChris Wilson f2 = dma_fence_get_rcu_safe(&t->fences[!t->id]); 4672989f645SChris Wilson } while (!f2 && !kthread_should_stop()); 4682989f645SChris Wilson rcu_read_unlock(); 4692989f645SChris Wilson 4702989f645SChris Wilson if (t->before) 4712989f645SChris Wilson dma_fence_signal(f1); 4722989f645SChris Wilson 4732989f645SChris Wilson smp_store_mb(cb.seen, false); 4742989f645SChris Wilson if (!f2 || dma_fence_add_callback(f2, &cb.cb, simple_callback)) 4752989f645SChris Wilson miss++, cb.seen = true; 4762989f645SChris Wilson 4772989f645SChris Wilson if (!t->before) 4782989f645SChris Wilson dma_fence_signal(f1); 4792989f645SChris Wilson 4802989f645SChris Wilson if (!cb.seen) { 4812989f645SChris Wilson dma_fence_wait(f2, false); 4822989f645SChris Wilson __wait_for_callbacks(f2); 4832989f645SChris Wilson } 4842989f645SChris Wilson 4852989f645SChris Wilson if (!READ_ONCE(cb.seen)) { 4862989f645SChris Wilson pr_err("Callback not seen on thread %d, pass %lu (%lu misses), signaling %s add_callback; fence signaled? %s\n", 4872989f645SChris Wilson t->id, pass, miss, 4882989f645SChris Wilson t->before ? "before" : "after", 4892989f645SChris Wilson dma_fence_is_signaled(f2) ? "yes" : "no"); 4902989f645SChris Wilson err = -EINVAL; 4912989f645SChris Wilson } 4922989f645SChris Wilson 4932989f645SChris Wilson dma_fence_put(f2); 4942989f645SChris Wilson 4952989f645SChris Wilson rcu_assign_pointer(t->fences[t->id], NULL); 4962989f645SChris Wilson smp_wmb(); 4972989f645SChris Wilson 4982989f645SChris Wilson dma_fence_put(f1); 4992989f645SChris Wilson 5002989f645SChris Wilson pass++; 5012989f645SChris Wilson } 5022989f645SChris Wilson 5032989f645SChris Wilson pr_info("%s[%d] completed %lu passes, %lu misses\n", 5042989f645SChris Wilson __func__, t->id, pass, miss); 5052989f645SChris Wilson return err; 5062989f645SChris Wilson } 5072989f645SChris Wilson 5082989f645SChris Wilson static int race_signal_callback(void *arg) 5092989f645SChris Wilson { 5102989f645SChris Wilson struct dma_fence __rcu *f[2] = {}; 5112989f645SChris Wilson int ret = 0; 5122989f645SChris Wilson int pass; 5132989f645SChris Wilson 5142989f645SChris Wilson for (pass = 0; !ret && pass <= 1; pass++) { 5152989f645SChris Wilson struct race_thread t[2]; 5162989f645SChris Wilson int i; 5172989f645SChris Wilson 5182989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(t); i++) { 5192989f645SChris Wilson t[i].fences = f; 5202989f645SChris Wilson t[i].id = i; 5212989f645SChris Wilson t[i].before = pass; 5222989f645SChris Wilson t[i].task = kthread_run(thread_signal_callback, &t[i], 5232989f645SChris Wilson "dma-fence:%d", i); 5242989f645SChris Wilson get_task_struct(t[i].task); 5252989f645SChris Wilson } 5262989f645SChris Wilson 5272989f645SChris Wilson msleep(50); 5282989f645SChris Wilson 5292989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(t); i++) { 5302989f645SChris Wilson int err; 5312989f645SChris Wilson 5322989f645SChris Wilson err = kthread_stop(t[i].task); 5332989f645SChris Wilson if (err && !ret) 5342989f645SChris Wilson ret = err; 5352989f645SChris Wilson 5362989f645SChris Wilson put_task_struct(t[i].task); 5372989f645SChris Wilson } 5382989f645SChris Wilson } 5392989f645SChris Wilson 5402989f645SChris Wilson return ret; 5412989f645SChris Wilson } 5422989f645SChris Wilson 5432989f645SChris Wilson int dma_fence(void) 5442989f645SChris Wilson { 5452989f645SChris Wilson static const struct subtest tests[] = { 5462989f645SChris Wilson SUBTEST(sanitycheck), 5472989f645SChris Wilson SUBTEST(test_signaling), 5482989f645SChris Wilson SUBTEST(test_add_callback), 5492989f645SChris Wilson SUBTEST(test_late_add_callback), 5502989f645SChris Wilson SUBTEST(test_rm_callback), 5512989f645SChris Wilson SUBTEST(test_late_rm_callback), 5522989f645SChris Wilson SUBTEST(test_status), 5532989f645SChris Wilson SUBTEST(test_error), 5542989f645SChris Wilson SUBTEST(test_wait), 5552989f645SChris Wilson SUBTEST(test_wait_timeout), 5562989f645SChris Wilson SUBTEST(test_stub), 5572989f645SChris Wilson SUBTEST(race_signal_callback), 5582989f645SChris Wilson }; 5592989f645SChris Wilson int ret; 5602989f645SChris Wilson 561ea4e537aSChris Wilson pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence)); 5622989f645SChris Wilson 5632989f645SChris Wilson slab_fences = KMEM_CACHE(mock_fence, 5642989f645SChris Wilson SLAB_TYPESAFE_BY_RCU | 5652989f645SChris Wilson SLAB_HWCACHE_ALIGN); 5662989f645SChris Wilson if (!slab_fences) 5672989f645SChris Wilson return -ENOMEM; 5682989f645SChris Wilson 5692989f645SChris Wilson ret = subtests(tests, NULL); 5702989f645SChris Wilson 5712989f645SChris Wilson kmem_cache_destroy(slab_fences); 5722989f645SChris Wilson 5732989f645SChris Wilson return ret; 5742989f645SChris Wilson } 575