162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * SPDX-License-Identifier: MIT 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * (C) Copyright 2016 Intel Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/dma-fence.h> 962306a36Sopenharmony_ci#include <linux/irq_work.h> 1062306a36Sopenharmony_ci#include <linux/dma-resv.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "i915_sw_fence.h" 1362306a36Sopenharmony_ci#include "i915_selftest.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) 1662306a36Sopenharmony_ci#define I915_SW_FENCE_BUG_ON(expr) BUG_ON(expr) 1762306a36Sopenharmony_ci#else 1862306a36Sopenharmony_ci#define I915_SW_FENCE_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr) 1962306a36Sopenharmony_ci#endif 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_CHECK_DAG 2262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(i915_sw_fence_lock); 2362306a36Sopenharmony_ci#endif 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define WQ_FLAG_BITS \ 2662306a36Sopenharmony_ci BITS_PER_TYPE(typeof_member(struct wait_queue_entry, flags)) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* after WQ_FLAG_* for safety */ 2962306a36Sopenharmony_ci#define I915_SW_FENCE_FLAG_FENCE BIT(WQ_FLAG_BITS - 1) 3062306a36Sopenharmony_ci#define I915_SW_FENCE_FLAG_ALLOC BIT(WQ_FLAG_BITS - 2) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cienum { 3362306a36Sopenharmony_ci DEBUG_FENCE_IDLE = 0, 3462306a36Sopenharmony_ci DEBUG_FENCE_NOTIFY, 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void *i915_sw_fence_debug_hint(void *addr) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci return (void *)(((struct i915_sw_fence *)addr)->fn); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic const struct debug_obj_descr i915_sw_fence_debug_descr = { 4562306a36Sopenharmony_ci .name = "i915_sw_fence", 4662306a36Sopenharmony_ci .debug_hint = i915_sw_fence_debug_hint, 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic inline void debug_fence_init(struct i915_sw_fence *fence) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci debug_object_init(fence, &i915_sw_fence_debug_descr); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic inline void debug_fence_init_onstack(struct i915_sw_fence *fence) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci debug_object_init_on_stack(fence, &i915_sw_fence_debug_descr); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline void debug_fence_activate(struct i915_sw_fence *fence) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci debug_object_activate(fence, &i915_sw_fence_debug_descr); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic inline void debug_fence_set_state(struct i915_sw_fence *fence, 6562306a36Sopenharmony_ci int old, int new) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci debug_object_active_state(fence, &i915_sw_fence_debug_descr, old, new); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline void debug_fence_deactivate(struct i915_sw_fence *fence) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci debug_object_deactivate(fence, &i915_sw_fence_debug_descr); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic inline void debug_fence_destroy(struct i915_sw_fence *fence) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci debug_object_destroy(fence, &i915_sw_fence_debug_descr); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic inline void debug_fence_free(struct i915_sw_fence *fence) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci debug_object_free(fence, &i915_sw_fence_debug_descr); 8362306a36Sopenharmony_ci smp_wmb(); /* flush the change in state before reallocation */ 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic inline void debug_fence_assert(struct i915_sw_fence *fence) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci debug_object_assert_init(fence, &i915_sw_fence_debug_descr); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#else 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic inline void debug_fence_init(struct i915_sw_fence *fence) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic inline void debug_fence_init_onstack(struct i915_sw_fence *fence) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic inline void debug_fence_activate(struct i915_sw_fence *fence) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic inline void debug_fence_set_state(struct i915_sw_fence *fence, 10662306a36Sopenharmony_ci int old, int new) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic inline void debug_fence_deactivate(struct i915_sw_fence *fence) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic inline void debug_fence_destroy(struct i915_sw_fence *fence) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline void debug_fence_free(struct i915_sw_fence *fence) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic inline void debug_fence_assert(struct i915_sw_fence *fence) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#endif 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int __i915_sw_fence_notify(struct i915_sw_fence *fence, 12962306a36Sopenharmony_ci enum i915_sw_fence_notify state) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci return fence->fn(fence, state); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS 13562306a36Sopenharmony_civoid i915_sw_fence_fini(struct i915_sw_fence *fence) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci debug_fence_free(fence); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci#endif 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence, 14262306a36Sopenharmony_ci struct list_head *continuation) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci wait_queue_head_t *x = &fence->wait; 14562306a36Sopenharmony_ci wait_queue_entry_t *pos, *next; 14662306a36Sopenharmony_ci unsigned long flags; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci debug_fence_deactivate(fence); 14962306a36Sopenharmony_ci atomic_set_release(&fence->pending, -1); /* 0 -> -1 [done] */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * To prevent unbounded recursion as we traverse the graph of 15362306a36Sopenharmony_ci * i915_sw_fences, we move the entry list from this, the next ready 15462306a36Sopenharmony_ci * fence, to the tail of the original fence's entry list 15562306a36Sopenharmony_ci * (and so added to the list to be woken). 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci spin_lock_irqsave_nested(&x->lock, flags, 1 + !!continuation); 15962306a36Sopenharmony_ci if (continuation) { 16062306a36Sopenharmony_ci list_for_each_entry_safe(pos, next, &x->head, entry) { 16162306a36Sopenharmony_ci if (pos->flags & I915_SW_FENCE_FLAG_FENCE) 16262306a36Sopenharmony_ci list_move_tail(&pos->entry, continuation); 16362306a36Sopenharmony_ci else 16462306a36Sopenharmony_ci pos->func(pos, TASK_NORMAL, 0, continuation); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci } else { 16762306a36Sopenharmony_ci LIST_HEAD(extra); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci do { 17062306a36Sopenharmony_ci list_for_each_entry_safe(pos, next, &x->head, entry) { 17162306a36Sopenharmony_ci int wake_flags; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci wake_flags = 0; 17462306a36Sopenharmony_ci if (pos->flags & I915_SW_FENCE_FLAG_FENCE) 17562306a36Sopenharmony_ci wake_flags = fence->error; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci pos->func(pos, TASK_NORMAL, wake_flags, &extra); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (list_empty(&extra)) 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci list_splice_tail_init(&extra, &x->head); 18462306a36Sopenharmony_ci } while (1); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci spin_unlock_irqrestore(&x->lock, flags); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci debug_fence_assert(fence); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void __i915_sw_fence_complete(struct i915_sw_fence *fence, 19262306a36Sopenharmony_ci struct list_head *continuation) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci debug_fence_assert(fence); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (!atomic_dec_and_test(&fence->pending)) 19762306a36Sopenharmony_ci return; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci debug_fence_set_state(fence, DEBUG_FENCE_IDLE, DEBUG_FENCE_NOTIFY); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (__i915_sw_fence_notify(fence, FENCE_COMPLETE) != NOTIFY_DONE) 20262306a36Sopenharmony_ci return; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci debug_fence_set_state(fence, DEBUG_FENCE_NOTIFY, DEBUG_FENCE_IDLE); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci __i915_sw_fence_wake_up_all(fence, continuation); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci debug_fence_destroy(fence); 20962306a36Sopenharmony_ci __i915_sw_fence_notify(fence, FENCE_FREE); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_civoid i915_sw_fence_complete(struct i915_sw_fence *fence) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci debug_fence_assert(fence); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (WARN_ON(i915_sw_fence_done(fence))) 21762306a36Sopenharmony_ci return; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci __i915_sw_fence_complete(fence, NULL); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cibool i915_sw_fence_await(struct i915_sw_fence *fence) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci int pending; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * It is only safe to add a new await to the fence while it has 22862306a36Sopenharmony_ci * not yet been signaled (i.e. there are still existing signalers). 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci pending = atomic_read(&fence->pending); 23162306a36Sopenharmony_ci do { 23262306a36Sopenharmony_ci if (pending < 1) 23362306a36Sopenharmony_ci return false; 23462306a36Sopenharmony_ci } while (!atomic_try_cmpxchg(&fence->pending, &pending, pending + 1)); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return true; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_civoid __i915_sw_fence_init(struct i915_sw_fence *fence, 24062306a36Sopenharmony_ci i915_sw_fence_notify_t fn, 24162306a36Sopenharmony_ci const char *name, 24262306a36Sopenharmony_ci struct lock_class_key *key) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci __init_waitqueue_head(&fence->wait, name, key); 24562306a36Sopenharmony_ci fence->fn = fn; 24662306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_CHECK_DAG 24762306a36Sopenharmony_ci fence->flags = 0; 24862306a36Sopenharmony_ci#endif 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci i915_sw_fence_reinit(fence); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_civoid i915_sw_fence_reinit(struct i915_sw_fence *fence) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci debug_fence_init(fence); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci atomic_set(&fence->pending, 1); 25862306a36Sopenharmony_ci fence->error = 0; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci I915_SW_FENCE_BUG_ON(!list_empty(&fence->wait.head)); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_civoid i915_sw_fence_commit(struct i915_sw_fence *fence) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci debug_fence_activate(fence); 26662306a36Sopenharmony_ci i915_sw_fence_complete(fence); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int i915_sw_fence_wake(wait_queue_entry_t *wq, unsigned mode, int flags, void *key) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci i915_sw_fence_set_error_once(wq->private, flags); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci list_del(&wq->entry); 27462306a36Sopenharmony_ci __i915_sw_fence_complete(wq->private, key); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (wq->flags & I915_SW_FENCE_FLAG_ALLOC) 27762306a36Sopenharmony_ci kfree(wq); 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_CHECK_DAG 28262306a36Sopenharmony_cistatic bool __i915_sw_fence_check_if_after(struct i915_sw_fence *fence, 28362306a36Sopenharmony_ci const struct i915_sw_fence * const signaler) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci wait_queue_entry_t *wq; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (__test_and_set_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags)) 28862306a36Sopenharmony_ci return false; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (fence == signaler) 29162306a36Sopenharmony_ci return true; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci list_for_each_entry(wq, &fence->wait.head, entry) { 29462306a36Sopenharmony_ci if (wq->func != i915_sw_fence_wake) 29562306a36Sopenharmony_ci continue; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (__i915_sw_fence_check_if_after(wq->private, signaler)) 29862306a36Sopenharmony_ci return true; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return false; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void __i915_sw_fence_clear_checked_bit(struct i915_sw_fence *fence) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci wait_queue_entry_t *wq; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (!__test_and_clear_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags)) 30962306a36Sopenharmony_ci return; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci list_for_each_entry(wq, &fence->wait.head, entry) { 31262306a36Sopenharmony_ci if (wq->func != i915_sw_fence_wake) 31362306a36Sopenharmony_ci continue; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci __i915_sw_fence_clear_checked_bit(wq->private); 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic bool i915_sw_fence_check_if_after(struct i915_sw_fence *fence, 32062306a36Sopenharmony_ci const struct i915_sw_fence * const signaler) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci unsigned long flags; 32362306a36Sopenharmony_ci bool err; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci spin_lock_irqsave(&i915_sw_fence_lock, flags); 32662306a36Sopenharmony_ci err = __i915_sw_fence_check_if_after(fence, signaler); 32762306a36Sopenharmony_ci __i915_sw_fence_clear_checked_bit(fence); 32862306a36Sopenharmony_ci spin_unlock_irqrestore(&i915_sw_fence_lock, flags); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return err; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci#else 33362306a36Sopenharmony_cistatic bool i915_sw_fence_check_if_after(struct i915_sw_fence *fence, 33462306a36Sopenharmony_ci const struct i915_sw_fence * const signaler) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci return false; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci#endif 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic int __i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence, 34162306a36Sopenharmony_ci struct i915_sw_fence *signaler, 34262306a36Sopenharmony_ci wait_queue_entry_t *wq, gfp_t gfp) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci unsigned int pending; 34562306a36Sopenharmony_ci unsigned long flags; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci debug_fence_assert(fence); 34862306a36Sopenharmony_ci might_sleep_if(gfpflags_allow_blocking(gfp)); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (i915_sw_fence_done(signaler)) { 35162306a36Sopenharmony_ci i915_sw_fence_set_error_once(fence, signaler->error); 35262306a36Sopenharmony_ci return 0; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci debug_fence_assert(signaler); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* The dependency graph must be acyclic. */ 35862306a36Sopenharmony_ci if (unlikely(i915_sw_fence_check_if_after(fence, signaler))) 35962306a36Sopenharmony_ci return -EINVAL; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci pending = I915_SW_FENCE_FLAG_FENCE; 36262306a36Sopenharmony_ci if (!wq) { 36362306a36Sopenharmony_ci wq = kmalloc(sizeof(*wq), gfp); 36462306a36Sopenharmony_ci if (!wq) { 36562306a36Sopenharmony_ci if (!gfpflags_allow_blocking(gfp)) 36662306a36Sopenharmony_ci return -ENOMEM; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci i915_sw_fence_wait(signaler); 36962306a36Sopenharmony_ci i915_sw_fence_set_error_once(fence, signaler->error); 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci pending |= I915_SW_FENCE_FLAG_ALLOC; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci INIT_LIST_HEAD(&wq->entry); 37762306a36Sopenharmony_ci wq->flags = pending; 37862306a36Sopenharmony_ci wq->func = i915_sw_fence_wake; 37962306a36Sopenharmony_ci wq->private = fence; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci i915_sw_fence_await(fence); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci spin_lock_irqsave(&signaler->wait.lock, flags); 38462306a36Sopenharmony_ci if (likely(!i915_sw_fence_done(signaler))) { 38562306a36Sopenharmony_ci __add_wait_queue_entry_tail(&signaler->wait, wq); 38662306a36Sopenharmony_ci pending = 1; 38762306a36Sopenharmony_ci } else { 38862306a36Sopenharmony_ci i915_sw_fence_wake(wq, 0, signaler->error, NULL); 38962306a36Sopenharmony_ci pending = 0; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci spin_unlock_irqrestore(&signaler->wait.lock, flags); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return pending; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ciint i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence, 39762306a36Sopenharmony_ci struct i915_sw_fence *signaler, 39862306a36Sopenharmony_ci wait_queue_entry_t *wq) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci return __i915_sw_fence_await_sw_fence(fence, signaler, wq, 0); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ciint i915_sw_fence_await_sw_fence_gfp(struct i915_sw_fence *fence, 40462306a36Sopenharmony_ci struct i915_sw_fence *signaler, 40562306a36Sopenharmony_ci gfp_t gfp) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci return __i915_sw_fence_await_sw_fence(fence, signaler, NULL, gfp); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistruct i915_sw_dma_fence_cb_timer { 41162306a36Sopenharmony_ci struct i915_sw_dma_fence_cb base; 41262306a36Sopenharmony_ci struct dma_fence *dma; 41362306a36Sopenharmony_ci struct timer_list timer; 41462306a36Sopenharmony_ci struct irq_work work; 41562306a36Sopenharmony_ci struct rcu_head rcu; 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic void dma_i915_sw_fence_wake(struct dma_fence *dma, 41962306a36Sopenharmony_ci struct dma_fence_cb *data) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci i915_sw_fence_set_error_once(cb->fence, dma->error); 42462306a36Sopenharmony_ci i915_sw_fence_complete(cb->fence); 42562306a36Sopenharmony_ci kfree(cb); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void timer_i915_sw_fence_wake(struct timer_list *t) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct i915_sw_dma_fence_cb_timer *cb = from_timer(cb, t, timer); 43162306a36Sopenharmony_ci struct i915_sw_fence *fence; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci fence = xchg(&cb->base.fence, NULL); 43462306a36Sopenharmony_ci if (!fence) 43562306a36Sopenharmony_ci return; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci pr_notice("Asynchronous wait on fence %s:%s:%llx timed out (hint:%ps)\n", 43862306a36Sopenharmony_ci cb->dma->ops->get_driver_name(cb->dma), 43962306a36Sopenharmony_ci cb->dma->ops->get_timeline_name(cb->dma), 44062306a36Sopenharmony_ci cb->dma->seqno, 44162306a36Sopenharmony_ci i915_sw_fence_debug_hint(fence)); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci i915_sw_fence_set_error_once(fence, -ETIMEDOUT); 44462306a36Sopenharmony_ci i915_sw_fence_complete(fence); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic void dma_i915_sw_fence_wake_timer(struct dma_fence *dma, 44862306a36Sopenharmony_ci struct dma_fence_cb *data) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct i915_sw_dma_fence_cb_timer *cb = 45162306a36Sopenharmony_ci container_of(data, typeof(*cb), base.base); 45262306a36Sopenharmony_ci struct i915_sw_fence *fence; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci fence = xchg(&cb->base.fence, NULL); 45562306a36Sopenharmony_ci if (fence) { 45662306a36Sopenharmony_ci i915_sw_fence_set_error_once(fence, dma->error); 45762306a36Sopenharmony_ci i915_sw_fence_complete(fence); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci irq_work_queue(&cb->work); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic void irq_i915_sw_fence_work(struct irq_work *wrk) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct i915_sw_dma_fence_cb_timer *cb = 46662306a36Sopenharmony_ci container_of(wrk, typeof(*cb), work); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci timer_shutdown_sync(&cb->timer); 46962306a36Sopenharmony_ci dma_fence_put(cb->dma); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci kfree_rcu(cb, rcu); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ciint i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, 47562306a36Sopenharmony_ci struct dma_fence *dma, 47662306a36Sopenharmony_ci unsigned long timeout, 47762306a36Sopenharmony_ci gfp_t gfp) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct i915_sw_dma_fence_cb *cb; 48062306a36Sopenharmony_ci dma_fence_func_t func; 48162306a36Sopenharmony_ci int ret; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci debug_fence_assert(fence); 48462306a36Sopenharmony_ci might_sleep_if(gfpflags_allow_blocking(gfp)); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (dma_fence_is_signaled(dma)) { 48762306a36Sopenharmony_ci i915_sw_fence_set_error_once(fence, dma->error); 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci cb = kmalloc(timeout ? 49262306a36Sopenharmony_ci sizeof(struct i915_sw_dma_fence_cb_timer) : 49362306a36Sopenharmony_ci sizeof(struct i915_sw_dma_fence_cb), 49462306a36Sopenharmony_ci gfp); 49562306a36Sopenharmony_ci if (!cb) { 49662306a36Sopenharmony_ci if (!gfpflags_allow_blocking(gfp)) 49762306a36Sopenharmony_ci return -ENOMEM; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci ret = dma_fence_wait(dma, false); 50062306a36Sopenharmony_ci if (ret) 50162306a36Sopenharmony_ci return ret; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci i915_sw_fence_set_error_once(fence, dma->error); 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci cb->fence = fence; 50862306a36Sopenharmony_ci i915_sw_fence_await(fence); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci func = dma_i915_sw_fence_wake; 51162306a36Sopenharmony_ci if (timeout) { 51262306a36Sopenharmony_ci struct i915_sw_dma_fence_cb_timer *timer = 51362306a36Sopenharmony_ci container_of(cb, typeof(*timer), base); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci timer->dma = dma_fence_get(dma); 51662306a36Sopenharmony_ci init_irq_work(&timer->work, irq_i915_sw_fence_work); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci timer_setup(&timer->timer, 51962306a36Sopenharmony_ci timer_i915_sw_fence_wake, TIMER_IRQSAFE); 52062306a36Sopenharmony_ci mod_timer(&timer->timer, round_jiffies_up(jiffies + timeout)); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci func = dma_i915_sw_fence_wake_timer; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ret = dma_fence_add_callback(dma, &cb->base, func); 52662306a36Sopenharmony_ci if (ret == 0) { 52762306a36Sopenharmony_ci ret = 1; 52862306a36Sopenharmony_ci } else { 52962306a36Sopenharmony_ci func(dma, &cb->base); 53062306a36Sopenharmony_ci if (ret == -ENOENT) /* fence already signaled */ 53162306a36Sopenharmony_ci ret = 0; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return ret; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void __dma_i915_sw_fence_wake(struct dma_fence *dma, 53862306a36Sopenharmony_ci struct dma_fence_cb *data) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci i915_sw_fence_set_error_once(cb->fence, dma->error); 54362306a36Sopenharmony_ci i915_sw_fence_complete(cb->fence); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ciint __i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, 54762306a36Sopenharmony_ci struct dma_fence *dma, 54862306a36Sopenharmony_ci struct i915_sw_dma_fence_cb *cb) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci int ret; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci debug_fence_assert(fence); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (dma_fence_is_signaled(dma)) { 55562306a36Sopenharmony_ci i915_sw_fence_set_error_once(fence, dma->error); 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci cb->fence = fence; 56062306a36Sopenharmony_ci i915_sw_fence_await(fence); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ret = 1; 56362306a36Sopenharmony_ci if (dma_fence_add_callback(dma, &cb->base, __dma_i915_sw_fence_wake)) { 56462306a36Sopenharmony_ci /* fence already signaled */ 56562306a36Sopenharmony_ci __dma_i915_sw_fence_wake(dma, &cb->base); 56662306a36Sopenharmony_ci ret = 0; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return ret; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ciint i915_sw_fence_await_reservation(struct i915_sw_fence *fence, 57362306a36Sopenharmony_ci struct dma_resv *resv, 57462306a36Sopenharmony_ci bool write, 57562306a36Sopenharmony_ci unsigned long timeout, 57662306a36Sopenharmony_ci gfp_t gfp) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct dma_resv_iter cursor; 57962306a36Sopenharmony_ci struct dma_fence *f; 58062306a36Sopenharmony_ci int ret = 0, pending; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci debug_fence_assert(fence); 58362306a36Sopenharmony_ci might_sleep_if(gfpflags_allow_blocking(gfp)); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci dma_resv_iter_begin(&cursor, resv, dma_resv_usage_rw(write)); 58662306a36Sopenharmony_ci dma_resv_for_each_fence_unlocked(&cursor, f) { 58762306a36Sopenharmony_ci pending = i915_sw_fence_await_dma_fence(fence, f, timeout, 58862306a36Sopenharmony_ci gfp); 58962306a36Sopenharmony_ci if (pending < 0) { 59062306a36Sopenharmony_ci ret = pending; 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci ret |= pending; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci dma_resv_iter_end(&cursor); 59762306a36Sopenharmony_ci return ret; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 60162306a36Sopenharmony_ci#include "selftests/lib_sw_fence.c" 60262306a36Sopenharmony_ci#include "selftests/i915_sw_fence.c" 60362306a36Sopenharmony_ci#endif 604