18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * SPDX-License-Identifier: MIT 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * (C) Copyright 2016 Intel Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/dma-fence.h> 98c2ecf20Sopenharmony_ci#include <linux/irq_work.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-resv.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "i915_sw_fence.h" 138c2ecf20Sopenharmony_ci#include "i915_selftest.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) 168c2ecf20Sopenharmony_ci#define I915_SW_FENCE_BUG_ON(expr) BUG_ON(expr) 178c2ecf20Sopenharmony_ci#else 188c2ecf20Sopenharmony_ci#define I915_SW_FENCE_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr) 198c2ecf20Sopenharmony_ci#endif 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define I915_SW_FENCE_FLAG_ALLOC BIT(3) /* after WQ_FLAG_* for safety */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(i915_sw_fence_lock); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cienum { 268c2ecf20Sopenharmony_ci DEBUG_FENCE_IDLE = 0, 278c2ecf20Sopenharmony_ci DEBUG_FENCE_NOTIFY, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic void *i915_sw_fence_debug_hint(void *addr) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci return (void *)(((struct i915_sw_fence *)addr)->flags & I915_SW_FENCE_MASK); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const struct debug_obj_descr i915_sw_fence_debug_descr = { 388c2ecf20Sopenharmony_ci .name = "i915_sw_fence", 398c2ecf20Sopenharmony_ci .debug_hint = i915_sw_fence_debug_hint, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic inline void debug_fence_init(struct i915_sw_fence *fence) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci debug_object_init(fence, &i915_sw_fence_debug_descr); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline void debug_fence_init_onstack(struct i915_sw_fence *fence) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci debug_object_init_on_stack(fence, &i915_sw_fence_debug_descr); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic inline void debug_fence_activate(struct i915_sw_fence *fence) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci debug_object_activate(fence, &i915_sw_fence_debug_descr); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic inline void debug_fence_set_state(struct i915_sw_fence *fence, 588c2ecf20Sopenharmony_ci int old, int new) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci debug_object_active_state(fence, &i915_sw_fence_debug_descr, old, new); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic inline void debug_fence_deactivate(struct i915_sw_fence *fence) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci debug_object_deactivate(fence, &i915_sw_fence_debug_descr); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic inline void debug_fence_destroy(struct i915_sw_fence *fence) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci debug_object_destroy(fence, &i915_sw_fence_debug_descr); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic inline void debug_fence_free(struct i915_sw_fence *fence) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci debug_object_free(fence, &i915_sw_fence_debug_descr); 768c2ecf20Sopenharmony_ci smp_wmb(); /* flush the change in state before reallocation */ 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline void debug_fence_assert(struct i915_sw_fence *fence) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci debug_object_assert_init(fence, &i915_sw_fence_debug_descr); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#else 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic inline void debug_fence_init(struct i915_sw_fence *fence) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic inline void debug_fence_init_onstack(struct i915_sw_fence *fence) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic inline void debug_fence_activate(struct i915_sw_fence *fence) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic inline void debug_fence_set_state(struct i915_sw_fence *fence, 998c2ecf20Sopenharmony_ci int old, int new) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic inline void debug_fence_deactivate(struct i915_sw_fence *fence) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic inline void debug_fence_destroy(struct i915_sw_fence *fence) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline void debug_fence_free(struct i915_sw_fence *fence) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic inline void debug_fence_assert(struct i915_sw_fence *fence) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#endif 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int __i915_sw_fence_notify(struct i915_sw_fence *fence, 1228c2ecf20Sopenharmony_ci enum i915_sw_fence_notify state) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci i915_sw_fence_notify_t fn; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci fn = (i915_sw_fence_notify_t)(fence->flags & I915_SW_FENCE_MASK); 1278c2ecf20Sopenharmony_ci return fn(fence, state); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS 1318c2ecf20Sopenharmony_civoid i915_sw_fence_fini(struct i915_sw_fence *fence) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci debug_fence_free(fence); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci#endif 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence, 1388c2ecf20Sopenharmony_ci struct list_head *continuation) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci wait_queue_head_t *x = &fence->wait; 1418c2ecf20Sopenharmony_ci wait_queue_entry_t *pos, *next; 1428c2ecf20Sopenharmony_ci unsigned long flags; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci debug_fence_deactivate(fence); 1458c2ecf20Sopenharmony_ci atomic_set_release(&fence->pending, -1); /* 0 -> -1 [done] */ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* 1488c2ecf20Sopenharmony_ci * To prevent unbounded recursion as we traverse the graph of 1498c2ecf20Sopenharmony_ci * i915_sw_fences, we move the entry list from this, the next ready 1508c2ecf20Sopenharmony_ci * fence, to the tail of the original fence's entry list 1518c2ecf20Sopenharmony_ci * (and so added to the list to be woken). 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci spin_lock_irqsave_nested(&x->lock, flags, 1 + !!continuation); 1558c2ecf20Sopenharmony_ci if (continuation) { 1568c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, next, &x->head, entry) { 1578c2ecf20Sopenharmony_ci if (pos->func == autoremove_wake_function) 1588c2ecf20Sopenharmony_ci pos->func(pos, TASK_NORMAL, 0, continuation); 1598c2ecf20Sopenharmony_ci else 1608c2ecf20Sopenharmony_ci list_move_tail(&pos->entry, continuation); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci } else { 1638c2ecf20Sopenharmony_ci LIST_HEAD(extra); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci do { 1668c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, next, &x->head, entry) { 1678c2ecf20Sopenharmony_ci int wake_flags; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci wake_flags = fence->error; 1708c2ecf20Sopenharmony_ci if (pos->func == autoremove_wake_function) 1718c2ecf20Sopenharmony_ci wake_flags = 0; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci pos->func(pos, TASK_NORMAL, wake_flags, &extra); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (list_empty(&extra)) 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci list_splice_tail_init(&extra, &x->head); 1808c2ecf20Sopenharmony_ci } while (1); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&x->lock, flags); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci debug_fence_assert(fence); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void __i915_sw_fence_complete(struct i915_sw_fence *fence, 1888c2ecf20Sopenharmony_ci struct list_head *continuation) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci debug_fence_assert(fence); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!atomic_dec_and_test(&fence->pending)) 1938c2ecf20Sopenharmony_ci return; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci debug_fence_set_state(fence, DEBUG_FENCE_IDLE, DEBUG_FENCE_NOTIFY); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (__i915_sw_fence_notify(fence, FENCE_COMPLETE) != NOTIFY_DONE) 1988c2ecf20Sopenharmony_ci return; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci debug_fence_set_state(fence, DEBUG_FENCE_NOTIFY, DEBUG_FENCE_IDLE); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci __i915_sw_fence_wake_up_all(fence, continuation); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci debug_fence_destroy(fence); 2058c2ecf20Sopenharmony_ci __i915_sw_fence_notify(fence, FENCE_FREE); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_civoid i915_sw_fence_complete(struct i915_sw_fence *fence) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci debug_fence_assert(fence); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (WARN_ON(i915_sw_fence_done(fence))) 2138c2ecf20Sopenharmony_ci return; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci __i915_sw_fence_complete(fence, NULL); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cibool i915_sw_fence_await(struct i915_sw_fence *fence) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci int pending; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci * It is only safe to add a new await to the fence while it has 2248c2ecf20Sopenharmony_ci * not yet been signaled (i.e. there are still existing signalers). 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci pending = atomic_read(&fence->pending); 2278c2ecf20Sopenharmony_ci do { 2288c2ecf20Sopenharmony_ci if (pending < 1) 2298c2ecf20Sopenharmony_ci return false; 2308c2ecf20Sopenharmony_ci } while (!atomic_try_cmpxchg(&fence->pending, &pending, pending + 1)); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return true; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_civoid __i915_sw_fence_init(struct i915_sw_fence *fence, 2368c2ecf20Sopenharmony_ci i915_sw_fence_notify_t fn, 2378c2ecf20Sopenharmony_ci const char *name, 2388c2ecf20Sopenharmony_ci struct lock_class_key *key) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci BUG_ON(!fn || (unsigned long)fn & ~I915_SW_FENCE_MASK); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci __init_waitqueue_head(&fence->wait, name, key); 2438c2ecf20Sopenharmony_ci fence->flags = (unsigned long)fn; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci i915_sw_fence_reinit(fence); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_civoid i915_sw_fence_reinit(struct i915_sw_fence *fence) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci debug_fence_init(fence); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci atomic_set(&fence->pending, 1); 2538c2ecf20Sopenharmony_ci fence->error = 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci I915_SW_FENCE_BUG_ON(!fence->flags); 2568c2ecf20Sopenharmony_ci I915_SW_FENCE_BUG_ON(!list_empty(&fence->wait.head)); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_civoid i915_sw_fence_commit(struct i915_sw_fence *fence) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci debug_fence_activate(fence); 2628c2ecf20Sopenharmony_ci i915_sw_fence_complete(fence); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int i915_sw_fence_wake(wait_queue_entry_t *wq, unsigned mode, int flags, void *key) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(wq->private, flags); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci list_del(&wq->entry); 2708c2ecf20Sopenharmony_ci __i915_sw_fence_complete(wq->private, key); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (wq->flags & I915_SW_FENCE_FLAG_ALLOC) 2738c2ecf20Sopenharmony_ci kfree(wq); 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic bool __i915_sw_fence_check_if_after(struct i915_sw_fence *fence, 2788c2ecf20Sopenharmony_ci const struct i915_sw_fence * const signaler) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci wait_queue_entry_t *wq; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (__test_and_set_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags)) 2838c2ecf20Sopenharmony_ci return false; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (fence == signaler) 2868c2ecf20Sopenharmony_ci return true; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci list_for_each_entry(wq, &fence->wait.head, entry) { 2898c2ecf20Sopenharmony_ci if (wq->func != i915_sw_fence_wake) 2908c2ecf20Sopenharmony_ci continue; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (__i915_sw_fence_check_if_after(wq->private, signaler)) 2938c2ecf20Sopenharmony_ci return true; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return false; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic void __i915_sw_fence_clear_checked_bit(struct i915_sw_fence *fence) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci wait_queue_entry_t *wq; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (!__test_and_clear_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags)) 3048c2ecf20Sopenharmony_ci return; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci list_for_each_entry(wq, &fence->wait.head, entry) { 3078c2ecf20Sopenharmony_ci if (wq->func != i915_sw_fence_wake) 3088c2ecf20Sopenharmony_ci continue; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci __i915_sw_fence_clear_checked_bit(wq->private); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic bool i915_sw_fence_check_if_after(struct i915_sw_fence *fence, 3158c2ecf20Sopenharmony_ci const struct i915_sw_fence * const signaler) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci unsigned long flags; 3188c2ecf20Sopenharmony_ci bool err; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_DRM_I915_SW_FENCE_CHECK_DAG)) 3218c2ecf20Sopenharmony_ci return false; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci spin_lock_irqsave(&i915_sw_fence_lock, flags); 3248c2ecf20Sopenharmony_ci err = __i915_sw_fence_check_if_after(fence, signaler); 3258c2ecf20Sopenharmony_ci __i915_sw_fence_clear_checked_bit(fence); 3268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&i915_sw_fence_lock, flags); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return err; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic int __i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence, 3328c2ecf20Sopenharmony_ci struct i915_sw_fence *signaler, 3338c2ecf20Sopenharmony_ci wait_queue_entry_t *wq, gfp_t gfp) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci unsigned long flags; 3368c2ecf20Sopenharmony_ci int pending; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci debug_fence_assert(fence); 3398c2ecf20Sopenharmony_ci might_sleep_if(gfpflags_allow_blocking(gfp)); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (i915_sw_fence_done(signaler)) { 3428c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(fence, signaler->error); 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci debug_fence_assert(signaler); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* The dependency graph must be acyclic. */ 3498c2ecf20Sopenharmony_ci if (unlikely(i915_sw_fence_check_if_after(fence, signaler))) 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci pending = 0; 3538c2ecf20Sopenharmony_ci if (!wq) { 3548c2ecf20Sopenharmony_ci wq = kmalloc(sizeof(*wq), gfp); 3558c2ecf20Sopenharmony_ci if (!wq) { 3568c2ecf20Sopenharmony_ci if (!gfpflags_allow_blocking(gfp)) 3578c2ecf20Sopenharmony_ci return -ENOMEM; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci i915_sw_fence_wait(signaler); 3608c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(fence, signaler->error); 3618c2ecf20Sopenharmony_ci return 0; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci pending |= I915_SW_FENCE_FLAG_ALLOC; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&wq->entry); 3688c2ecf20Sopenharmony_ci wq->flags = pending; 3698c2ecf20Sopenharmony_ci wq->func = i915_sw_fence_wake; 3708c2ecf20Sopenharmony_ci wq->private = fence; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci i915_sw_fence_await(fence); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci spin_lock_irqsave(&signaler->wait.lock, flags); 3758c2ecf20Sopenharmony_ci if (likely(!i915_sw_fence_done(signaler))) { 3768c2ecf20Sopenharmony_ci __add_wait_queue_entry_tail(&signaler->wait, wq); 3778c2ecf20Sopenharmony_ci pending = 1; 3788c2ecf20Sopenharmony_ci } else { 3798c2ecf20Sopenharmony_ci i915_sw_fence_wake(wq, 0, signaler->error, NULL); 3808c2ecf20Sopenharmony_ci pending = 0; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&signaler->wait.lock, flags); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return pending; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ciint i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence, 3888c2ecf20Sopenharmony_ci struct i915_sw_fence *signaler, 3898c2ecf20Sopenharmony_ci wait_queue_entry_t *wq) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci return __i915_sw_fence_await_sw_fence(fence, signaler, wq, 0); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciint i915_sw_fence_await_sw_fence_gfp(struct i915_sw_fence *fence, 3958c2ecf20Sopenharmony_ci struct i915_sw_fence *signaler, 3968c2ecf20Sopenharmony_ci gfp_t gfp) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci return __i915_sw_fence_await_sw_fence(fence, signaler, NULL, gfp); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistruct i915_sw_dma_fence_cb_timer { 4028c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb base; 4038c2ecf20Sopenharmony_ci struct dma_fence *dma; 4048c2ecf20Sopenharmony_ci struct timer_list timer; 4058c2ecf20Sopenharmony_ci struct irq_work work; 4068c2ecf20Sopenharmony_ci struct rcu_head rcu; 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void dma_i915_sw_fence_wake(struct dma_fence *dma, 4108c2ecf20Sopenharmony_ci struct dma_fence_cb *data) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(cb->fence, dma->error); 4158c2ecf20Sopenharmony_ci i915_sw_fence_complete(cb->fence); 4168c2ecf20Sopenharmony_ci kfree(cb); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic void timer_i915_sw_fence_wake(struct timer_list *t) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb_timer *cb = from_timer(cb, t, timer); 4228c2ecf20Sopenharmony_ci struct i915_sw_fence *fence; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci fence = xchg(&cb->base.fence, NULL); 4258c2ecf20Sopenharmony_ci if (!fence) 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci pr_notice("Asynchronous wait on fence %s:%s:%llx timed out (hint:%ps)\n", 4298c2ecf20Sopenharmony_ci cb->dma->ops->get_driver_name(cb->dma), 4308c2ecf20Sopenharmony_ci cb->dma->ops->get_timeline_name(cb->dma), 4318c2ecf20Sopenharmony_ci cb->dma->seqno, 4328c2ecf20Sopenharmony_ci i915_sw_fence_debug_hint(fence)); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(fence, -ETIMEDOUT); 4358c2ecf20Sopenharmony_ci i915_sw_fence_complete(fence); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic void dma_i915_sw_fence_wake_timer(struct dma_fence *dma, 4398c2ecf20Sopenharmony_ci struct dma_fence_cb *data) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb_timer *cb = 4428c2ecf20Sopenharmony_ci container_of(data, typeof(*cb), base.base); 4438c2ecf20Sopenharmony_ci struct i915_sw_fence *fence; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci fence = xchg(&cb->base.fence, NULL); 4468c2ecf20Sopenharmony_ci if (fence) { 4478c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(fence, dma->error); 4488c2ecf20Sopenharmony_ci i915_sw_fence_complete(fence); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci irq_work_queue(&cb->work); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void irq_i915_sw_fence_work(struct irq_work *wrk) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb_timer *cb = 4578c2ecf20Sopenharmony_ci container_of(wrk, typeof(*cb), work); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci del_timer_sync(&cb->timer); 4608c2ecf20Sopenharmony_ci dma_fence_put(cb->dma); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci kfree_rcu(cb, rcu); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ciint i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, 4668c2ecf20Sopenharmony_ci struct dma_fence *dma, 4678c2ecf20Sopenharmony_ci unsigned long timeout, 4688c2ecf20Sopenharmony_ci gfp_t gfp) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb *cb; 4718c2ecf20Sopenharmony_ci dma_fence_func_t func; 4728c2ecf20Sopenharmony_ci int ret; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci debug_fence_assert(fence); 4758c2ecf20Sopenharmony_ci might_sleep_if(gfpflags_allow_blocking(gfp)); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (dma_fence_is_signaled(dma)) { 4788c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(fence, dma->error); 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci cb = kmalloc(timeout ? 4838c2ecf20Sopenharmony_ci sizeof(struct i915_sw_dma_fence_cb_timer) : 4848c2ecf20Sopenharmony_ci sizeof(struct i915_sw_dma_fence_cb), 4858c2ecf20Sopenharmony_ci gfp); 4868c2ecf20Sopenharmony_ci if (!cb) { 4878c2ecf20Sopenharmony_ci if (!gfpflags_allow_blocking(gfp)) 4888c2ecf20Sopenharmony_ci return -ENOMEM; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci ret = dma_fence_wait(dma, false); 4918c2ecf20Sopenharmony_ci if (ret) 4928c2ecf20Sopenharmony_ci return ret; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(fence, dma->error); 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci cb->fence = fence; 4998c2ecf20Sopenharmony_ci i915_sw_fence_await(fence); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci func = dma_i915_sw_fence_wake; 5028c2ecf20Sopenharmony_ci if (timeout) { 5038c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb_timer *timer = 5048c2ecf20Sopenharmony_ci container_of(cb, typeof(*timer), base); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci timer->dma = dma_fence_get(dma); 5078c2ecf20Sopenharmony_ci init_irq_work(&timer->work, irq_i915_sw_fence_work); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci timer_setup(&timer->timer, 5108c2ecf20Sopenharmony_ci timer_i915_sw_fence_wake, TIMER_IRQSAFE); 5118c2ecf20Sopenharmony_ci mod_timer(&timer->timer, round_jiffies_up(jiffies + timeout)); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci func = dma_i915_sw_fence_wake_timer; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci ret = dma_fence_add_callback(dma, &cb->base, func); 5178c2ecf20Sopenharmony_ci if (ret == 0) { 5188c2ecf20Sopenharmony_ci ret = 1; 5198c2ecf20Sopenharmony_ci } else { 5208c2ecf20Sopenharmony_ci func(dma, &cb->base); 5218c2ecf20Sopenharmony_ci if (ret == -ENOENT) /* fence already signaled */ 5228c2ecf20Sopenharmony_ci ret = 0; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return ret; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic void __dma_i915_sw_fence_wake(struct dma_fence *dma, 5298c2ecf20Sopenharmony_ci struct dma_fence_cb *data) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(cb->fence, dma->error); 5348c2ecf20Sopenharmony_ci i915_sw_fence_complete(cb->fence); 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ciint __i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, 5388c2ecf20Sopenharmony_ci struct dma_fence *dma, 5398c2ecf20Sopenharmony_ci struct i915_sw_dma_fence_cb *cb) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci int ret; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci debug_fence_assert(fence); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (dma_fence_is_signaled(dma)) { 5468c2ecf20Sopenharmony_ci i915_sw_fence_set_error_once(fence, dma->error); 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci cb->fence = fence; 5518c2ecf20Sopenharmony_ci i915_sw_fence_await(fence); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci ret = 1; 5548c2ecf20Sopenharmony_ci if (dma_fence_add_callback(dma, &cb->base, __dma_i915_sw_fence_wake)) { 5558c2ecf20Sopenharmony_ci /* fence already signaled */ 5568c2ecf20Sopenharmony_ci __dma_i915_sw_fence_wake(dma, &cb->base); 5578c2ecf20Sopenharmony_ci ret = 0; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ciint i915_sw_fence_await_reservation(struct i915_sw_fence *fence, 5648c2ecf20Sopenharmony_ci struct dma_resv *resv, 5658c2ecf20Sopenharmony_ci const struct dma_fence_ops *exclude, 5668c2ecf20Sopenharmony_ci bool write, 5678c2ecf20Sopenharmony_ci unsigned long timeout, 5688c2ecf20Sopenharmony_ci gfp_t gfp) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct dma_fence *excl; 5718c2ecf20Sopenharmony_ci int ret = 0, pending; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci debug_fence_assert(fence); 5748c2ecf20Sopenharmony_ci might_sleep_if(gfpflags_allow_blocking(gfp)); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (write) { 5778c2ecf20Sopenharmony_ci struct dma_fence **shared; 5788c2ecf20Sopenharmony_ci unsigned int count, i; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci ret = dma_resv_get_fences_rcu(resv, &excl, &count, &shared); 5818c2ecf20Sopenharmony_ci if (ret) 5828c2ecf20Sopenharmony_ci return ret; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 5858c2ecf20Sopenharmony_ci if (shared[i]->ops == exclude) 5868c2ecf20Sopenharmony_ci continue; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci pending = i915_sw_fence_await_dma_fence(fence, 5898c2ecf20Sopenharmony_ci shared[i], 5908c2ecf20Sopenharmony_ci timeout, 5918c2ecf20Sopenharmony_ci gfp); 5928c2ecf20Sopenharmony_ci if (pending < 0) { 5938c2ecf20Sopenharmony_ci ret = pending; 5948c2ecf20Sopenharmony_ci break; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci ret |= pending; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 6018c2ecf20Sopenharmony_ci dma_fence_put(shared[i]); 6028c2ecf20Sopenharmony_ci kfree(shared); 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci excl = dma_resv_get_excl_rcu(resv); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (ret >= 0 && excl && excl->ops != exclude) { 6088c2ecf20Sopenharmony_ci pending = i915_sw_fence_await_dma_fence(fence, 6098c2ecf20Sopenharmony_ci excl, 6108c2ecf20Sopenharmony_ci timeout, 6118c2ecf20Sopenharmony_ci gfp); 6128c2ecf20Sopenharmony_ci if (pending < 0) 6138c2ecf20Sopenharmony_ci ret = pending; 6148c2ecf20Sopenharmony_ci else 6158c2ecf20Sopenharmony_ci ret |= pending; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci dma_fence_put(excl); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return ret; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 6248c2ecf20Sopenharmony_ci#include "selftests/lib_sw_fence.c" 6258c2ecf20Sopenharmony_ci#include "selftests/i915_sw_fence.c" 6268c2ecf20Sopenharmony_ci#endif 627