@@ -1383,6 +1383,7 @@ out:
* request has not actually been fully processed yet.
*/
spin_lock_irq(&req->engine->fence_lock);
+ req->engine->last_irq_seqno = 0;
i915_gem_request_notify(req->engine, true);
spin_unlock_irq(&req->engine->fence_lock);
}
@@ -2584,9 +2585,12 @@ i915_gem_init_seqno(struct drm_device *dev, u32 seqno)
i915_gem_retire_requests(dev);
/* Finally reset hw state */
- for_each_engine(engine, dev_priv)
+ for_each_engine(engine, dev_priv) {
intel_ring_init_seqno(engine, seqno);
+ engine->last_irq_seqno = 0;
+ }
+
return 0;
}
@@ -2920,13 +2924,24 @@ void i915_gem_request_notify(struct intel_engine_cs *engine, bool fence_locked)
return;
}
- if (!fence_locked)
- spin_lock_irqsave(&engine->fence_lock, flags);
-
+ /*
+ * Check for a new seqno. If it hasn't actually changed then early
+ * exit without even grabbing the spinlock. Note that this is safe
+ * because any corruption of last_irq_seqno merely results in doing
+ * the full processing when there is potentially no work to be done.
+ * It can never lead to not processing work that does need to happen.
+ */
if (engine->irq_seqno_barrier)
engine->irq_seqno_barrier(engine);
seqno = engine->get_seqno(engine);
trace_i915_gem_request_notify(engine, seqno);
+ if (seqno == engine->last_irq_seqno)
+ return;
+
+ if (!fence_locked)
+ spin_lock_irqsave(&engine->fence_lock, flags);
+
+ engine->last_irq_seqno = seqno;
list_for_each_entry_safe(req, req_next, &engine->fence_signal_list, signal_link) {
if (!req->cancelled) {
@@ -3242,7 +3257,10 @@ static void i915_gem_reset_engine_cleanup(struct drm_i915_private *dev_priv,
* Tidy up anything left over. This includes a call to
* i915_gem_request_notify() which will make sure that any requests
* that were on the signal pending list get also cleaned up.
+ * NB: The seqno cache must be cleared otherwise the notify call will
+ * simply return immediately.
*/
+ engine->last_irq_seqno = 0;
i915_gem_retire_requests_ring(engine);
/* Having flushed all requests from all queues, we know that all
@@ -359,6 +359,7 @@ struct intel_engine_cs {
spinlock_t fence_lock;
struct list_head fence_signal_list;
struct list_head fence_unsignal_list;
+ uint32_t last_irq_seqno;
};
static inline bool