162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2015-2021 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/kthread.h> 762306a36Sopenharmony_ci#include <linux/string_helpers.h> 862306a36Sopenharmony_ci#include <trace/events/dma_fence.h> 962306a36Sopenharmony_ci#include <uapi/linux/sched/types.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "i915_drv.h" 1262306a36Sopenharmony_ci#include "i915_trace.h" 1362306a36Sopenharmony_ci#include "intel_breadcrumbs.h" 1462306a36Sopenharmony_ci#include "intel_context.h" 1562306a36Sopenharmony_ci#include "intel_engine_pm.h" 1662306a36Sopenharmony_ci#include "intel_gt_pm.h" 1762306a36Sopenharmony_ci#include "intel_gt_requests.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic bool irq_enable(struct intel_breadcrumbs *b) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci return intel_engine_irq_enable(b->irq_engine); 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic void irq_disable(struct intel_breadcrumbs *b) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci intel_engine_irq_disable(b->irq_engine); 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci /* 3262306a36Sopenharmony_ci * Since we are waiting on a request, the GPU should be busy 3362306a36Sopenharmony_ci * and should have its own rpm reference. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci if (GEM_WARN_ON(!intel_gt_pm_get_if_awake(b->irq_engine->gt))) 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* 3962306a36Sopenharmony_ci * The breadcrumb irq will be disarmed on the interrupt after the 4062306a36Sopenharmony_ci * waiters are signaled. This gives us a single interrupt window in 4162306a36Sopenharmony_ci * which we can add a new waiter and avoid the cost of re-enabling 4262306a36Sopenharmony_ci * the irq. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci WRITE_ONCE(b->irq_armed, true); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* Requests may have completed before we could enable the interrupt. */ 4762306a36Sopenharmony_ci if (!b->irq_enabled++ && b->irq_enable(b)) 4862306a36Sopenharmony_ci irq_work_queue(&b->irq_work); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci if (!b->irq_engine) 5462306a36Sopenharmony_ci return; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci spin_lock(&b->irq_lock); 5762306a36Sopenharmony_ci if (!b->irq_armed) 5862306a36Sopenharmony_ci __intel_breadcrumbs_arm_irq(b); 5962306a36Sopenharmony_ci spin_unlock(&b->irq_lock); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci GEM_BUG_ON(!b->irq_enabled); 6562306a36Sopenharmony_ci if (!--b->irq_enabled) 6662306a36Sopenharmony_ci b->irq_disable(b); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci WRITE_ONCE(b->irq_armed, false); 6962306a36Sopenharmony_ci intel_gt_pm_put_async(b->irq_engine->gt); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci spin_lock(&b->irq_lock); 7562306a36Sopenharmony_ci if (b->irq_armed) 7662306a36Sopenharmony_ci __intel_breadcrumbs_disarm_irq(b); 7762306a36Sopenharmony_ci spin_unlock(&b->irq_lock); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic void add_signaling_context(struct intel_breadcrumbs *b, 8162306a36Sopenharmony_ci struct intel_context *ce) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci lockdep_assert_held(&ce->signal_lock); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci spin_lock(&b->signalers_lock); 8662306a36Sopenharmony_ci list_add_rcu(&ce->signal_link, &b->signalers); 8762306a36Sopenharmony_ci spin_unlock(&b->signalers_lock); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic bool remove_signaling_context(struct intel_breadcrumbs *b, 9162306a36Sopenharmony_ci struct intel_context *ce) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci lockdep_assert_held(&ce->signal_lock); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (!list_empty(&ce->signals)) 9662306a36Sopenharmony_ci return false; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci spin_lock(&b->signalers_lock); 9962306a36Sopenharmony_ci list_del_rcu(&ce->signal_link); 10062306a36Sopenharmony_ci spin_unlock(&b->signalers_lock); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return true; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci__maybe_unused static bool 10662306a36Sopenharmony_cicheck_signal_order(struct intel_context *ce, struct i915_request *rq) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci if (rq->context != ce) 10962306a36Sopenharmony_ci return false; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (!list_is_last(&rq->signal_link, &ce->signals) && 11262306a36Sopenharmony_ci i915_seqno_passed(rq->fence.seqno, 11362306a36Sopenharmony_ci list_next_entry(rq, signal_link)->fence.seqno)) 11462306a36Sopenharmony_ci return false; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (!list_is_first(&rq->signal_link, &ce->signals) && 11762306a36Sopenharmony_ci i915_seqno_passed(list_prev_entry(rq, signal_link)->fence.seqno, 11862306a36Sopenharmony_ci rq->fence.seqno)) 11962306a36Sopenharmony_ci return false; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return true; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic bool 12562306a36Sopenharmony_ci__dma_fence_signal(struct dma_fence *fence) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci return !test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void 13162306a36Sopenharmony_ci__dma_fence_signal__timestamp(struct dma_fence *fence, ktime_t timestamp) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci fence->timestamp = timestamp; 13462306a36Sopenharmony_ci set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags); 13562306a36Sopenharmony_ci trace_dma_fence_signaled(fence); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void 13962306a36Sopenharmony_ci__dma_fence_signal__notify(struct dma_fence *fence, 14062306a36Sopenharmony_ci const struct list_head *list) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct dma_fence_cb *cur, *tmp; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci lockdep_assert_held(fence->lock); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci list_for_each_entry_safe(cur, tmp, list, node) { 14762306a36Sopenharmony_ci INIT_LIST_HEAD(&cur->node); 14862306a36Sopenharmony_ci cur->func(fence, cur); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci if (b->irq_engine) 15562306a36Sopenharmony_ci intel_engine_add_retire(b->irq_engine, tl); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic struct llist_node * 15962306a36Sopenharmony_cislist_add(struct llist_node *node, struct llist_node *head) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci node->next = head; 16262306a36Sopenharmony_ci return node; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void signal_irq_work(struct irq_work *work) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct intel_breadcrumbs *b = container_of(work, typeof(*b), irq_work); 16862306a36Sopenharmony_ci const ktime_t timestamp = ktime_get(); 16962306a36Sopenharmony_ci struct llist_node *signal, *sn; 17062306a36Sopenharmony_ci struct intel_context *ce; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci signal = NULL; 17362306a36Sopenharmony_ci if (unlikely(!llist_empty(&b->signaled_requests))) 17462306a36Sopenharmony_ci signal = llist_del_all(&b->signaled_requests); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * Keep the irq armed until the interrupt after all listeners are gone. 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * Enabling/disabling the interrupt is rather costly, roughly a couple 18062306a36Sopenharmony_ci * of hundred microseconds. If we are proactive and enable/disable 18162306a36Sopenharmony_ci * the interrupt around every request that wants a breadcrumb, we 18262306a36Sopenharmony_ci * quickly drown in the extra orders of magnitude of latency imposed 18362306a36Sopenharmony_ci * on request submission. 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * So we try to be lazy, and keep the interrupts enabled until no 18662306a36Sopenharmony_ci * more listeners appear within a breadcrumb interrupt interval (that 18762306a36Sopenharmony_ci * is until a request completes that no one cares about). The 18862306a36Sopenharmony_ci * observation is that listeners come in batches, and will often 18962306a36Sopenharmony_ci * listen to a bunch of requests in succession. Though note on icl+, 19062306a36Sopenharmony_ci * interrupts are always enabled due to concerns with rc6 being 19162306a36Sopenharmony_ci * dysfunctional with per-engine interrupt masking. 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * We also try to avoid raising too many interrupts, as they may 19462306a36Sopenharmony_ci * be generated by userspace batches and it is unfortunately rather 19562306a36Sopenharmony_ci * too easy to drown the CPU under a flood of GPU interrupts. Thus 19662306a36Sopenharmony_ci * whenever no one appears to be listening, we turn off the interrupts. 19762306a36Sopenharmony_ci * Fewer interrupts should conserve power -- at the very least, fewer 19862306a36Sopenharmony_ci * interrupt draw less ire from other users of the system and tools 19962306a36Sopenharmony_ci * like powertop. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci if (!signal && READ_ONCE(b->irq_armed) && list_empty(&b->signalers)) 20262306a36Sopenharmony_ci intel_breadcrumbs_disarm_irq(b); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rcu_read_lock(); 20562306a36Sopenharmony_ci atomic_inc(&b->signaler_active); 20662306a36Sopenharmony_ci list_for_each_entry_rcu(ce, &b->signalers, signal_link) { 20762306a36Sopenharmony_ci struct i915_request *rq; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci list_for_each_entry_rcu(rq, &ce->signals, signal_link) { 21062306a36Sopenharmony_ci bool release; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!__i915_request_is_complete(rq)) 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, 21662306a36Sopenharmony_ci &rq->fence.flags)) 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* 22062306a36Sopenharmony_ci * Queue for execution after dropping the signaling 22162306a36Sopenharmony_ci * spinlock as the callback chain may end up adding 22262306a36Sopenharmony_ci * more signalers to the same context or engine. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci spin_lock(&ce->signal_lock); 22562306a36Sopenharmony_ci list_del_rcu(&rq->signal_link); 22662306a36Sopenharmony_ci release = remove_signaling_context(b, ce); 22762306a36Sopenharmony_ci spin_unlock(&ce->signal_lock); 22862306a36Sopenharmony_ci if (release) { 22962306a36Sopenharmony_ci if (intel_timeline_is_last(ce->timeline, rq)) 23062306a36Sopenharmony_ci add_retire(b, ce->timeline); 23162306a36Sopenharmony_ci intel_context_put(ce); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (__dma_fence_signal(&rq->fence)) 23562306a36Sopenharmony_ci /* We own signal_node now, xfer to local list */ 23662306a36Sopenharmony_ci signal = slist_add(&rq->signal_node, signal); 23762306a36Sopenharmony_ci else 23862306a36Sopenharmony_ci i915_request_put(rq); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci atomic_dec(&b->signaler_active); 24262306a36Sopenharmony_ci rcu_read_unlock(); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci llist_for_each_safe(signal, sn, signal) { 24562306a36Sopenharmony_ci struct i915_request *rq = 24662306a36Sopenharmony_ci llist_entry(signal, typeof(*rq), signal_node); 24762306a36Sopenharmony_ci struct list_head cb_list; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (rq->engine->sched_engine->retire_inflight_request_prio) 25062306a36Sopenharmony_ci rq->engine->sched_engine->retire_inflight_request_prio(rq); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci spin_lock(&rq->lock); 25362306a36Sopenharmony_ci list_replace(&rq->fence.cb_list, &cb_list); 25462306a36Sopenharmony_ci __dma_fence_signal__timestamp(&rq->fence, timestamp); 25562306a36Sopenharmony_ci __dma_fence_signal__notify(&rq->fence, &cb_list); 25662306a36Sopenharmony_ci spin_unlock(&rq->lock); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci i915_request_put(rq); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (!READ_ONCE(b->irq_armed) && !list_empty(&b->signalers)) 26262306a36Sopenharmony_ci intel_breadcrumbs_arm_irq(b); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistruct intel_breadcrumbs * 26662306a36Sopenharmony_ciintel_breadcrumbs_create(struct intel_engine_cs *irq_engine) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct intel_breadcrumbs *b; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci b = kzalloc(sizeof(*b), GFP_KERNEL); 27162306a36Sopenharmony_ci if (!b) 27262306a36Sopenharmony_ci return NULL; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci kref_init(&b->ref); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci spin_lock_init(&b->signalers_lock); 27762306a36Sopenharmony_ci INIT_LIST_HEAD(&b->signalers); 27862306a36Sopenharmony_ci init_llist_head(&b->signaled_requests); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci spin_lock_init(&b->irq_lock); 28162306a36Sopenharmony_ci init_irq_work(&b->irq_work, signal_irq_work); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci b->irq_engine = irq_engine; 28462306a36Sopenharmony_ci b->irq_enable = irq_enable; 28562306a36Sopenharmony_ci b->irq_disable = irq_disable; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return b; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_civoid intel_breadcrumbs_reset(struct intel_breadcrumbs *b) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci unsigned long flags; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (!b->irq_engine) 29562306a36Sopenharmony_ci return; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spin_lock_irqsave(&b->irq_lock, flags); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (b->irq_enabled) 30062306a36Sopenharmony_ci b->irq_enable(b); 30162306a36Sopenharmony_ci else 30262306a36Sopenharmony_ci b->irq_disable(b); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci spin_unlock_irqrestore(&b->irq_lock, flags); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_civoid __intel_breadcrumbs_park(struct intel_breadcrumbs *b) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci if (!READ_ONCE(b->irq_armed)) 31062306a36Sopenharmony_ci return; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* Kick the work once more to drain the signalers, and disarm the irq */ 31362306a36Sopenharmony_ci irq_work_sync(&b->irq_work); 31462306a36Sopenharmony_ci while (READ_ONCE(b->irq_armed) && !atomic_read(&b->active)) { 31562306a36Sopenharmony_ci local_irq_disable(); 31662306a36Sopenharmony_ci signal_irq_work(&b->irq_work); 31762306a36Sopenharmony_ci local_irq_enable(); 31862306a36Sopenharmony_ci cond_resched(); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_civoid intel_breadcrumbs_free(struct kref *kref) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct intel_breadcrumbs *b = container_of(kref, typeof(*b), ref); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci irq_work_sync(&b->irq_work); 32762306a36Sopenharmony_ci GEM_BUG_ON(!list_empty(&b->signalers)); 32862306a36Sopenharmony_ci GEM_BUG_ON(b->irq_armed); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci kfree(b); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void irq_signal_request(struct i915_request *rq, 33462306a36Sopenharmony_ci struct intel_breadcrumbs *b) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci if (!__dma_fence_signal(&rq->fence)) 33762306a36Sopenharmony_ci return; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci i915_request_get(rq); 34062306a36Sopenharmony_ci if (llist_add(&rq->signal_node, &b->signaled_requests)) 34162306a36Sopenharmony_ci irq_work_queue(&b->irq_work); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic void insert_breadcrumb(struct i915_request *rq) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs; 34762306a36Sopenharmony_ci struct intel_context *ce = rq->context; 34862306a36Sopenharmony_ci struct list_head *pos; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags)) 35162306a36Sopenharmony_ci return; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* 35462306a36Sopenharmony_ci * If the request is already completed, we can transfer it 35562306a36Sopenharmony_ci * straight onto a signaled list, and queue the irq worker for 35662306a36Sopenharmony_ci * its signal completion. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci if (__i915_request_is_complete(rq)) { 35962306a36Sopenharmony_ci irq_signal_request(rq, b); 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (list_empty(&ce->signals)) { 36462306a36Sopenharmony_ci intel_context_get(ce); 36562306a36Sopenharmony_ci add_signaling_context(b, ce); 36662306a36Sopenharmony_ci pos = &ce->signals; 36762306a36Sopenharmony_ci } else { 36862306a36Sopenharmony_ci /* 36962306a36Sopenharmony_ci * We keep the seqno in retirement order, so we can break 37062306a36Sopenharmony_ci * inside intel_engine_signal_breadcrumbs as soon as we've 37162306a36Sopenharmony_ci * passed the last completed request (or seen a request that 37262306a36Sopenharmony_ci * hasn't event started). We could walk the timeline->requests, 37362306a36Sopenharmony_ci * but keeping a separate signalers_list has the advantage of 37462306a36Sopenharmony_ci * hopefully being much smaller than the full list and so 37562306a36Sopenharmony_ci * provides faster iteration and detection when there are no 37662306a36Sopenharmony_ci * more interrupts required for this context. 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * We typically expect to add new signalers in order, so we 37962306a36Sopenharmony_ci * start looking for our insertion point from the tail of 38062306a36Sopenharmony_ci * the list. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci list_for_each_prev(pos, &ce->signals) { 38362306a36Sopenharmony_ci struct i915_request *it = 38462306a36Sopenharmony_ci list_entry(pos, typeof(*it), signal_link); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (i915_seqno_passed(rq->fence.seqno, it->fence.seqno)) 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci i915_request_get(rq); 39262306a36Sopenharmony_ci list_add_rcu(&rq->signal_link, pos); 39362306a36Sopenharmony_ci GEM_BUG_ON(!check_signal_order(ce, rq)); 39462306a36Sopenharmony_ci GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags)); 39562306a36Sopenharmony_ci set_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* 39862306a36Sopenharmony_ci * Defer enabling the interrupt to after HW submission and recheck 39962306a36Sopenharmony_ci * the request as it may have completed and raised the interrupt as 40062306a36Sopenharmony_ci * we were attaching it into the lists. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci if (!b->irq_armed || __i915_request_is_complete(rq)) 40362306a36Sopenharmony_ci irq_work_queue(&b->irq_work); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cibool i915_request_enable_breadcrumb(struct i915_request *rq) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct intel_context *ce = rq->context; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Serialises with i915_request_retire() using rq->lock */ 41162306a36Sopenharmony_ci if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags)) 41262306a36Sopenharmony_ci return true; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* 41562306a36Sopenharmony_ci * Peek at i915_request_submit()/i915_request_unsubmit() status. 41662306a36Sopenharmony_ci * 41762306a36Sopenharmony_ci * If the request is not yet active (and not signaled), we will 41862306a36Sopenharmony_ci * attach the breadcrumb later. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci if (!test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags)) 42162306a36Sopenharmony_ci return true; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci spin_lock(&ce->signal_lock); 42462306a36Sopenharmony_ci if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags)) 42562306a36Sopenharmony_ci insert_breadcrumb(rq); 42662306a36Sopenharmony_ci spin_unlock(&ce->signal_lock); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return true; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_civoid i915_request_cancel_breadcrumb(struct i915_request *rq) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs; 43462306a36Sopenharmony_ci struct intel_context *ce = rq->context; 43562306a36Sopenharmony_ci bool release; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci spin_lock(&ce->signal_lock); 43862306a36Sopenharmony_ci if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags)) { 43962306a36Sopenharmony_ci spin_unlock(&ce->signal_lock); 44062306a36Sopenharmony_ci return; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci list_del_rcu(&rq->signal_link); 44462306a36Sopenharmony_ci release = remove_signaling_context(b, ce); 44562306a36Sopenharmony_ci spin_unlock(&ce->signal_lock); 44662306a36Sopenharmony_ci if (release) 44762306a36Sopenharmony_ci intel_context_put(ce); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (__i915_request_is_complete(rq)) 45062306a36Sopenharmony_ci irq_signal_request(rq, b); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci i915_request_put(rq); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_civoid intel_context_remove_breadcrumbs(struct intel_context *ce, 45662306a36Sopenharmony_ci struct intel_breadcrumbs *b) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct i915_request *rq, *rn; 45962306a36Sopenharmony_ci bool release = false; 46062306a36Sopenharmony_ci unsigned long flags; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci spin_lock_irqsave(&ce->signal_lock, flags); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (list_empty(&ce->signals)) 46562306a36Sopenharmony_ci goto unlock; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci list_for_each_entry_safe(rq, rn, &ce->signals, signal_link) { 46862306a36Sopenharmony_ci GEM_BUG_ON(!__i915_request_is_complete(rq)); 46962306a36Sopenharmony_ci if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, 47062306a36Sopenharmony_ci &rq->fence.flags)) 47162306a36Sopenharmony_ci continue; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci list_del_rcu(&rq->signal_link); 47462306a36Sopenharmony_ci irq_signal_request(rq, b); 47562306a36Sopenharmony_ci i915_request_put(rq); 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci release = remove_signaling_context(b, ce); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ciunlock: 48062306a36Sopenharmony_ci spin_unlock_irqrestore(&ce->signal_lock, flags); 48162306a36Sopenharmony_ci if (release) 48262306a36Sopenharmony_ci intel_context_put(ce); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci while (atomic_read(&b->signaler_active)) 48562306a36Sopenharmony_ci cpu_relax(); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct intel_context *ce; 49162306a36Sopenharmony_ci struct i915_request *rq; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci drm_printf(p, "Signals:\n"); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci rcu_read_lock(); 49662306a36Sopenharmony_ci list_for_each_entry_rcu(ce, &b->signalers, signal_link) { 49762306a36Sopenharmony_ci list_for_each_entry_rcu(rq, &ce->signals, signal_link) 49862306a36Sopenharmony_ci drm_printf(p, "\t[%llx:%llx%s] @ %dms\n", 49962306a36Sopenharmony_ci rq->fence.context, rq->fence.seqno, 50062306a36Sopenharmony_ci __i915_request_is_complete(rq) ? "!" : 50162306a36Sopenharmony_ci __i915_request_has_started(rq) ? "*" : 50262306a36Sopenharmony_ci "", 50362306a36Sopenharmony_ci jiffies_to_msecs(jiffies - rq->emitted_jiffies)); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci rcu_read_unlock(); 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_civoid intel_engine_print_breadcrumbs(struct intel_engine_cs *engine, 50962306a36Sopenharmony_ci struct drm_printer *p) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct intel_breadcrumbs *b; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci b = engine->breadcrumbs; 51462306a36Sopenharmony_ci if (!b) 51562306a36Sopenharmony_ci return; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci drm_printf(p, "IRQ: %s\n", str_enabled_disabled(b->irq_armed)); 51862306a36Sopenharmony_ci if (!list_empty(&b->signalers)) 51962306a36Sopenharmony_ci print_signals(b, p); 52062306a36Sopenharmony_ci} 521