162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * SPDX-License-Identifier: MIT 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/debugobjects.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "gt/intel_context.h" 1062306a36Sopenharmony_ci#include "gt/intel_engine_heartbeat.h" 1162306a36Sopenharmony_ci#include "gt/intel_engine_pm.h" 1262306a36Sopenharmony_ci#include "gt/intel_ring.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "i915_drv.h" 1562306a36Sopenharmony_ci#include "i915_active.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Active refs memory management 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * To be more economical with memory, we reap all the i915_active trees as 2162306a36Sopenharmony_ci * they idle (when we know the active requests are inactive) and allocate the 2262306a36Sopenharmony_ci * nodes from a local slab cache to hopefully reduce the fragmentation. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_cistatic struct kmem_cache *slab_cache; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct active_node { 2762306a36Sopenharmony_ci struct rb_node node; 2862306a36Sopenharmony_ci struct i915_active_fence base; 2962306a36Sopenharmony_ci struct i915_active *ref; 3062306a36Sopenharmony_ci u64 timeline; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define fetch_node(x) rb_entry(READ_ONCE(x), typeof(struct active_node), node) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic inline struct active_node * 3662306a36Sopenharmony_cinode_from_active(struct i915_active_fence *active) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci return container_of(active, struct active_node, base); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define take_preallocated_barriers(x) llist_del_all(&(x)->preallocated_barriers) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic inline bool is_barrier(const struct i915_active_fence *active) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci return IS_ERR(rcu_access_pointer(active->fence)); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic inline struct llist_node *barrier_to_ll(struct active_node *node) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci GEM_BUG_ON(!is_barrier(&node->base)); 5162306a36Sopenharmony_ci return (struct llist_node *)&node->base.cb.node; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic inline struct intel_engine_cs * 5562306a36Sopenharmony_ci__barrier_to_engine(struct active_node *node) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return (struct intel_engine_cs *)READ_ONCE(node->base.cb.node.prev); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic inline struct intel_engine_cs * 6162306a36Sopenharmony_cibarrier_to_engine(struct active_node *node) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci GEM_BUG_ON(!is_barrier(&node->base)); 6462306a36Sopenharmony_ci return __barrier_to_engine(node); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic inline struct active_node *barrier_from_ll(struct llist_node *x) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return container_of((struct list_head *)x, 7062306a36Sopenharmony_ci struct active_node, base.cb.node); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) && IS_ENABLED(CONFIG_DEBUG_OBJECTS) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void *active_debug_hint(void *addr) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct i915_active *ref = addr; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return (void *)ref->active ?: (void *)ref->retire ?: (void *)ref; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic const struct debug_obj_descr active_debug_desc = { 8362306a36Sopenharmony_ci .name = "i915_active", 8462306a36Sopenharmony_ci .debug_hint = active_debug_hint, 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void debug_active_init(struct i915_active *ref) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci debug_object_init(ref, &active_debug_desc); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic void debug_active_activate(struct i915_active *ref) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci lockdep_assert_held(&ref->tree_lock); 9562306a36Sopenharmony_ci debug_object_activate(ref, &active_debug_desc); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void debug_active_deactivate(struct i915_active *ref) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci lockdep_assert_held(&ref->tree_lock); 10162306a36Sopenharmony_ci if (!atomic_read(&ref->count)) /* after the last dec */ 10262306a36Sopenharmony_ci debug_object_deactivate(ref, &active_debug_desc); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void debug_active_fini(struct i915_active *ref) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci debug_object_free(ref, &active_debug_desc); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void debug_active_assert(struct i915_active *ref) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci debug_object_assert_init(ref, &active_debug_desc); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#else 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline void debug_active_init(struct i915_active *ref) { } 11862306a36Sopenharmony_cistatic inline void debug_active_activate(struct i915_active *ref) { } 11962306a36Sopenharmony_cistatic inline void debug_active_deactivate(struct i915_active *ref) { } 12062306a36Sopenharmony_cistatic inline void debug_active_fini(struct i915_active *ref) { } 12162306a36Sopenharmony_cistatic inline void debug_active_assert(struct i915_active *ref) { } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#endif 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void 12662306a36Sopenharmony_ci__active_retire(struct i915_active *ref) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct rb_root root = RB_ROOT; 12962306a36Sopenharmony_ci struct active_node *it, *n; 13062306a36Sopenharmony_ci unsigned long flags; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci GEM_BUG_ON(i915_active_is_idle(ref)); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* return the unused nodes to our slabcache -- flushing the allocator */ 13562306a36Sopenharmony_ci if (!atomic_dec_and_lock_irqsave(&ref->count, &ref->tree_lock, flags)) 13662306a36Sopenharmony_ci return; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci GEM_BUG_ON(rcu_access_pointer(ref->excl.fence)); 13962306a36Sopenharmony_ci debug_active_deactivate(ref); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Even if we have not used the cache, we may still have a barrier */ 14262306a36Sopenharmony_ci if (!ref->cache) 14362306a36Sopenharmony_ci ref->cache = fetch_node(ref->tree.rb_node); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Keep the MRU cached node for reuse */ 14662306a36Sopenharmony_ci if (ref->cache) { 14762306a36Sopenharmony_ci /* Discard all other nodes in the tree */ 14862306a36Sopenharmony_ci rb_erase(&ref->cache->node, &ref->tree); 14962306a36Sopenharmony_ci root = ref->tree; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Rebuild the tree with only the cached node */ 15262306a36Sopenharmony_ci rb_link_node(&ref->cache->node, NULL, &ref->tree.rb_node); 15362306a36Sopenharmony_ci rb_insert_color(&ref->cache->node, &ref->tree); 15462306a36Sopenharmony_ci GEM_BUG_ON(ref->tree.rb_node != &ref->cache->node); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Make the cached node available for reuse with any timeline */ 15762306a36Sopenharmony_ci ref->cache->timeline = 0; /* needs cmpxchg(u64) */ 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci spin_unlock_irqrestore(&ref->tree_lock, flags); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* After the final retire, the entire struct may be freed */ 16362306a36Sopenharmony_ci if (ref->retire) 16462306a36Sopenharmony_ci ref->retire(ref); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* ... except if you wait on it, you must manage your own references! */ 16762306a36Sopenharmony_ci wake_up_var(ref); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* Finally free the discarded timeline tree */ 17062306a36Sopenharmony_ci rbtree_postorder_for_each_entry_safe(it, n, &root, node) { 17162306a36Sopenharmony_ci GEM_BUG_ON(i915_active_fence_isset(&it->base)); 17262306a36Sopenharmony_ci kmem_cache_free(slab_cache, it); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic void 17762306a36Sopenharmony_ciactive_work(struct work_struct *wrk) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct i915_active *ref = container_of(wrk, typeof(*ref), work); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci GEM_BUG_ON(!atomic_read(&ref->count)); 18262306a36Sopenharmony_ci if (atomic_add_unless(&ref->count, -1, 1)) 18362306a36Sopenharmony_ci return; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci __active_retire(ref); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void 18962306a36Sopenharmony_ciactive_retire(struct i915_active *ref) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci GEM_BUG_ON(!atomic_read(&ref->count)); 19262306a36Sopenharmony_ci if (atomic_add_unless(&ref->count, -1, 1)) 19362306a36Sopenharmony_ci return; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (ref->flags & I915_ACTIVE_RETIRE_SLEEPS) { 19662306a36Sopenharmony_ci queue_work(system_unbound_wq, &ref->work); 19762306a36Sopenharmony_ci return; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci __active_retire(ref); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic inline struct dma_fence ** 20462306a36Sopenharmony_ci__active_fence_slot(struct i915_active_fence *active) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci return (struct dma_fence ** __force)&active->fence; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline bool 21062306a36Sopenharmony_ciactive_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct i915_active_fence *active = 21362306a36Sopenharmony_ci container_of(cb, typeof(*active), cb); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return cmpxchg(__active_fence_slot(active), fence, NULL) == fence; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void 21962306a36Sopenharmony_cinode_retire(struct dma_fence *fence, struct dma_fence_cb *cb) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci if (active_fence_cb(fence, cb)) 22262306a36Sopenharmony_ci active_retire(container_of(cb, struct active_node, base.cb)->ref); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic void 22662306a36Sopenharmony_ciexcl_retire(struct dma_fence *fence, struct dma_fence_cb *cb) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci if (active_fence_cb(fence, cb)) 22962306a36Sopenharmony_ci active_retire(container_of(cb, struct i915_active, excl.cb)); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic struct active_node *__active_lookup(struct i915_active *ref, u64 idx) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct active_node *it; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci GEM_BUG_ON(idx == 0); /* 0 is the unordered timeline, rsvd for cache */ 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* 23962306a36Sopenharmony_ci * We track the most recently used timeline to skip a rbtree search 24062306a36Sopenharmony_ci * for the common case, under typical loads we never need the rbtree 24162306a36Sopenharmony_ci * at all. We can reuse the last slot if it is empty, that is 24262306a36Sopenharmony_ci * after the previous activity has been retired, or if it matches the 24362306a36Sopenharmony_ci * current timeline. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci it = READ_ONCE(ref->cache); 24662306a36Sopenharmony_ci if (it) { 24762306a36Sopenharmony_ci u64 cached = READ_ONCE(it->timeline); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Once claimed, this slot will only belong to this idx */ 25062306a36Sopenharmony_ci if (cached == idx) 25162306a36Sopenharmony_ci return it; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * An unclaimed cache [.timeline=0] can only be claimed once. 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * If the value is already non-zero, some other thread has 25762306a36Sopenharmony_ci * claimed the cache and we know that is does not match our 25862306a36Sopenharmony_ci * idx. If, and only if, the timeline is currently zero is it 25962306a36Sopenharmony_ci * worth competing to claim it atomically for ourselves (for 26062306a36Sopenharmony_ci * only the winner of that race will cmpxchg return the old 26162306a36Sopenharmony_ci * value of 0). 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci if (!cached && !cmpxchg64(&it->timeline, 0, idx)) 26462306a36Sopenharmony_ci return it; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(typeof(*it), node)); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* While active, the tree can only be built; not destroyed */ 27062306a36Sopenharmony_ci GEM_BUG_ON(i915_active_is_idle(ref)); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci it = fetch_node(ref->tree.rb_node); 27362306a36Sopenharmony_ci while (it) { 27462306a36Sopenharmony_ci if (it->timeline < idx) { 27562306a36Sopenharmony_ci it = fetch_node(it->node.rb_right); 27662306a36Sopenharmony_ci } else if (it->timeline > idx) { 27762306a36Sopenharmony_ci it = fetch_node(it->node.rb_left); 27862306a36Sopenharmony_ci } else { 27962306a36Sopenharmony_ci WRITE_ONCE(ref->cache, it); 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* NB: If the tree rotated beneath us, we may miss our target. */ 28562306a36Sopenharmony_ci return it; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic struct i915_active_fence * 28962306a36Sopenharmony_ciactive_instance(struct i915_active *ref, u64 idx) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct active_node *node; 29262306a36Sopenharmony_ci struct rb_node **p, *parent; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci node = __active_lookup(ref, idx); 29562306a36Sopenharmony_ci if (likely(node)) 29662306a36Sopenharmony_ci return &node->base; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci spin_lock_irq(&ref->tree_lock); 29962306a36Sopenharmony_ci GEM_BUG_ON(i915_active_is_idle(ref)); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci parent = NULL; 30262306a36Sopenharmony_ci p = &ref->tree.rb_node; 30362306a36Sopenharmony_ci while (*p) { 30462306a36Sopenharmony_ci parent = *p; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci node = rb_entry(parent, struct active_node, node); 30762306a36Sopenharmony_ci if (node->timeline == idx) 30862306a36Sopenharmony_ci goto out; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (node->timeline < idx) 31162306a36Sopenharmony_ci p = &parent->rb_right; 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci p = &parent->rb_left; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * XXX: We should preallocate this before i915_active_ref() is ever 31862306a36Sopenharmony_ci * called, but we cannot call into fs_reclaim() anyway, so use GFP_ATOMIC. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci node = kmem_cache_alloc(slab_cache, GFP_ATOMIC); 32162306a36Sopenharmony_ci if (!node) 32262306a36Sopenharmony_ci goto out; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci __i915_active_fence_init(&node->base, NULL, node_retire); 32562306a36Sopenharmony_ci node->ref = ref; 32662306a36Sopenharmony_ci node->timeline = idx; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci rb_link_node(&node->node, parent, p); 32962306a36Sopenharmony_ci rb_insert_color(&node->node, &ref->tree); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ciout: 33262306a36Sopenharmony_ci WRITE_ONCE(ref->cache, node); 33362306a36Sopenharmony_ci spin_unlock_irq(&ref->tree_lock); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return &node->base; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_civoid __i915_active_init(struct i915_active *ref, 33962306a36Sopenharmony_ci int (*active)(struct i915_active *ref), 34062306a36Sopenharmony_ci void (*retire)(struct i915_active *ref), 34162306a36Sopenharmony_ci unsigned long flags, 34262306a36Sopenharmony_ci struct lock_class_key *mkey, 34362306a36Sopenharmony_ci struct lock_class_key *wkey) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci debug_active_init(ref); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ref->flags = flags; 34862306a36Sopenharmony_ci ref->active = active; 34962306a36Sopenharmony_ci ref->retire = retire; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci spin_lock_init(&ref->tree_lock); 35262306a36Sopenharmony_ci ref->tree = RB_ROOT; 35362306a36Sopenharmony_ci ref->cache = NULL; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci init_llist_head(&ref->preallocated_barriers); 35662306a36Sopenharmony_ci atomic_set(&ref->count, 0); 35762306a36Sopenharmony_ci __mutex_init(&ref->mutex, "i915_active", mkey); 35862306a36Sopenharmony_ci __i915_active_fence_init(&ref->excl, NULL, excl_retire); 35962306a36Sopenharmony_ci INIT_WORK(&ref->work, active_work); 36062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_LOCKDEP) 36162306a36Sopenharmony_ci lockdep_init_map(&ref->work.lockdep_map, "i915_active.work", wkey, 0); 36262306a36Sopenharmony_ci#endif 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic bool ____active_del_barrier(struct i915_active *ref, 36662306a36Sopenharmony_ci struct active_node *node, 36762306a36Sopenharmony_ci struct intel_engine_cs *engine) 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct llist_node *head = NULL, *tail = NULL; 37162306a36Sopenharmony_ci struct llist_node *pos, *next; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci GEM_BUG_ON(node->timeline != engine->kernel_context->timeline->fence_context); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * Rebuild the llist excluding our node. We may perform this 37762306a36Sopenharmony_ci * outside of the kernel_context timeline mutex and so someone 37862306a36Sopenharmony_ci * else may be manipulating the engine->barrier_tasks, in 37962306a36Sopenharmony_ci * which case either we or they will be upset :) 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * A second __active_del_barrier() will report failure to claim 38262306a36Sopenharmony_ci * the active_node and the caller will just shrug and know not to 38362306a36Sopenharmony_ci * claim ownership of its node. 38462306a36Sopenharmony_ci * 38562306a36Sopenharmony_ci * A concurrent i915_request_add_active_barriers() will miss adding 38662306a36Sopenharmony_ci * any of the tasks, but we will try again on the next -- and since 38762306a36Sopenharmony_ci * we are actively using the barrier, we know that there will be 38862306a36Sopenharmony_ci * at least another opportunity when we idle. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci llist_for_each_safe(pos, next, llist_del_all(&engine->barrier_tasks)) { 39162306a36Sopenharmony_ci if (node == barrier_from_ll(pos)) { 39262306a36Sopenharmony_ci node = NULL; 39362306a36Sopenharmony_ci continue; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci pos->next = head; 39762306a36Sopenharmony_ci head = pos; 39862306a36Sopenharmony_ci if (!tail) 39962306a36Sopenharmony_ci tail = pos; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci if (head) 40262306a36Sopenharmony_ci llist_add_batch(head, tail, &engine->barrier_tasks); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return !node; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic bool 40862306a36Sopenharmony_ci__active_del_barrier(struct i915_active *ref, struct active_node *node) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci return ____active_del_barrier(ref, node, barrier_to_engine(node)); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic bool 41462306a36Sopenharmony_cireplace_barrier(struct i915_active *ref, struct i915_active_fence *active) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci if (!is_barrier(active)) /* proto-node used by our idle barrier? */ 41762306a36Sopenharmony_ci return false; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * This request is on the kernel_context timeline, and so 42162306a36Sopenharmony_ci * we can use it to substitute for the pending idle-barrer 42262306a36Sopenharmony_ci * request that we want to emit on the kernel_context. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci return __active_del_barrier(ref, node_from_active(active)); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ciint i915_active_add_request(struct i915_active *ref, struct i915_request *rq) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci u64 idx = i915_request_timeline(rq)->fence_context; 43062306a36Sopenharmony_ci struct dma_fence *fence = &rq->fence; 43162306a36Sopenharmony_ci struct i915_active_fence *active; 43262306a36Sopenharmony_ci int err; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Prevent reaping in case we malloc/wait while building the tree */ 43562306a36Sopenharmony_ci err = i915_active_acquire(ref); 43662306a36Sopenharmony_ci if (err) 43762306a36Sopenharmony_ci return err; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci do { 44062306a36Sopenharmony_ci active = active_instance(ref, idx); 44162306a36Sopenharmony_ci if (!active) { 44262306a36Sopenharmony_ci err = -ENOMEM; 44362306a36Sopenharmony_ci goto out; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (replace_barrier(ref, active)) { 44762306a36Sopenharmony_ci RCU_INIT_POINTER(active->fence, NULL); 44862306a36Sopenharmony_ci atomic_dec(&ref->count); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci } while (unlikely(is_barrier(active))); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci fence = __i915_active_fence_set(active, fence); 45362306a36Sopenharmony_ci if (!fence) 45462306a36Sopenharmony_ci __i915_active_acquire(ref); 45562306a36Sopenharmony_ci else 45662306a36Sopenharmony_ci dma_fence_put(fence); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ciout: 45962306a36Sopenharmony_ci i915_active_release(ref); 46062306a36Sopenharmony_ci return err; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic struct dma_fence * 46462306a36Sopenharmony_ci__i915_active_set_fence(struct i915_active *ref, 46562306a36Sopenharmony_ci struct i915_active_fence *active, 46662306a36Sopenharmony_ci struct dma_fence *fence) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct dma_fence *prev; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (replace_barrier(ref, active)) { 47162306a36Sopenharmony_ci RCU_INIT_POINTER(active->fence, fence); 47262306a36Sopenharmony_ci return NULL; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci prev = __i915_active_fence_set(active, fence); 47662306a36Sopenharmony_ci if (!prev) 47762306a36Sopenharmony_ci __i915_active_acquire(ref); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return prev; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistruct dma_fence * 48362306a36Sopenharmony_cii915_active_set_exclusive(struct i915_active *ref, struct dma_fence *f) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci /* We expect the caller to manage the exclusive timeline ordering */ 48662306a36Sopenharmony_ci return __i915_active_set_fence(ref, &ref->excl, f); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cibool i915_active_acquire_if_busy(struct i915_active *ref) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci debug_active_assert(ref); 49262306a36Sopenharmony_ci return atomic_add_unless(&ref->count, 1, 0); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void __i915_active_activate(struct i915_active *ref) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci spin_lock_irq(&ref->tree_lock); /* __active_retire() */ 49862306a36Sopenharmony_ci if (!atomic_fetch_inc(&ref->count)) 49962306a36Sopenharmony_ci debug_active_activate(ref); 50062306a36Sopenharmony_ci spin_unlock_irq(&ref->tree_lock); 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ciint i915_active_acquire(struct i915_active *ref) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci int err; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (i915_active_acquire_if_busy(ref)) 50862306a36Sopenharmony_ci return 0; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (!ref->active) { 51162306a36Sopenharmony_ci __i915_active_activate(ref); 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci err = mutex_lock_interruptible(&ref->mutex); 51662306a36Sopenharmony_ci if (err) 51762306a36Sopenharmony_ci return err; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (likely(!i915_active_acquire_if_busy(ref))) { 52062306a36Sopenharmony_ci err = ref->active(ref); 52162306a36Sopenharmony_ci if (!err) 52262306a36Sopenharmony_ci __i915_active_activate(ref); 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci mutex_unlock(&ref->mutex); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return err; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ciint i915_active_acquire_for_context(struct i915_active *ref, u64 idx) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct i915_active_fence *active; 53362306a36Sopenharmony_ci int err; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci err = i915_active_acquire(ref); 53662306a36Sopenharmony_ci if (err) 53762306a36Sopenharmony_ci return err; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci active = active_instance(ref, idx); 54062306a36Sopenharmony_ci if (!active) { 54162306a36Sopenharmony_ci i915_active_release(ref); 54262306a36Sopenharmony_ci return -ENOMEM; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return 0; /* return with active ref */ 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_civoid i915_active_release(struct i915_active *ref) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci debug_active_assert(ref); 55162306a36Sopenharmony_ci active_retire(ref); 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void enable_signaling(struct i915_active_fence *active) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct dma_fence *fence; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (unlikely(is_barrier(active))) 55962306a36Sopenharmony_ci return; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci fence = i915_active_fence_get(active); 56262306a36Sopenharmony_ci if (!fence) 56362306a36Sopenharmony_ci return; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci dma_fence_enable_sw_signaling(fence); 56662306a36Sopenharmony_ci dma_fence_put(fence); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic int flush_barrier(struct active_node *it) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct intel_engine_cs *engine; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (likely(!is_barrier(&it->base))) 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci engine = __barrier_to_engine(it); 57762306a36Sopenharmony_ci smp_rmb(); /* serialise with add_active_barriers */ 57862306a36Sopenharmony_ci if (!is_barrier(&it->base)) 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return intel_engine_flush_barriers(engine); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int flush_lazy_signals(struct i915_active *ref) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct active_node *it, *n; 58762306a36Sopenharmony_ci int err = 0; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci enable_signaling(&ref->excl); 59062306a36Sopenharmony_ci rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node) { 59162306a36Sopenharmony_ci err = flush_barrier(it); /* unconnected idle barrier? */ 59262306a36Sopenharmony_ci if (err) 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci enable_signaling(&it->base); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return err; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ciint __i915_active_wait(struct i915_active *ref, int state) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci might_sleep(); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* Any fence added after the wait begins will not be auto-signaled */ 60662306a36Sopenharmony_ci if (i915_active_acquire_if_busy(ref)) { 60762306a36Sopenharmony_ci int err; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci err = flush_lazy_signals(ref); 61062306a36Sopenharmony_ci i915_active_release(ref); 61162306a36Sopenharmony_ci if (err) 61262306a36Sopenharmony_ci return err; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (___wait_var_event(ref, i915_active_is_idle(ref), 61562306a36Sopenharmony_ci state, 0, 0, schedule())) 61662306a36Sopenharmony_ci return -EINTR; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* 62062306a36Sopenharmony_ci * After the wait is complete, the caller may free the active. 62162306a36Sopenharmony_ci * We have to flush any concurrent retirement before returning. 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci flush_work(&ref->work); 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic int __await_active(struct i915_active_fence *active, 62862306a36Sopenharmony_ci int (*fn)(void *arg, struct dma_fence *fence), 62962306a36Sopenharmony_ci void *arg) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct dma_fence *fence; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (is_barrier(active)) /* XXX flush the barrier? */ 63462306a36Sopenharmony_ci return 0; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci fence = i915_active_fence_get(active); 63762306a36Sopenharmony_ci if (fence) { 63862306a36Sopenharmony_ci int err; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci err = fn(arg, fence); 64162306a36Sopenharmony_ci dma_fence_put(fence); 64262306a36Sopenharmony_ci if (err < 0) 64362306a36Sopenharmony_ci return err; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return 0; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistruct wait_barrier { 65062306a36Sopenharmony_ci struct wait_queue_entry base; 65162306a36Sopenharmony_ci struct i915_active *ref; 65262306a36Sopenharmony_ci}; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic int 65562306a36Sopenharmony_cibarrier_wake(wait_queue_entry_t *wq, unsigned int mode, int flags, void *key) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci struct wait_barrier *wb = container_of(wq, typeof(*wb), base); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (i915_active_is_idle(wb->ref)) { 66062306a36Sopenharmony_ci list_del(&wq->entry); 66162306a36Sopenharmony_ci i915_sw_fence_complete(wq->private); 66262306a36Sopenharmony_ci kfree(wq); 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int __await_barrier(struct i915_active *ref, struct i915_sw_fence *fence) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct wait_barrier *wb; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci wb = kmalloc(sizeof(*wb), GFP_KERNEL); 67362306a36Sopenharmony_ci if (unlikely(!wb)) 67462306a36Sopenharmony_ci return -ENOMEM; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci GEM_BUG_ON(i915_active_is_idle(ref)); 67762306a36Sopenharmony_ci if (!i915_sw_fence_await(fence)) { 67862306a36Sopenharmony_ci kfree(wb); 67962306a36Sopenharmony_ci return -EINVAL; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci wb->base.flags = 0; 68362306a36Sopenharmony_ci wb->base.func = barrier_wake; 68462306a36Sopenharmony_ci wb->base.private = fence; 68562306a36Sopenharmony_ci wb->ref = ref; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci add_wait_queue(__var_waitqueue(ref), &wb->base); 68862306a36Sopenharmony_ci return 0; 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic int await_active(struct i915_active *ref, 69262306a36Sopenharmony_ci unsigned int flags, 69362306a36Sopenharmony_ci int (*fn)(void *arg, struct dma_fence *fence), 69462306a36Sopenharmony_ci void *arg, struct i915_sw_fence *barrier) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci int err = 0; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (!i915_active_acquire_if_busy(ref)) 69962306a36Sopenharmony_ci return 0; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (flags & I915_ACTIVE_AWAIT_EXCL && 70262306a36Sopenharmony_ci rcu_access_pointer(ref->excl.fence)) { 70362306a36Sopenharmony_ci err = __await_active(&ref->excl, fn, arg); 70462306a36Sopenharmony_ci if (err) 70562306a36Sopenharmony_ci goto out; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (flags & I915_ACTIVE_AWAIT_ACTIVE) { 70962306a36Sopenharmony_ci struct active_node *it, *n; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node) { 71262306a36Sopenharmony_ci err = __await_active(&it->base, fn, arg); 71362306a36Sopenharmony_ci if (err) 71462306a36Sopenharmony_ci goto out; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (flags & I915_ACTIVE_AWAIT_BARRIER) { 71962306a36Sopenharmony_ci err = flush_lazy_signals(ref); 72062306a36Sopenharmony_ci if (err) 72162306a36Sopenharmony_ci goto out; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci err = __await_barrier(ref, barrier); 72462306a36Sopenharmony_ci if (err) 72562306a36Sopenharmony_ci goto out; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ciout: 72962306a36Sopenharmony_ci i915_active_release(ref); 73062306a36Sopenharmony_ci return err; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int rq_await_fence(void *arg, struct dma_fence *fence) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci return i915_request_await_dma_fence(arg, fence); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ciint i915_request_await_active(struct i915_request *rq, 73962306a36Sopenharmony_ci struct i915_active *ref, 74062306a36Sopenharmony_ci unsigned int flags) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci return await_active(ref, flags, rq_await_fence, rq, &rq->submit); 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int sw_await_fence(void *arg, struct dma_fence *fence) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci return i915_sw_fence_await_dma_fence(arg, fence, 0, 74862306a36Sopenharmony_ci GFP_NOWAIT | __GFP_NOWARN); 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ciint i915_sw_fence_await_active(struct i915_sw_fence *fence, 75262306a36Sopenharmony_ci struct i915_active *ref, 75362306a36Sopenharmony_ci unsigned int flags) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci return await_active(ref, flags, sw_await_fence, fence, fence); 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_civoid i915_active_fini(struct i915_active *ref) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci debug_active_fini(ref); 76162306a36Sopenharmony_ci GEM_BUG_ON(atomic_read(&ref->count)); 76262306a36Sopenharmony_ci GEM_BUG_ON(work_pending(&ref->work)); 76362306a36Sopenharmony_ci mutex_destroy(&ref->mutex); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (ref->cache) 76662306a36Sopenharmony_ci kmem_cache_free(slab_cache, ref->cache); 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic inline bool is_idle_barrier(struct active_node *node, u64 idx) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci return node->timeline == idx && !i915_active_fence_isset(&node->base); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic struct active_node *reuse_idle_barrier(struct i915_active *ref, u64 idx) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct rb_node *prev, *p; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (RB_EMPTY_ROOT(&ref->tree)) 77962306a36Sopenharmony_ci return NULL; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci GEM_BUG_ON(i915_active_is_idle(ref)); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* 78462306a36Sopenharmony_ci * Try to reuse any existing barrier nodes already allocated for this 78562306a36Sopenharmony_ci * i915_active, due to overlapping active phases there is likely a 78662306a36Sopenharmony_ci * node kept alive (as we reuse before parking). We prefer to reuse 78762306a36Sopenharmony_ci * completely idle barriers (less hassle in manipulating the llists), 78862306a36Sopenharmony_ci * but otherwise any will do. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci if (ref->cache && is_idle_barrier(ref->cache, idx)) { 79162306a36Sopenharmony_ci p = &ref->cache->node; 79262306a36Sopenharmony_ci goto match; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci prev = NULL; 79662306a36Sopenharmony_ci p = ref->tree.rb_node; 79762306a36Sopenharmony_ci while (p) { 79862306a36Sopenharmony_ci struct active_node *node = 79962306a36Sopenharmony_ci rb_entry(p, struct active_node, node); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (is_idle_barrier(node, idx)) 80262306a36Sopenharmony_ci goto match; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci prev = p; 80562306a36Sopenharmony_ci if (node->timeline < idx) 80662306a36Sopenharmony_ci p = READ_ONCE(p->rb_right); 80762306a36Sopenharmony_ci else 80862306a36Sopenharmony_ci p = READ_ONCE(p->rb_left); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* 81262306a36Sopenharmony_ci * No quick match, but we did find the leftmost rb_node for the 81362306a36Sopenharmony_ci * kernel_context. Walk the rb_tree in-order to see if there were 81462306a36Sopenharmony_ci * any idle-barriers on this timeline that we missed, or just use 81562306a36Sopenharmony_ci * the first pending barrier. 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci for (p = prev; p; p = rb_next(p)) { 81862306a36Sopenharmony_ci struct active_node *node = 81962306a36Sopenharmony_ci rb_entry(p, struct active_node, node); 82062306a36Sopenharmony_ci struct intel_engine_cs *engine; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (node->timeline > idx) 82362306a36Sopenharmony_ci break; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (node->timeline < idx) 82662306a36Sopenharmony_ci continue; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (is_idle_barrier(node, idx)) 82962306a36Sopenharmony_ci goto match; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* 83262306a36Sopenharmony_ci * The list of pending barriers is protected by the 83362306a36Sopenharmony_ci * kernel_context timeline, which notably we do not hold 83462306a36Sopenharmony_ci * here. i915_request_add_active_barriers() may consume 83562306a36Sopenharmony_ci * the barrier before we claim it, so we have to check 83662306a36Sopenharmony_ci * for success. 83762306a36Sopenharmony_ci */ 83862306a36Sopenharmony_ci engine = __barrier_to_engine(node); 83962306a36Sopenharmony_ci smp_rmb(); /* serialise with add_active_barriers */ 84062306a36Sopenharmony_ci if (is_barrier(&node->base) && 84162306a36Sopenharmony_ci ____active_del_barrier(ref, node, engine)) 84262306a36Sopenharmony_ci goto match; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return NULL; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cimatch: 84862306a36Sopenharmony_ci spin_lock_irq(&ref->tree_lock); 84962306a36Sopenharmony_ci rb_erase(p, &ref->tree); /* Hide from waits and sibling allocations */ 85062306a36Sopenharmony_ci if (p == &ref->cache->node) 85162306a36Sopenharmony_ci WRITE_ONCE(ref->cache, NULL); 85262306a36Sopenharmony_ci spin_unlock_irq(&ref->tree_lock); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci return rb_entry(p, struct active_node, node); 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ciint i915_active_acquire_preallocate_barrier(struct i915_active *ref, 85862306a36Sopenharmony_ci struct intel_engine_cs *engine) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci intel_engine_mask_t tmp, mask = engine->mask; 86162306a36Sopenharmony_ci struct llist_node *first = NULL, *last = NULL; 86262306a36Sopenharmony_ci struct intel_gt *gt = engine->gt; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci GEM_BUG_ON(i915_active_is_idle(ref)); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* Wait until the previous preallocation is completed */ 86762306a36Sopenharmony_ci while (!llist_empty(&ref->preallocated_barriers)) 86862306a36Sopenharmony_ci cond_resched(); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* 87162306a36Sopenharmony_ci * Preallocate a node for each physical engine supporting the target 87262306a36Sopenharmony_ci * engine (remember virtual engines have more than one sibling). 87362306a36Sopenharmony_ci * We can then use the preallocated nodes in 87462306a36Sopenharmony_ci * i915_active_acquire_barrier() 87562306a36Sopenharmony_ci */ 87662306a36Sopenharmony_ci GEM_BUG_ON(!mask); 87762306a36Sopenharmony_ci for_each_engine_masked(engine, gt, mask, tmp) { 87862306a36Sopenharmony_ci u64 idx = engine->kernel_context->timeline->fence_context; 87962306a36Sopenharmony_ci struct llist_node *prev = first; 88062306a36Sopenharmony_ci struct active_node *node; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci rcu_read_lock(); 88362306a36Sopenharmony_ci node = reuse_idle_barrier(ref, idx); 88462306a36Sopenharmony_ci rcu_read_unlock(); 88562306a36Sopenharmony_ci if (!node) { 88662306a36Sopenharmony_ci node = kmem_cache_alloc(slab_cache, GFP_KERNEL); 88762306a36Sopenharmony_ci if (!node) 88862306a36Sopenharmony_ci goto unwind; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci RCU_INIT_POINTER(node->base.fence, NULL); 89162306a36Sopenharmony_ci node->base.cb.func = node_retire; 89262306a36Sopenharmony_ci node->timeline = idx; 89362306a36Sopenharmony_ci node->ref = ref; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (!i915_active_fence_isset(&node->base)) { 89762306a36Sopenharmony_ci /* 89862306a36Sopenharmony_ci * Mark this as being *our* unconnected proto-node. 89962306a36Sopenharmony_ci * 90062306a36Sopenharmony_ci * Since this node is not in any list, and we have 90162306a36Sopenharmony_ci * decoupled it from the rbtree, we can reuse the 90262306a36Sopenharmony_ci * request to indicate this is an idle-barrier node 90362306a36Sopenharmony_ci * and then we can use the rb_node and list pointers 90462306a36Sopenharmony_ci * for our tracking of the pending barrier. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_ci RCU_INIT_POINTER(node->base.fence, ERR_PTR(-EAGAIN)); 90762306a36Sopenharmony_ci node->base.cb.node.prev = (void *)engine; 90862306a36Sopenharmony_ci __i915_active_acquire(ref); 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci GEM_BUG_ON(rcu_access_pointer(node->base.fence) != ERR_PTR(-EAGAIN)); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci GEM_BUG_ON(barrier_to_engine(node) != engine); 91362306a36Sopenharmony_ci first = barrier_to_ll(node); 91462306a36Sopenharmony_ci first->next = prev; 91562306a36Sopenharmony_ci if (!last) 91662306a36Sopenharmony_ci last = first; 91762306a36Sopenharmony_ci intel_engine_pm_get(engine); 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci GEM_BUG_ON(!llist_empty(&ref->preallocated_barriers)); 92162306a36Sopenharmony_ci llist_add_batch(first, last, &ref->preallocated_barriers); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci return 0; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ciunwind: 92662306a36Sopenharmony_ci while (first) { 92762306a36Sopenharmony_ci struct active_node *node = barrier_from_ll(first); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci first = first->next; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci atomic_dec(&ref->count); 93262306a36Sopenharmony_ci intel_engine_pm_put(barrier_to_engine(node)); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci kmem_cache_free(slab_cache, node); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci return -ENOMEM; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_civoid i915_active_acquire_barrier(struct i915_active *ref) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct llist_node *pos, *next; 94262306a36Sopenharmony_ci unsigned long flags; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci GEM_BUG_ON(i915_active_is_idle(ref)); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* 94762306a36Sopenharmony_ci * Transfer the list of preallocated barriers into the 94862306a36Sopenharmony_ci * i915_active rbtree, but only as proto-nodes. They will be 94962306a36Sopenharmony_ci * populated by i915_request_add_active_barriers() to point to the 95062306a36Sopenharmony_ci * request that will eventually release them. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_ci llist_for_each_safe(pos, next, take_preallocated_barriers(ref)) { 95362306a36Sopenharmony_ci struct active_node *node = barrier_from_ll(pos); 95462306a36Sopenharmony_ci struct intel_engine_cs *engine = barrier_to_engine(node); 95562306a36Sopenharmony_ci struct rb_node **p, *parent; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci spin_lock_irqsave_nested(&ref->tree_lock, flags, 95862306a36Sopenharmony_ci SINGLE_DEPTH_NESTING); 95962306a36Sopenharmony_ci parent = NULL; 96062306a36Sopenharmony_ci p = &ref->tree.rb_node; 96162306a36Sopenharmony_ci while (*p) { 96262306a36Sopenharmony_ci struct active_node *it; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci parent = *p; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci it = rb_entry(parent, struct active_node, node); 96762306a36Sopenharmony_ci if (it->timeline < node->timeline) 96862306a36Sopenharmony_ci p = &parent->rb_right; 96962306a36Sopenharmony_ci else 97062306a36Sopenharmony_ci p = &parent->rb_left; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci rb_link_node(&node->node, parent, p); 97362306a36Sopenharmony_ci rb_insert_color(&node->node, &ref->tree); 97462306a36Sopenharmony_ci spin_unlock_irqrestore(&ref->tree_lock, flags); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci GEM_BUG_ON(!intel_engine_pm_is_awake(engine)); 97762306a36Sopenharmony_ci llist_add(barrier_to_ll(node), &engine->barrier_tasks); 97862306a36Sopenharmony_ci intel_engine_pm_put_delay(engine, 2); 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic struct dma_fence **ll_to_fence_slot(struct llist_node *node) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci return __active_fence_slot(&barrier_from_ll(node)->base); 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_civoid i915_request_add_active_barriers(struct i915_request *rq) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci struct intel_engine_cs *engine = rq->engine; 99062306a36Sopenharmony_ci struct llist_node *node, *next; 99162306a36Sopenharmony_ci unsigned long flags; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci GEM_BUG_ON(!intel_context_is_barrier(rq->context)); 99462306a36Sopenharmony_ci GEM_BUG_ON(intel_engine_is_virtual(engine)); 99562306a36Sopenharmony_ci GEM_BUG_ON(i915_request_timeline(rq) != engine->kernel_context->timeline); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci node = llist_del_all(&engine->barrier_tasks); 99862306a36Sopenharmony_ci if (!node) 99962306a36Sopenharmony_ci return; 100062306a36Sopenharmony_ci /* 100162306a36Sopenharmony_ci * Attach the list of proto-fences to the in-flight request such 100262306a36Sopenharmony_ci * that the parent i915_active will be released when this request 100362306a36Sopenharmony_ci * is retired. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_ci spin_lock_irqsave(&rq->lock, flags); 100662306a36Sopenharmony_ci llist_for_each_safe(node, next, node) { 100762306a36Sopenharmony_ci /* serialise with reuse_idle_barrier */ 100862306a36Sopenharmony_ci smp_store_mb(*ll_to_fence_slot(node), &rq->fence); 100962306a36Sopenharmony_ci list_add_tail((struct list_head *)node, &rq->fence.cb_list); 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci spin_unlock_irqrestore(&rq->lock, flags); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci/* 101562306a36Sopenharmony_ci * __i915_active_fence_set: Update the last active fence along its timeline 101662306a36Sopenharmony_ci * @active: the active tracker 101762306a36Sopenharmony_ci * @fence: the new fence (under construction) 101862306a36Sopenharmony_ci * 101962306a36Sopenharmony_ci * Records the new @fence as the last active fence along its timeline in 102062306a36Sopenharmony_ci * this active tracker, moving the tracking callbacks from the previous 102162306a36Sopenharmony_ci * fence onto this one. Gets and returns a reference to the previous fence 102262306a36Sopenharmony_ci * (if not already completed), which the caller must put after making sure 102362306a36Sopenharmony_ci * that it is executed before the new fence. To ensure that the order of 102462306a36Sopenharmony_ci * fences within the timeline of the i915_active_fence is understood, it 102562306a36Sopenharmony_ci * should be locked by the caller. 102662306a36Sopenharmony_ci */ 102762306a36Sopenharmony_cistruct dma_fence * 102862306a36Sopenharmony_ci__i915_active_fence_set(struct i915_active_fence *active, 102962306a36Sopenharmony_ci struct dma_fence *fence) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct dma_fence *prev; 103262306a36Sopenharmony_ci unsigned long flags; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* 103562306a36Sopenharmony_ci * In case of fences embedded in i915_requests, their memory is 103662306a36Sopenharmony_ci * SLAB_FAILSAFE_BY_RCU, then it can be reused right after release 103762306a36Sopenharmony_ci * by new requests. Then, there is a risk of passing back a pointer 103862306a36Sopenharmony_ci * to a new, completely unrelated fence that reuses the same memory 103962306a36Sopenharmony_ci * while tracked under a different active tracker. Combined with i915 104062306a36Sopenharmony_ci * perf open/close operations that build await dependencies between 104162306a36Sopenharmony_ci * engine kernel context requests and user requests from different 104262306a36Sopenharmony_ci * timelines, this can lead to dependency loops and infinite waits. 104362306a36Sopenharmony_ci * 104462306a36Sopenharmony_ci * As a countermeasure, we try to get a reference to the active->fence 104562306a36Sopenharmony_ci * first, so if we succeed and pass it back to our user then it is not 104662306a36Sopenharmony_ci * released and potentially reused by an unrelated request before the 104762306a36Sopenharmony_ci * user has a chance to set up an await dependency on it. 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_ci prev = i915_active_fence_get(active); 105062306a36Sopenharmony_ci if (fence == prev) 105162306a36Sopenharmony_ci return fence; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* 105662306a36Sopenharmony_ci * Consider that we have two threads arriving (A and B), with 105762306a36Sopenharmony_ci * C already resident as the active->fence. 105862306a36Sopenharmony_ci * 105962306a36Sopenharmony_ci * Both A and B have got a reference to C or NULL, depending on the 106062306a36Sopenharmony_ci * timing of the interrupt handler. Let's assume that if A has got C 106162306a36Sopenharmony_ci * then it has locked C first (before B). 106262306a36Sopenharmony_ci * 106362306a36Sopenharmony_ci * Note the strong ordering of the timeline also provides consistent 106462306a36Sopenharmony_ci * nesting rules for the fence->lock; the inner lock is always the 106562306a36Sopenharmony_ci * older lock. 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_ci spin_lock_irqsave(fence->lock, flags); 106862306a36Sopenharmony_ci if (prev) 106962306a36Sopenharmony_ci spin_lock_nested(prev->lock, SINGLE_DEPTH_NESTING); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* 107262306a36Sopenharmony_ci * A does the cmpxchg first, and so it sees C or NULL, as before, or 107362306a36Sopenharmony_ci * something else, depending on the timing of other threads and/or 107462306a36Sopenharmony_ci * interrupt handler. If not the same as before then A unlocks C if 107562306a36Sopenharmony_ci * applicable and retries, starting from an attempt to get a new 107662306a36Sopenharmony_ci * active->fence. Meanwhile, B follows the same path as A. 107762306a36Sopenharmony_ci * Once A succeeds with cmpxch, B fails again, retires, gets A from 107862306a36Sopenharmony_ci * active->fence, locks it as soon as A completes, and possibly 107962306a36Sopenharmony_ci * succeeds with cmpxchg. 108062306a36Sopenharmony_ci */ 108162306a36Sopenharmony_ci while (cmpxchg(__active_fence_slot(active), prev, fence) != prev) { 108262306a36Sopenharmony_ci if (prev) { 108362306a36Sopenharmony_ci spin_unlock(prev->lock); 108462306a36Sopenharmony_ci dma_fence_put(prev); 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci spin_unlock_irqrestore(fence->lock, flags); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci prev = i915_active_fence_get(active); 108962306a36Sopenharmony_ci GEM_BUG_ON(prev == fence); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci spin_lock_irqsave(fence->lock, flags); 109262306a36Sopenharmony_ci if (prev) 109362306a36Sopenharmony_ci spin_lock_nested(prev->lock, SINGLE_DEPTH_NESTING); 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* 109762306a36Sopenharmony_ci * If prev is NULL then the previous fence must have been signaled 109862306a36Sopenharmony_ci * and we know that we are first on the timeline. If it is still 109962306a36Sopenharmony_ci * present then, having the lock on that fence already acquired, we 110062306a36Sopenharmony_ci * serialise with the interrupt handler, in the process of removing it 110162306a36Sopenharmony_ci * from any future interrupt callback. A will then wait on C before 110262306a36Sopenharmony_ci * executing (if present). 110362306a36Sopenharmony_ci * 110462306a36Sopenharmony_ci * As B is second, it sees A as the previous fence and so waits for 110562306a36Sopenharmony_ci * it to complete its transition and takes over the occupancy for 110662306a36Sopenharmony_ci * itself -- remembering that it needs to wait on A before executing. 110762306a36Sopenharmony_ci */ 110862306a36Sopenharmony_ci if (prev) { 110962306a36Sopenharmony_ci __list_del_entry(&active->cb.node); 111062306a36Sopenharmony_ci spin_unlock(prev->lock); /* serialise with prev->cb_list */ 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci list_add_tail(&active->cb.node, &fence->cb_list); 111362306a36Sopenharmony_ci spin_unlock_irqrestore(fence->lock, flags); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci return prev; 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ciint i915_active_fence_set(struct i915_active_fence *active, 111962306a36Sopenharmony_ci struct i915_request *rq) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci struct dma_fence *fence; 112262306a36Sopenharmony_ci int err = 0; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci /* Must maintain timeline ordering wrt previous active requests */ 112562306a36Sopenharmony_ci fence = __i915_active_fence_set(active, &rq->fence); 112662306a36Sopenharmony_ci if (fence) { 112762306a36Sopenharmony_ci err = i915_request_await_dma_fence(rq, fence); 112862306a36Sopenharmony_ci dma_fence_put(fence); 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci return err; 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_civoid i915_active_noop(struct dma_fence *fence, struct dma_fence_cb *cb) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci active_fence_cb(fence, cb); 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistruct auto_active { 114062306a36Sopenharmony_ci struct i915_active base; 114162306a36Sopenharmony_ci struct kref ref; 114262306a36Sopenharmony_ci}; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistruct i915_active *i915_active_get(struct i915_active *ref) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci struct auto_active *aa = container_of(ref, typeof(*aa), base); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci kref_get(&aa->ref); 114962306a36Sopenharmony_ci return &aa->base; 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cistatic void auto_release(struct kref *ref) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct auto_active *aa = container_of(ref, typeof(*aa), ref); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci i915_active_fini(&aa->base); 115762306a36Sopenharmony_ci kfree(aa); 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_civoid i915_active_put(struct i915_active *ref) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci struct auto_active *aa = container_of(ref, typeof(*aa), base); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci kref_put(&aa->ref, auto_release); 116562306a36Sopenharmony_ci} 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_cistatic int auto_active(struct i915_active *ref) 116862306a36Sopenharmony_ci{ 116962306a36Sopenharmony_ci i915_active_get(ref); 117062306a36Sopenharmony_ci return 0; 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_cistatic void auto_retire(struct i915_active *ref) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci i915_active_put(ref); 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistruct i915_active *i915_active_create(void) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci struct auto_active *aa; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci aa = kmalloc(sizeof(*aa), GFP_KERNEL); 118362306a36Sopenharmony_ci if (!aa) 118462306a36Sopenharmony_ci return NULL; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci kref_init(&aa->ref); 118762306a36Sopenharmony_ci i915_active_init(&aa->base, auto_active, auto_retire, 0); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return &aa->base; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 119362306a36Sopenharmony_ci#include "selftests/i915_active.c" 119462306a36Sopenharmony_ci#endif 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_civoid i915_active_module_exit(void) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci kmem_cache_destroy(slab_cache); 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ciint __init i915_active_module_init(void) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci slab_cache = KMEM_CACHE(active_node, SLAB_HWCACHE_ALIGN); 120462306a36Sopenharmony_ci if (!slab_cache) 120562306a36Sopenharmony_ci return -ENOMEM; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci return 0; 120862306a36Sopenharmony_ci} 1209