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 105d62c43a9SArvind Yadav dma_fence_enable_sw_signaling(f); 106d62c43a9SArvind Yadav 1072989f645SChris Wilson dma_fence_signal(f); 1082989f645SChris Wilson dma_fence_put(f); 1092989f645SChris Wilson 1102989f645SChris Wilson return 0; 1112989f645SChris Wilson } 1122989f645SChris Wilson 1132989f645SChris Wilson static int test_signaling(void *arg) 1142989f645SChris Wilson { 1152989f645SChris Wilson struct dma_fence *f; 1162989f645SChris Wilson int err = -EINVAL; 1172989f645SChris Wilson 1182989f645SChris Wilson f = mock_fence(); 1192989f645SChris Wilson if (!f) 1202989f645SChris Wilson return -ENOMEM; 1212989f645SChris Wilson 122d62c43a9SArvind Yadav dma_fence_enable_sw_signaling(f); 123d62c43a9SArvind Yadav 1242989f645SChris Wilson if (dma_fence_is_signaled(f)) { 1252989f645SChris Wilson pr_err("Fence unexpectedly signaled on creation\n"); 1262989f645SChris Wilson goto err_free; 1272989f645SChris Wilson } 1282989f645SChris Wilson 1292989f645SChris Wilson if (dma_fence_signal(f)) { 1302989f645SChris Wilson pr_err("Fence reported being already signaled\n"); 1312989f645SChris Wilson goto err_free; 1322989f645SChris Wilson } 1332989f645SChris Wilson 1342989f645SChris Wilson if (!dma_fence_is_signaled(f)) { 1352989f645SChris Wilson pr_err("Fence not reporting signaled\n"); 1362989f645SChris Wilson goto err_free; 1372989f645SChris Wilson } 1382989f645SChris Wilson 1392989f645SChris Wilson if (!dma_fence_signal(f)) { 1402989f645SChris Wilson pr_err("Fence reported not being already signaled\n"); 1412989f645SChris Wilson goto err_free; 1422989f645SChris Wilson } 1432989f645SChris Wilson 1442989f645SChris Wilson err = 0; 1452989f645SChris Wilson err_free: 1462989f645SChris Wilson dma_fence_put(f); 1472989f645SChris Wilson return err; 1482989f645SChris Wilson } 1492989f645SChris Wilson 1502989f645SChris Wilson struct simple_cb { 1512989f645SChris Wilson struct dma_fence_cb cb; 1522989f645SChris Wilson bool seen; 1532989f645SChris Wilson }; 1542989f645SChris Wilson 1552989f645SChris Wilson static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb) 1562989f645SChris Wilson { 1572989f645SChris Wilson smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true); 1582989f645SChris Wilson } 1592989f645SChris Wilson 1602989f645SChris Wilson static int test_add_callback(void *arg) 1612989f645SChris Wilson { 1622989f645SChris Wilson struct simple_cb cb = {}; 1632989f645SChris Wilson struct dma_fence *f; 1642989f645SChris Wilson int err = -EINVAL; 1652989f645SChris Wilson 1662989f645SChris Wilson f = mock_fence(); 1672989f645SChris Wilson if (!f) 1682989f645SChris Wilson return -ENOMEM; 1692989f645SChris Wilson 1702989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 1712989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 1722989f645SChris Wilson goto err_free; 1732989f645SChris Wilson } 1742989f645SChris Wilson 1752989f645SChris Wilson dma_fence_signal(f); 1762989f645SChris Wilson if (!cb.seen) { 1772989f645SChris Wilson pr_err("Callback failed!\n"); 1782989f645SChris Wilson goto err_free; 1792989f645SChris Wilson } 1802989f645SChris Wilson 1812989f645SChris Wilson err = 0; 1822989f645SChris Wilson err_free: 1832989f645SChris Wilson dma_fence_put(f); 1842989f645SChris Wilson return err; 1852989f645SChris Wilson } 1862989f645SChris Wilson 1872989f645SChris Wilson static int test_late_add_callback(void *arg) 1882989f645SChris Wilson { 1892989f645SChris Wilson struct simple_cb cb = {}; 1902989f645SChris Wilson struct dma_fence *f; 1912989f645SChris Wilson int err = -EINVAL; 1922989f645SChris Wilson 1932989f645SChris Wilson f = mock_fence(); 1942989f645SChris Wilson if (!f) 1952989f645SChris Wilson return -ENOMEM; 1962989f645SChris Wilson 197d62c43a9SArvind Yadav dma_fence_enable_sw_signaling(f); 198d62c43a9SArvind Yadav 1992989f645SChris Wilson dma_fence_signal(f); 2002989f645SChris Wilson 2012989f645SChris Wilson if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) { 2022989f645SChris Wilson pr_err("Added callback, but fence was already signaled!\n"); 2032989f645SChris Wilson goto err_free; 2042989f645SChris Wilson } 2052989f645SChris Wilson 2062989f645SChris Wilson dma_fence_signal(f); 2072989f645SChris Wilson if (cb.seen) { 2082989f645SChris Wilson pr_err("Callback called after failed attachment !\n"); 2092989f645SChris Wilson goto err_free; 2102989f645SChris Wilson } 2112989f645SChris Wilson 2122989f645SChris Wilson err = 0; 2132989f645SChris Wilson err_free: 2142989f645SChris Wilson dma_fence_put(f); 2152989f645SChris Wilson return err; 2162989f645SChris Wilson } 2172989f645SChris Wilson 2182989f645SChris Wilson static int test_rm_callback(void *arg) 2192989f645SChris Wilson { 2202989f645SChris Wilson struct simple_cb cb = {}; 2212989f645SChris Wilson struct dma_fence *f; 2222989f645SChris Wilson int err = -EINVAL; 2232989f645SChris Wilson 2242989f645SChris Wilson f = mock_fence(); 2252989f645SChris Wilson if (!f) 2262989f645SChris Wilson return -ENOMEM; 2272989f645SChris Wilson 2282989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 2292989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 2302989f645SChris Wilson goto err_free; 2312989f645SChris Wilson } 2322989f645SChris Wilson 2332989f645SChris Wilson if (!dma_fence_remove_callback(f, &cb.cb)) { 2342989f645SChris Wilson pr_err("Failed to remove callback!\n"); 2352989f645SChris Wilson goto err_free; 2362989f645SChris Wilson } 2372989f645SChris Wilson 2382989f645SChris Wilson dma_fence_signal(f); 2392989f645SChris Wilson if (cb.seen) { 2402989f645SChris Wilson pr_err("Callback still signaled after removal!\n"); 2412989f645SChris Wilson goto err_free; 2422989f645SChris Wilson } 2432989f645SChris Wilson 2442989f645SChris Wilson err = 0; 2452989f645SChris Wilson err_free: 2462989f645SChris Wilson dma_fence_put(f); 2472989f645SChris Wilson return err; 2482989f645SChris Wilson } 2492989f645SChris Wilson 2502989f645SChris Wilson static int test_late_rm_callback(void *arg) 2512989f645SChris Wilson { 2522989f645SChris Wilson struct simple_cb cb = {}; 2532989f645SChris Wilson struct dma_fence *f; 2542989f645SChris Wilson int err = -EINVAL; 2552989f645SChris Wilson 2562989f645SChris Wilson f = mock_fence(); 2572989f645SChris Wilson if (!f) 2582989f645SChris Wilson return -ENOMEM; 2592989f645SChris Wilson 2602989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 2612989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 2622989f645SChris Wilson goto err_free; 2632989f645SChris Wilson } 2642989f645SChris Wilson 2652989f645SChris Wilson dma_fence_signal(f); 2662989f645SChris Wilson if (!cb.seen) { 2672989f645SChris Wilson pr_err("Callback failed!\n"); 2682989f645SChris Wilson goto err_free; 2692989f645SChris Wilson } 2702989f645SChris Wilson 2712989f645SChris Wilson if (dma_fence_remove_callback(f, &cb.cb)) { 2722989f645SChris Wilson pr_err("Callback removal succeed after being executed!\n"); 2732989f645SChris Wilson goto err_free; 2742989f645SChris Wilson } 2752989f645SChris Wilson 2762989f645SChris Wilson err = 0; 2772989f645SChris Wilson err_free: 2782989f645SChris Wilson dma_fence_put(f); 2792989f645SChris Wilson return err; 2802989f645SChris Wilson } 2812989f645SChris Wilson 2822989f645SChris Wilson static int test_status(void *arg) 2832989f645SChris Wilson { 2842989f645SChris Wilson struct dma_fence *f; 2852989f645SChris Wilson int err = -EINVAL; 2862989f645SChris Wilson 2872989f645SChris Wilson f = mock_fence(); 2882989f645SChris Wilson if (!f) 2892989f645SChris Wilson return -ENOMEM; 2902989f645SChris Wilson 291d62c43a9SArvind Yadav dma_fence_enable_sw_signaling(f); 292d62c43a9SArvind Yadav 2932989f645SChris Wilson if (dma_fence_get_status(f)) { 2942989f645SChris Wilson pr_err("Fence unexpectedly has signaled status on creation\n"); 2952989f645SChris Wilson goto err_free; 2962989f645SChris Wilson } 2972989f645SChris Wilson 2982989f645SChris Wilson dma_fence_signal(f); 2992989f645SChris Wilson if (!dma_fence_get_status(f)) { 3002989f645SChris Wilson pr_err("Fence not reporting signaled status\n"); 3012989f645SChris Wilson goto err_free; 3022989f645SChris Wilson } 3032989f645SChris Wilson 3042989f645SChris Wilson err = 0; 3052989f645SChris Wilson err_free: 3062989f645SChris Wilson dma_fence_put(f); 3072989f645SChris Wilson return err; 3082989f645SChris Wilson } 3092989f645SChris Wilson 3102989f645SChris Wilson static int test_error(void *arg) 3112989f645SChris Wilson { 3122989f645SChris Wilson struct dma_fence *f; 3132989f645SChris Wilson int err = -EINVAL; 3142989f645SChris Wilson 3152989f645SChris Wilson f = mock_fence(); 3162989f645SChris Wilson if (!f) 3172989f645SChris Wilson return -ENOMEM; 3182989f645SChris Wilson 319d62c43a9SArvind Yadav dma_fence_enable_sw_signaling(f); 320d62c43a9SArvind Yadav 3212989f645SChris Wilson dma_fence_set_error(f, -EIO); 3222989f645SChris Wilson 3232989f645SChris Wilson if (dma_fence_get_status(f)) { 3242989f645SChris Wilson pr_err("Fence unexpectedly has error status before signal\n"); 3252989f645SChris Wilson goto err_free; 3262989f645SChris Wilson } 3272989f645SChris Wilson 3282989f645SChris Wilson dma_fence_signal(f); 3292989f645SChris Wilson if (dma_fence_get_status(f) != -EIO) { 3302989f645SChris Wilson pr_err("Fence not reporting error status, got %d\n", 3312989f645SChris Wilson dma_fence_get_status(f)); 3322989f645SChris Wilson goto err_free; 3332989f645SChris Wilson } 3342989f645SChris Wilson 3352989f645SChris Wilson err = 0; 3362989f645SChris Wilson err_free: 3372989f645SChris Wilson dma_fence_put(f); 3382989f645SChris Wilson return err; 3392989f645SChris Wilson } 3402989f645SChris Wilson 3412989f645SChris Wilson static int test_wait(void *arg) 3422989f645SChris Wilson { 3432989f645SChris Wilson struct dma_fence *f; 3442989f645SChris Wilson int err = -EINVAL; 3452989f645SChris Wilson 3462989f645SChris Wilson f = mock_fence(); 3472989f645SChris Wilson if (!f) 3482989f645SChris Wilson return -ENOMEM; 3492989f645SChris Wilson 350d62c43a9SArvind Yadav dma_fence_enable_sw_signaling(f); 351d62c43a9SArvind Yadav 3522989f645SChris Wilson if (dma_fence_wait_timeout(f, false, 0) != -ETIME) { 3532989f645SChris Wilson pr_err("Wait reported complete before being signaled\n"); 3542989f645SChris Wilson goto err_free; 3552989f645SChris Wilson } 3562989f645SChris Wilson 3572989f645SChris Wilson dma_fence_signal(f); 3582989f645SChris Wilson 3592989f645SChris Wilson if (dma_fence_wait_timeout(f, false, 0) != 0) { 3602989f645SChris Wilson pr_err("Wait reported incomplete after being signaled\n"); 3612989f645SChris Wilson goto err_free; 3622989f645SChris Wilson } 3632989f645SChris Wilson 3642989f645SChris Wilson err = 0; 3652989f645SChris Wilson err_free: 3662989f645SChris Wilson dma_fence_signal(f); 3672989f645SChris Wilson dma_fence_put(f); 3682989f645SChris Wilson return err; 3692989f645SChris Wilson } 3702989f645SChris Wilson 3712989f645SChris Wilson struct wait_timer { 3722989f645SChris Wilson struct timer_list timer; 3732989f645SChris Wilson struct dma_fence *f; 3742989f645SChris Wilson }; 3752989f645SChris Wilson 3762989f645SChris Wilson static void wait_timer(struct timer_list *timer) 3772989f645SChris Wilson { 3782989f645SChris Wilson struct wait_timer *wt = from_timer(wt, timer, timer); 3792989f645SChris Wilson 3802989f645SChris Wilson dma_fence_signal(wt->f); 3812989f645SChris Wilson } 3822989f645SChris Wilson 3832989f645SChris Wilson static int test_wait_timeout(void *arg) 3842989f645SChris Wilson { 3852989f645SChris Wilson struct wait_timer wt; 3862989f645SChris Wilson int err = -EINVAL; 3872989f645SChris Wilson 3886ac3a0ebSChris Wilson timer_setup_on_stack(&wt.timer, wait_timer, 0); 3892989f645SChris Wilson 3902989f645SChris Wilson wt.f = mock_fence(); 3912989f645SChris Wilson if (!wt.f) 3922989f645SChris Wilson return -ENOMEM; 3932989f645SChris Wilson 394d62c43a9SArvind Yadav dma_fence_enable_sw_signaling(wt.f); 395d62c43a9SArvind Yadav 3962989f645SChris Wilson if (dma_fence_wait_timeout(wt.f, false, 1) != -ETIME) { 3972989f645SChris Wilson pr_err("Wait reported complete before being signaled\n"); 3982989f645SChris Wilson goto err_free; 3992989f645SChris Wilson } 4002989f645SChris Wilson 4012989f645SChris Wilson mod_timer(&wt.timer, jiffies + 1); 4022989f645SChris Wilson 4032989f645SChris Wilson if (dma_fence_wait_timeout(wt.f, false, 2) == -ETIME) { 4042989f645SChris Wilson if (timer_pending(&wt.timer)) { 4052989f645SChris Wilson pr_notice("Timer did not fire within the jiffie!\n"); 4062989f645SChris Wilson err = 0; /* not our fault! */ 4072989f645SChris Wilson } else { 4082989f645SChris Wilson pr_err("Wait reported incomplete after timeout\n"); 4092989f645SChris Wilson } 4102989f645SChris Wilson goto err_free; 4112989f645SChris Wilson } 4122989f645SChris Wilson 4132989f645SChris Wilson err = 0; 4142989f645SChris Wilson err_free: 4152989f645SChris Wilson del_timer_sync(&wt.timer); 4166ac3a0ebSChris Wilson destroy_timer_on_stack(&wt.timer); 4172989f645SChris Wilson dma_fence_signal(wt.f); 4182989f645SChris Wilson dma_fence_put(wt.f); 4192989f645SChris Wilson return err; 4202989f645SChris Wilson } 4212989f645SChris Wilson 4222989f645SChris Wilson static int test_stub(void *arg) 4232989f645SChris Wilson { 4242989f645SChris Wilson struct dma_fence *f[64]; 4252989f645SChris Wilson int err = -EINVAL; 4262989f645SChris Wilson int i; 4272989f645SChris Wilson 4282989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(f); i++) { 4292989f645SChris Wilson f[i] = dma_fence_get_stub(); 4302989f645SChris Wilson if (!dma_fence_is_signaled(f[i])) { 4312989f645SChris Wilson pr_err("Obtained unsignaled stub fence!\n"); 4322989f645SChris Wilson goto err; 4332989f645SChris Wilson } 4342989f645SChris Wilson } 4352989f645SChris Wilson 4362989f645SChris Wilson err = 0; 4372989f645SChris Wilson err: 4382989f645SChris Wilson while (i--) 4392989f645SChris Wilson dma_fence_put(f[i]); 4402989f645SChris Wilson return err; 4412989f645SChris Wilson } 4422989f645SChris Wilson 4432989f645SChris Wilson /* Now off to the races! */ 4442989f645SChris Wilson 4452989f645SChris Wilson struct race_thread { 4462989f645SChris Wilson struct dma_fence __rcu **fences; 4472989f645SChris Wilson struct task_struct *task; 4482989f645SChris Wilson bool before; 4492989f645SChris Wilson int id; 4502989f645SChris Wilson }; 4512989f645SChris Wilson 4522989f645SChris Wilson static void __wait_for_callbacks(struct dma_fence *f) 4532989f645SChris Wilson { 4542989f645SChris Wilson spin_lock_irq(f->lock); 4552989f645SChris Wilson spin_unlock_irq(f->lock); 4562989f645SChris Wilson } 4572989f645SChris Wilson 4582989f645SChris Wilson static int thread_signal_callback(void *arg) 4592989f645SChris Wilson { 4602989f645SChris Wilson const struct race_thread *t = arg; 4612989f645SChris Wilson unsigned long pass = 0; 4622989f645SChris Wilson unsigned long miss = 0; 4632989f645SChris Wilson int err = 0; 4642989f645SChris Wilson 4652989f645SChris Wilson while (!err && !kthread_should_stop()) { 4662989f645SChris Wilson struct dma_fence *f1, *f2; 4672989f645SChris Wilson struct simple_cb cb; 4682989f645SChris Wilson 4692989f645SChris Wilson f1 = mock_fence(); 4702989f645SChris Wilson if (!f1) { 4712989f645SChris Wilson err = -ENOMEM; 4722989f645SChris Wilson break; 4732989f645SChris Wilson } 4742989f645SChris Wilson 475d62c43a9SArvind Yadav dma_fence_enable_sw_signaling(f1); 476d62c43a9SArvind Yadav 4772989f645SChris Wilson rcu_assign_pointer(t->fences[t->id], f1); 4782989f645SChris Wilson smp_wmb(); 4792989f645SChris Wilson 4802989f645SChris Wilson rcu_read_lock(); 4812989f645SChris Wilson do { 4822989f645SChris Wilson f2 = dma_fence_get_rcu_safe(&t->fences[!t->id]); 4832989f645SChris Wilson } while (!f2 && !kthread_should_stop()); 4842989f645SChris Wilson rcu_read_unlock(); 4852989f645SChris Wilson 4862989f645SChris Wilson if (t->before) 4872989f645SChris Wilson dma_fence_signal(f1); 4882989f645SChris Wilson 4892989f645SChris Wilson smp_store_mb(cb.seen, false); 49046d4a938SJoe Perches if (!f2 || 49146d4a938SJoe Perches dma_fence_add_callback(f2, &cb.cb, simple_callback)) { 49246d4a938SJoe Perches miss++; 49346d4a938SJoe Perches cb.seen = true; 49446d4a938SJoe Perches } 4952989f645SChris Wilson 4962989f645SChris Wilson if (!t->before) 4972989f645SChris Wilson dma_fence_signal(f1); 4982989f645SChris Wilson 4992989f645SChris Wilson if (!cb.seen) { 5002989f645SChris Wilson dma_fence_wait(f2, false); 5012989f645SChris Wilson __wait_for_callbacks(f2); 5022989f645SChris Wilson } 5032989f645SChris Wilson 5042989f645SChris Wilson if (!READ_ONCE(cb.seen)) { 5052989f645SChris Wilson pr_err("Callback not seen on thread %d, pass %lu (%lu misses), signaling %s add_callback; fence signaled? %s\n", 5062989f645SChris Wilson t->id, pass, miss, 5072989f645SChris Wilson t->before ? "before" : "after", 5082989f645SChris Wilson dma_fence_is_signaled(f2) ? "yes" : "no"); 5092989f645SChris Wilson err = -EINVAL; 5102989f645SChris Wilson } 5112989f645SChris Wilson 5122989f645SChris Wilson dma_fence_put(f2); 5132989f645SChris Wilson 5142989f645SChris Wilson rcu_assign_pointer(t->fences[t->id], NULL); 5152989f645SChris Wilson smp_wmb(); 5162989f645SChris Wilson 5172989f645SChris Wilson dma_fence_put(f1); 5182989f645SChris Wilson 5192989f645SChris Wilson pass++; 5202989f645SChris Wilson } 5212989f645SChris Wilson 5222989f645SChris Wilson pr_info("%s[%d] completed %lu passes, %lu misses\n", 5232989f645SChris Wilson __func__, t->id, pass, miss); 5242989f645SChris Wilson return err; 5252989f645SChris Wilson } 5262989f645SChris Wilson 5272989f645SChris Wilson static int race_signal_callback(void *arg) 5282989f645SChris Wilson { 5292989f645SChris Wilson struct dma_fence __rcu *f[2] = {}; 5302989f645SChris Wilson int ret = 0; 5312989f645SChris Wilson int pass; 5322989f645SChris Wilson 5332989f645SChris Wilson for (pass = 0; !ret && pass <= 1; pass++) { 5342989f645SChris Wilson struct race_thread t[2]; 5352989f645SChris Wilson int i; 5362989f645SChris Wilson 5372989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(t); i++) { 5382989f645SChris Wilson t[i].fences = f; 5392989f645SChris Wilson t[i].id = i; 5402989f645SChris Wilson t[i].before = pass; 5412989f645SChris Wilson t[i].task = kthread_run(thread_signal_callback, &t[i], 5422989f645SChris Wilson "dma-fence:%d", i); 5432989f645SChris Wilson get_task_struct(t[i].task); 5442989f645SChris Wilson } 5452989f645SChris Wilson 5462989f645SChris Wilson msleep(50); 5472989f645SChris Wilson 5482989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(t); i++) { 5492989f645SChris Wilson int err; 5502989f645SChris Wilson 551*a9da6ddaSAndreas Gruenbacher err = kthread_stop_put(t[i].task); 5522989f645SChris Wilson if (err && !ret) 5532989f645SChris Wilson ret = err; 5542989f645SChris Wilson } 5552989f645SChris Wilson } 5562989f645SChris Wilson 5572989f645SChris Wilson return ret; 5582989f645SChris Wilson } 5592989f645SChris Wilson 5602989f645SChris Wilson int dma_fence(void) 5612989f645SChris Wilson { 5622989f645SChris Wilson static const struct subtest tests[] = { 5632989f645SChris Wilson SUBTEST(sanitycheck), 5642989f645SChris Wilson SUBTEST(test_signaling), 5652989f645SChris Wilson SUBTEST(test_add_callback), 5662989f645SChris Wilson SUBTEST(test_late_add_callback), 5672989f645SChris Wilson SUBTEST(test_rm_callback), 5682989f645SChris Wilson SUBTEST(test_late_rm_callback), 5692989f645SChris Wilson SUBTEST(test_status), 5702989f645SChris Wilson SUBTEST(test_error), 5712989f645SChris Wilson SUBTEST(test_wait), 5722989f645SChris Wilson SUBTEST(test_wait_timeout), 5732989f645SChris Wilson SUBTEST(test_stub), 5742989f645SChris Wilson SUBTEST(race_signal_callback), 5752989f645SChris Wilson }; 5762989f645SChris Wilson int ret; 5772989f645SChris Wilson 578ea4e537aSChris Wilson pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence)); 5792989f645SChris Wilson 5802989f645SChris Wilson slab_fences = KMEM_CACHE(mock_fence, 5812989f645SChris Wilson SLAB_TYPESAFE_BY_RCU | 5822989f645SChris Wilson SLAB_HWCACHE_ALIGN); 5832989f645SChris Wilson if (!slab_fences) 5842989f645SChris Wilson return -ENOMEM; 5852989f645SChris Wilson 5862989f645SChris Wilson ret = subtests(tests, NULL); 5872989f645SChris Wilson 5882989f645SChris Wilson kmem_cache_destroy(slab_fences); 5892989f645SChris Wilson 5902989f645SChris Wilson return ret; 5912989f645SChris Wilson } 592