1*2989f645SChris Wilson /* SPDX-License-Identifier: MIT */ 2*2989f645SChris Wilson 3*2989f645SChris Wilson /* 4*2989f645SChris Wilson * Copyright © 2019 Intel Corporation 5*2989f645SChris Wilson */ 6*2989f645SChris Wilson 7*2989f645SChris Wilson #include <linux/delay.h> 8*2989f645SChris Wilson #include <linux/dma-fence.h> 9*2989f645SChris Wilson #include <linux/kernel.h> 10*2989f645SChris Wilson #include <linux/kthread.h> 11*2989f645SChris Wilson #include <linux/sched/signal.h> 12*2989f645SChris Wilson #include <linux/slab.h> 13*2989f645SChris Wilson #include <linux/spinlock.h> 14*2989f645SChris Wilson 15*2989f645SChris Wilson #include "selftest.h" 16*2989f645SChris Wilson 17*2989f645SChris Wilson static struct kmem_cache *slab_fences; 18*2989f645SChris Wilson 19*2989f645SChris Wilson static struct mock_fence { 20*2989f645SChris Wilson struct dma_fence base; 21*2989f645SChris Wilson struct spinlock lock; 22*2989f645SChris Wilson } *to_mock_fence(struct dma_fence *f) { 23*2989f645SChris Wilson return container_of(f, struct mock_fence, base); 24*2989f645SChris Wilson } 25*2989f645SChris Wilson 26*2989f645SChris Wilson static const char *mock_name(struct dma_fence *f) 27*2989f645SChris Wilson { 28*2989f645SChris Wilson return "mock"; 29*2989f645SChris Wilson } 30*2989f645SChris Wilson 31*2989f645SChris Wilson static void mock_fence_release(struct dma_fence *f) 32*2989f645SChris Wilson { 33*2989f645SChris Wilson kmem_cache_free(slab_fences, to_mock_fence(f)); 34*2989f645SChris Wilson } 35*2989f645SChris Wilson 36*2989f645SChris Wilson struct wait_cb { 37*2989f645SChris Wilson struct dma_fence_cb cb; 38*2989f645SChris Wilson struct task_struct *task; 39*2989f645SChris Wilson }; 40*2989f645SChris Wilson 41*2989f645SChris Wilson static void mock_wakeup(struct dma_fence *f, struct dma_fence_cb *cb) 42*2989f645SChris Wilson { 43*2989f645SChris Wilson wake_up_process(container_of(cb, struct wait_cb, cb)->task); 44*2989f645SChris Wilson } 45*2989f645SChris Wilson 46*2989f645SChris Wilson static long mock_wait(struct dma_fence *f, bool intr, long timeout) 47*2989f645SChris Wilson { 48*2989f645SChris Wilson const int state = intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE; 49*2989f645SChris Wilson struct wait_cb cb = { .task = current }; 50*2989f645SChris Wilson 51*2989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, mock_wakeup)) 52*2989f645SChris Wilson return timeout; 53*2989f645SChris Wilson 54*2989f645SChris Wilson while (timeout) { 55*2989f645SChris Wilson set_current_state(state); 56*2989f645SChris Wilson 57*2989f645SChris Wilson if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags)) 58*2989f645SChris Wilson break; 59*2989f645SChris Wilson 60*2989f645SChris Wilson if (signal_pending_state(state, current)) 61*2989f645SChris Wilson break; 62*2989f645SChris Wilson 63*2989f645SChris Wilson timeout = schedule_timeout(timeout); 64*2989f645SChris Wilson } 65*2989f645SChris Wilson __set_current_state(TASK_RUNNING); 66*2989f645SChris Wilson 67*2989f645SChris Wilson if (!dma_fence_remove_callback(f, &cb.cb)) 68*2989f645SChris Wilson return timeout; 69*2989f645SChris Wilson 70*2989f645SChris Wilson if (signal_pending_state(state, current)) 71*2989f645SChris Wilson return -ERESTARTSYS; 72*2989f645SChris Wilson 73*2989f645SChris Wilson return -ETIME; 74*2989f645SChris Wilson } 75*2989f645SChris Wilson 76*2989f645SChris Wilson static const struct dma_fence_ops mock_ops = { 77*2989f645SChris Wilson .get_driver_name = mock_name, 78*2989f645SChris Wilson .get_timeline_name = mock_name, 79*2989f645SChris Wilson .wait = mock_wait, 80*2989f645SChris Wilson .release = mock_fence_release, 81*2989f645SChris Wilson }; 82*2989f645SChris Wilson 83*2989f645SChris Wilson static struct dma_fence *mock_fence(void) 84*2989f645SChris Wilson { 85*2989f645SChris Wilson struct mock_fence *f; 86*2989f645SChris Wilson 87*2989f645SChris Wilson f = kmem_cache_alloc(slab_fences, GFP_KERNEL); 88*2989f645SChris Wilson if (!f) 89*2989f645SChris Wilson return NULL; 90*2989f645SChris Wilson 91*2989f645SChris Wilson spin_lock_init(&f->lock); 92*2989f645SChris Wilson dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0); 93*2989f645SChris Wilson 94*2989f645SChris Wilson return &f->base; 95*2989f645SChris Wilson } 96*2989f645SChris Wilson 97*2989f645SChris Wilson static int sanitycheck(void *arg) 98*2989f645SChris Wilson { 99*2989f645SChris Wilson struct dma_fence *f; 100*2989f645SChris Wilson 101*2989f645SChris Wilson f = mock_fence(); 102*2989f645SChris Wilson if (!f) 103*2989f645SChris Wilson return -ENOMEM; 104*2989f645SChris Wilson 105*2989f645SChris Wilson dma_fence_signal(f); 106*2989f645SChris Wilson dma_fence_put(f); 107*2989f645SChris Wilson 108*2989f645SChris Wilson return 0; 109*2989f645SChris Wilson } 110*2989f645SChris Wilson 111*2989f645SChris Wilson static int test_signaling(void *arg) 112*2989f645SChris Wilson { 113*2989f645SChris Wilson struct dma_fence *f; 114*2989f645SChris Wilson int err = -EINVAL; 115*2989f645SChris Wilson 116*2989f645SChris Wilson f = mock_fence(); 117*2989f645SChris Wilson if (!f) 118*2989f645SChris Wilson return -ENOMEM; 119*2989f645SChris Wilson 120*2989f645SChris Wilson if (dma_fence_is_signaled(f)) { 121*2989f645SChris Wilson pr_err("Fence unexpectedly signaled on creation\n"); 122*2989f645SChris Wilson goto err_free; 123*2989f645SChris Wilson } 124*2989f645SChris Wilson 125*2989f645SChris Wilson if (dma_fence_signal(f)) { 126*2989f645SChris Wilson pr_err("Fence reported being already signaled\n"); 127*2989f645SChris Wilson goto err_free; 128*2989f645SChris Wilson } 129*2989f645SChris Wilson 130*2989f645SChris Wilson if (!dma_fence_is_signaled(f)) { 131*2989f645SChris Wilson pr_err("Fence not reporting signaled\n"); 132*2989f645SChris Wilson goto err_free; 133*2989f645SChris Wilson } 134*2989f645SChris Wilson 135*2989f645SChris Wilson if (!dma_fence_signal(f)) { 136*2989f645SChris Wilson pr_err("Fence reported not being already signaled\n"); 137*2989f645SChris Wilson goto err_free; 138*2989f645SChris Wilson } 139*2989f645SChris Wilson 140*2989f645SChris Wilson err = 0; 141*2989f645SChris Wilson err_free: 142*2989f645SChris Wilson dma_fence_put(f); 143*2989f645SChris Wilson return err; 144*2989f645SChris Wilson } 145*2989f645SChris Wilson 146*2989f645SChris Wilson struct simple_cb { 147*2989f645SChris Wilson struct dma_fence_cb cb; 148*2989f645SChris Wilson bool seen; 149*2989f645SChris Wilson }; 150*2989f645SChris Wilson 151*2989f645SChris Wilson static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb) 152*2989f645SChris Wilson { 153*2989f645SChris Wilson smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true); 154*2989f645SChris Wilson } 155*2989f645SChris Wilson 156*2989f645SChris Wilson static int test_add_callback(void *arg) 157*2989f645SChris Wilson { 158*2989f645SChris Wilson struct simple_cb cb = {}; 159*2989f645SChris Wilson struct dma_fence *f; 160*2989f645SChris Wilson int err = -EINVAL; 161*2989f645SChris Wilson 162*2989f645SChris Wilson f = mock_fence(); 163*2989f645SChris Wilson if (!f) 164*2989f645SChris Wilson return -ENOMEM; 165*2989f645SChris Wilson 166*2989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 167*2989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 168*2989f645SChris Wilson goto err_free; 169*2989f645SChris Wilson } 170*2989f645SChris Wilson 171*2989f645SChris Wilson dma_fence_signal(f); 172*2989f645SChris Wilson if (!cb.seen) { 173*2989f645SChris Wilson pr_err("Callback failed!\n"); 174*2989f645SChris Wilson goto err_free; 175*2989f645SChris Wilson } 176*2989f645SChris Wilson 177*2989f645SChris Wilson err = 0; 178*2989f645SChris Wilson err_free: 179*2989f645SChris Wilson dma_fence_put(f); 180*2989f645SChris Wilson return err; 181*2989f645SChris Wilson } 182*2989f645SChris Wilson 183*2989f645SChris Wilson static int test_late_add_callback(void *arg) 184*2989f645SChris Wilson { 185*2989f645SChris Wilson struct simple_cb cb = {}; 186*2989f645SChris Wilson struct dma_fence *f; 187*2989f645SChris Wilson int err = -EINVAL; 188*2989f645SChris Wilson 189*2989f645SChris Wilson f = mock_fence(); 190*2989f645SChris Wilson if (!f) 191*2989f645SChris Wilson return -ENOMEM; 192*2989f645SChris Wilson 193*2989f645SChris Wilson dma_fence_signal(f); 194*2989f645SChris Wilson 195*2989f645SChris Wilson if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) { 196*2989f645SChris Wilson pr_err("Added callback, but fence was already signaled!\n"); 197*2989f645SChris Wilson goto err_free; 198*2989f645SChris Wilson } 199*2989f645SChris Wilson 200*2989f645SChris Wilson dma_fence_signal(f); 201*2989f645SChris Wilson if (cb.seen) { 202*2989f645SChris Wilson pr_err("Callback called after failed attachment !\n"); 203*2989f645SChris Wilson goto err_free; 204*2989f645SChris Wilson } 205*2989f645SChris Wilson 206*2989f645SChris Wilson err = 0; 207*2989f645SChris Wilson err_free: 208*2989f645SChris Wilson dma_fence_put(f); 209*2989f645SChris Wilson return err; 210*2989f645SChris Wilson } 211*2989f645SChris Wilson 212*2989f645SChris Wilson static int test_rm_callback(void *arg) 213*2989f645SChris Wilson { 214*2989f645SChris Wilson struct simple_cb cb = {}; 215*2989f645SChris Wilson struct dma_fence *f; 216*2989f645SChris Wilson int err = -EINVAL; 217*2989f645SChris Wilson 218*2989f645SChris Wilson f = mock_fence(); 219*2989f645SChris Wilson if (!f) 220*2989f645SChris Wilson return -ENOMEM; 221*2989f645SChris Wilson 222*2989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 223*2989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 224*2989f645SChris Wilson goto err_free; 225*2989f645SChris Wilson } 226*2989f645SChris Wilson 227*2989f645SChris Wilson if (!dma_fence_remove_callback(f, &cb.cb)) { 228*2989f645SChris Wilson pr_err("Failed to remove callback!\n"); 229*2989f645SChris Wilson goto err_free; 230*2989f645SChris Wilson } 231*2989f645SChris Wilson 232*2989f645SChris Wilson dma_fence_signal(f); 233*2989f645SChris Wilson if (cb.seen) { 234*2989f645SChris Wilson pr_err("Callback still signaled after removal!\n"); 235*2989f645SChris Wilson goto err_free; 236*2989f645SChris Wilson } 237*2989f645SChris Wilson 238*2989f645SChris Wilson err = 0; 239*2989f645SChris Wilson err_free: 240*2989f645SChris Wilson dma_fence_put(f); 241*2989f645SChris Wilson return err; 242*2989f645SChris Wilson } 243*2989f645SChris Wilson 244*2989f645SChris Wilson static int test_late_rm_callback(void *arg) 245*2989f645SChris Wilson { 246*2989f645SChris Wilson struct simple_cb cb = {}; 247*2989f645SChris Wilson struct dma_fence *f; 248*2989f645SChris Wilson int err = -EINVAL; 249*2989f645SChris Wilson 250*2989f645SChris Wilson f = mock_fence(); 251*2989f645SChris Wilson if (!f) 252*2989f645SChris Wilson return -ENOMEM; 253*2989f645SChris Wilson 254*2989f645SChris Wilson if (dma_fence_add_callback(f, &cb.cb, simple_callback)) { 255*2989f645SChris Wilson pr_err("Failed to add callback, fence already signaled!\n"); 256*2989f645SChris Wilson goto err_free; 257*2989f645SChris Wilson } 258*2989f645SChris Wilson 259*2989f645SChris Wilson dma_fence_signal(f); 260*2989f645SChris Wilson if (!cb.seen) { 261*2989f645SChris Wilson pr_err("Callback failed!\n"); 262*2989f645SChris Wilson goto err_free; 263*2989f645SChris Wilson } 264*2989f645SChris Wilson 265*2989f645SChris Wilson if (dma_fence_remove_callback(f, &cb.cb)) { 266*2989f645SChris Wilson pr_err("Callback removal succeed after being executed!\n"); 267*2989f645SChris Wilson goto err_free; 268*2989f645SChris Wilson } 269*2989f645SChris Wilson 270*2989f645SChris Wilson err = 0; 271*2989f645SChris Wilson err_free: 272*2989f645SChris Wilson dma_fence_put(f); 273*2989f645SChris Wilson return err; 274*2989f645SChris Wilson } 275*2989f645SChris Wilson 276*2989f645SChris Wilson static int test_status(void *arg) 277*2989f645SChris Wilson { 278*2989f645SChris Wilson struct dma_fence *f; 279*2989f645SChris Wilson int err = -EINVAL; 280*2989f645SChris Wilson 281*2989f645SChris Wilson f = mock_fence(); 282*2989f645SChris Wilson if (!f) 283*2989f645SChris Wilson return -ENOMEM; 284*2989f645SChris Wilson 285*2989f645SChris Wilson if (dma_fence_get_status(f)) { 286*2989f645SChris Wilson pr_err("Fence unexpectedly has signaled status on creation\n"); 287*2989f645SChris Wilson goto err_free; 288*2989f645SChris Wilson } 289*2989f645SChris Wilson 290*2989f645SChris Wilson dma_fence_signal(f); 291*2989f645SChris Wilson if (!dma_fence_get_status(f)) { 292*2989f645SChris Wilson pr_err("Fence not reporting signaled status\n"); 293*2989f645SChris Wilson goto err_free; 294*2989f645SChris Wilson } 295*2989f645SChris Wilson 296*2989f645SChris Wilson err = 0; 297*2989f645SChris Wilson err_free: 298*2989f645SChris Wilson dma_fence_put(f); 299*2989f645SChris Wilson return err; 300*2989f645SChris Wilson } 301*2989f645SChris Wilson 302*2989f645SChris Wilson static int test_error(void *arg) 303*2989f645SChris Wilson { 304*2989f645SChris Wilson struct dma_fence *f; 305*2989f645SChris Wilson int err = -EINVAL; 306*2989f645SChris Wilson 307*2989f645SChris Wilson f = mock_fence(); 308*2989f645SChris Wilson if (!f) 309*2989f645SChris Wilson return -ENOMEM; 310*2989f645SChris Wilson 311*2989f645SChris Wilson dma_fence_set_error(f, -EIO); 312*2989f645SChris Wilson 313*2989f645SChris Wilson if (dma_fence_get_status(f)) { 314*2989f645SChris Wilson pr_err("Fence unexpectedly has error status before signal\n"); 315*2989f645SChris Wilson goto err_free; 316*2989f645SChris Wilson } 317*2989f645SChris Wilson 318*2989f645SChris Wilson dma_fence_signal(f); 319*2989f645SChris Wilson if (dma_fence_get_status(f) != -EIO) { 320*2989f645SChris Wilson pr_err("Fence not reporting error status, got %d\n", 321*2989f645SChris Wilson dma_fence_get_status(f)); 322*2989f645SChris Wilson goto err_free; 323*2989f645SChris Wilson } 324*2989f645SChris Wilson 325*2989f645SChris Wilson err = 0; 326*2989f645SChris Wilson err_free: 327*2989f645SChris Wilson dma_fence_put(f); 328*2989f645SChris Wilson return err; 329*2989f645SChris Wilson } 330*2989f645SChris Wilson 331*2989f645SChris Wilson static int test_wait(void *arg) 332*2989f645SChris Wilson { 333*2989f645SChris Wilson struct dma_fence *f; 334*2989f645SChris Wilson int err = -EINVAL; 335*2989f645SChris Wilson 336*2989f645SChris Wilson f = mock_fence(); 337*2989f645SChris Wilson if (!f) 338*2989f645SChris Wilson return -ENOMEM; 339*2989f645SChris Wilson 340*2989f645SChris Wilson if (dma_fence_wait_timeout(f, false, 0) != -ETIME) { 341*2989f645SChris Wilson pr_err("Wait reported complete before being signaled\n"); 342*2989f645SChris Wilson goto err_free; 343*2989f645SChris Wilson } 344*2989f645SChris Wilson 345*2989f645SChris Wilson dma_fence_signal(f); 346*2989f645SChris Wilson 347*2989f645SChris Wilson if (dma_fence_wait_timeout(f, false, 0) != 0) { 348*2989f645SChris Wilson pr_err("Wait reported incomplete after being signaled\n"); 349*2989f645SChris Wilson goto err_free; 350*2989f645SChris Wilson } 351*2989f645SChris Wilson 352*2989f645SChris Wilson err = 0; 353*2989f645SChris Wilson err_free: 354*2989f645SChris Wilson dma_fence_signal(f); 355*2989f645SChris Wilson dma_fence_put(f); 356*2989f645SChris Wilson return err; 357*2989f645SChris Wilson } 358*2989f645SChris Wilson 359*2989f645SChris Wilson struct wait_timer { 360*2989f645SChris Wilson struct timer_list timer; 361*2989f645SChris Wilson struct dma_fence *f; 362*2989f645SChris Wilson }; 363*2989f645SChris Wilson 364*2989f645SChris Wilson static void wait_timer(struct timer_list *timer) 365*2989f645SChris Wilson { 366*2989f645SChris Wilson struct wait_timer *wt = from_timer(wt, timer, timer); 367*2989f645SChris Wilson 368*2989f645SChris Wilson dma_fence_signal(wt->f); 369*2989f645SChris Wilson } 370*2989f645SChris Wilson 371*2989f645SChris Wilson static int test_wait_timeout(void *arg) 372*2989f645SChris Wilson { 373*2989f645SChris Wilson struct wait_timer wt; 374*2989f645SChris Wilson int err = -EINVAL; 375*2989f645SChris Wilson 376*2989f645SChris Wilson timer_setup(&wt.timer, wait_timer, 0); 377*2989f645SChris Wilson 378*2989f645SChris Wilson wt.f = mock_fence(); 379*2989f645SChris Wilson if (!wt.f) 380*2989f645SChris Wilson return -ENOMEM; 381*2989f645SChris Wilson 382*2989f645SChris Wilson if (dma_fence_wait_timeout(wt.f, false, 1) != -ETIME) { 383*2989f645SChris Wilson pr_err("Wait reported complete before being signaled\n"); 384*2989f645SChris Wilson goto err_free; 385*2989f645SChris Wilson } 386*2989f645SChris Wilson 387*2989f645SChris Wilson mod_timer(&wt.timer, jiffies + 1); 388*2989f645SChris Wilson 389*2989f645SChris Wilson if (dma_fence_wait_timeout(wt.f, false, 2) == -ETIME) { 390*2989f645SChris Wilson if (timer_pending(&wt.timer)) { 391*2989f645SChris Wilson pr_notice("Timer did not fire within the jiffie!\n"); 392*2989f645SChris Wilson err = 0; /* not our fault! */ 393*2989f645SChris Wilson } else { 394*2989f645SChris Wilson pr_err("Wait reported incomplete after timeout\n"); 395*2989f645SChris Wilson } 396*2989f645SChris Wilson goto err_free; 397*2989f645SChris Wilson } 398*2989f645SChris Wilson 399*2989f645SChris Wilson err = 0; 400*2989f645SChris Wilson err_free: 401*2989f645SChris Wilson del_timer_sync(&wt.timer); 402*2989f645SChris Wilson dma_fence_signal(wt.f); 403*2989f645SChris Wilson dma_fence_put(wt.f); 404*2989f645SChris Wilson return err; 405*2989f645SChris Wilson } 406*2989f645SChris Wilson 407*2989f645SChris Wilson static int test_stub(void *arg) 408*2989f645SChris Wilson { 409*2989f645SChris Wilson struct dma_fence *f[64]; 410*2989f645SChris Wilson int err = -EINVAL; 411*2989f645SChris Wilson int i; 412*2989f645SChris Wilson 413*2989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(f); i++) { 414*2989f645SChris Wilson f[i] = dma_fence_get_stub(); 415*2989f645SChris Wilson if (!dma_fence_is_signaled(f[i])) { 416*2989f645SChris Wilson pr_err("Obtained unsignaled stub fence!\n"); 417*2989f645SChris Wilson goto err; 418*2989f645SChris Wilson } 419*2989f645SChris Wilson } 420*2989f645SChris Wilson 421*2989f645SChris Wilson err = 0; 422*2989f645SChris Wilson err: 423*2989f645SChris Wilson while (i--) 424*2989f645SChris Wilson dma_fence_put(f[i]); 425*2989f645SChris Wilson return err; 426*2989f645SChris Wilson } 427*2989f645SChris Wilson 428*2989f645SChris Wilson /* Now off to the races! */ 429*2989f645SChris Wilson 430*2989f645SChris Wilson struct race_thread { 431*2989f645SChris Wilson struct dma_fence __rcu **fences; 432*2989f645SChris Wilson struct task_struct *task; 433*2989f645SChris Wilson bool before; 434*2989f645SChris Wilson int id; 435*2989f645SChris Wilson }; 436*2989f645SChris Wilson 437*2989f645SChris Wilson static void __wait_for_callbacks(struct dma_fence *f) 438*2989f645SChris Wilson { 439*2989f645SChris Wilson spin_lock_irq(f->lock); 440*2989f645SChris Wilson spin_unlock_irq(f->lock); 441*2989f645SChris Wilson } 442*2989f645SChris Wilson 443*2989f645SChris Wilson static int thread_signal_callback(void *arg) 444*2989f645SChris Wilson { 445*2989f645SChris Wilson const struct race_thread *t = arg; 446*2989f645SChris Wilson unsigned long pass = 0; 447*2989f645SChris Wilson unsigned long miss = 0; 448*2989f645SChris Wilson int err = 0; 449*2989f645SChris Wilson 450*2989f645SChris Wilson while (!err && !kthread_should_stop()) { 451*2989f645SChris Wilson struct dma_fence *f1, *f2; 452*2989f645SChris Wilson struct simple_cb cb; 453*2989f645SChris Wilson 454*2989f645SChris Wilson f1 = mock_fence(); 455*2989f645SChris Wilson if (!f1) { 456*2989f645SChris Wilson err = -ENOMEM; 457*2989f645SChris Wilson break; 458*2989f645SChris Wilson } 459*2989f645SChris Wilson 460*2989f645SChris Wilson rcu_assign_pointer(t->fences[t->id], f1); 461*2989f645SChris Wilson smp_wmb(); 462*2989f645SChris Wilson 463*2989f645SChris Wilson rcu_read_lock(); 464*2989f645SChris Wilson do { 465*2989f645SChris Wilson f2 = dma_fence_get_rcu_safe(&t->fences[!t->id]); 466*2989f645SChris Wilson } while (!f2 && !kthread_should_stop()); 467*2989f645SChris Wilson rcu_read_unlock(); 468*2989f645SChris Wilson 469*2989f645SChris Wilson if (t->before) 470*2989f645SChris Wilson dma_fence_signal(f1); 471*2989f645SChris Wilson 472*2989f645SChris Wilson smp_store_mb(cb.seen, false); 473*2989f645SChris Wilson if (!f2 || dma_fence_add_callback(f2, &cb.cb, simple_callback)) 474*2989f645SChris Wilson miss++, cb.seen = true; 475*2989f645SChris Wilson 476*2989f645SChris Wilson if (!t->before) 477*2989f645SChris Wilson dma_fence_signal(f1); 478*2989f645SChris Wilson 479*2989f645SChris Wilson if (!cb.seen) { 480*2989f645SChris Wilson dma_fence_wait(f2, false); 481*2989f645SChris Wilson __wait_for_callbacks(f2); 482*2989f645SChris Wilson } 483*2989f645SChris Wilson 484*2989f645SChris Wilson if (!READ_ONCE(cb.seen)) { 485*2989f645SChris Wilson pr_err("Callback not seen on thread %d, pass %lu (%lu misses), signaling %s add_callback; fence signaled? %s\n", 486*2989f645SChris Wilson t->id, pass, miss, 487*2989f645SChris Wilson t->before ? "before" : "after", 488*2989f645SChris Wilson dma_fence_is_signaled(f2) ? "yes" : "no"); 489*2989f645SChris Wilson err = -EINVAL; 490*2989f645SChris Wilson } 491*2989f645SChris Wilson 492*2989f645SChris Wilson dma_fence_put(f2); 493*2989f645SChris Wilson 494*2989f645SChris Wilson rcu_assign_pointer(t->fences[t->id], NULL); 495*2989f645SChris Wilson smp_wmb(); 496*2989f645SChris Wilson 497*2989f645SChris Wilson dma_fence_put(f1); 498*2989f645SChris Wilson 499*2989f645SChris Wilson pass++; 500*2989f645SChris Wilson } 501*2989f645SChris Wilson 502*2989f645SChris Wilson pr_info("%s[%d] completed %lu passes, %lu misses\n", 503*2989f645SChris Wilson __func__, t->id, pass, miss); 504*2989f645SChris Wilson return err; 505*2989f645SChris Wilson } 506*2989f645SChris Wilson 507*2989f645SChris Wilson static int race_signal_callback(void *arg) 508*2989f645SChris Wilson { 509*2989f645SChris Wilson struct dma_fence __rcu *f[2] = {}; 510*2989f645SChris Wilson int ret = 0; 511*2989f645SChris Wilson int pass; 512*2989f645SChris Wilson 513*2989f645SChris Wilson for (pass = 0; !ret && pass <= 1; pass++) { 514*2989f645SChris Wilson struct race_thread t[2]; 515*2989f645SChris Wilson int i; 516*2989f645SChris Wilson 517*2989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(t); i++) { 518*2989f645SChris Wilson t[i].fences = f; 519*2989f645SChris Wilson t[i].id = i; 520*2989f645SChris Wilson t[i].before = pass; 521*2989f645SChris Wilson t[i].task = kthread_run(thread_signal_callback, &t[i], 522*2989f645SChris Wilson "dma-fence:%d", i); 523*2989f645SChris Wilson get_task_struct(t[i].task); 524*2989f645SChris Wilson } 525*2989f645SChris Wilson 526*2989f645SChris Wilson msleep(50); 527*2989f645SChris Wilson 528*2989f645SChris Wilson for (i = 0; i < ARRAY_SIZE(t); i++) { 529*2989f645SChris Wilson int err; 530*2989f645SChris Wilson 531*2989f645SChris Wilson err = kthread_stop(t[i].task); 532*2989f645SChris Wilson if (err && !ret) 533*2989f645SChris Wilson ret = err; 534*2989f645SChris Wilson 535*2989f645SChris Wilson put_task_struct(t[i].task); 536*2989f645SChris Wilson } 537*2989f645SChris Wilson } 538*2989f645SChris Wilson 539*2989f645SChris Wilson return ret; 540*2989f645SChris Wilson } 541*2989f645SChris Wilson 542*2989f645SChris Wilson int dma_fence(void) 543*2989f645SChris Wilson { 544*2989f645SChris Wilson static const struct subtest tests[] = { 545*2989f645SChris Wilson SUBTEST(sanitycheck), 546*2989f645SChris Wilson SUBTEST(test_signaling), 547*2989f645SChris Wilson SUBTEST(test_add_callback), 548*2989f645SChris Wilson SUBTEST(test_late_add_callback), 549*2989f645SChris Wilson SUBTEST(test_rm_callback), 550*2989f645SChris Wilson SUBTEST(test_late_rm_callback), 551*2989f645SChris Wilson SUBTEST(test_status), 552*2989f645SChris Wilson SUBTEST(test_error), 553*2989f645SChris Wilson SUBTEST(test_wait), 554*2989f645SChris Wilson SUBTEST(test_wait_timeout), 555*2989f645SChris Wilson SUBTEST(test_stub), 556*2989f645SChris Wilson SUBTEST(race_signal_callback), 557*2989f645SChris Wilson }; 558*2989f645SChris Wilson int ret; 559*2989f645SChris Wilson 560*2989f645SChris Wilson pr_info("sizeof(dma_fence)=%lu\n", sizeof(struct dma_fence)); 561*2989f645SChris Wilson 562*2989f645SChris Wilson slab_fences = KMEM_CACHE(mock_fence, 563*2989f645SChris Wilson SLAB_TYPESAFE_BY_RCU | 564*2989f645SChris Wilson SLAB_HWCACHE_ALIGN); 565*2989f645SChris Wilson if (!slab_fences) 566*2989f645SChris Wilson return -ENOMEM; 567*2989f645SChris Wilson 568*2989f645SChris Wilson ret = subtests(tests, NULL); 569*2989f645SChris Wilson 570*2989f645SChris Wilson kmem_cache_destroy(slab_fences); 571*2989f645SChris Wilson 572*2989f645SChris Wilson return ret; 573*2989f645SChris Wilson } 574