* but it is easier and safer to do it every time the waiter
* is woken.
*/
- if (engine->irq_seqno_barrier) {
+ if (engine->irq_seqno_barrier &&
+ cmpxchg_relaxed(&engine->irq_posted, 1, 0)) {
+ /* The ordering of irq_posted versus applying the barrier
+ * is crucial. The clearing of the current irq_posted must
+ * be visible before we perform the barrier operation,
+ * such that if a subsequent interrupt arrives, irq_posted
+ * is reasserted and our task rewoken (which causes us to
+ * do another __i915_request_irq_complete() immediately
+ * and reapply the barrier). Conversely, if the clear
+ * occurs after the barrier, then an interrupt that arrived
+ * whilst we waited on the barrier would not trigger a
+ * barrier on the next pass, and the read may not see the
+ * seqno update.
+ */
engine->irq_seqno_barrier(engine);
if (i915_gem_request_completed(req))
return true;
static void irq_enable(struct intel_engine_cs *engine)
{
+ /* Enabling the IRQ may miss the generation of the interrupt, but
+ * we still need to force the barrier before reading the seqno,
+ * just in case.
+ */
+ engine->irq_posted = true;
WARN_ON(!engine->irq_get(engine));
}
static void irq_disable(struct intel_engine_cs *engine)
{
engine->irq_put(engine);
+ engine->irq_posted = false;
}
static bool __intel_breadcrumbs_enable_irq(struct intel_breadcrumbs *b)
struct intel_engine_cs *engine =
container_of(b, struct intel_engine_cs, breadcrumbs);
struct drm_i915_private *i915 = engine->i915;
- bool irq_posted = false;
assert_spin_locked(&b->lock);
if (b->rpm_wakelock)
/* No interrupts? Kick the waiter every jiffie! */
if (intel_irqs_enabled(i915)) {
- if (!test_bit(engine->id, &i915->gpu_error.test_irq_rings)) {
+ if (!test_bit(engine->id, &i915->gpu_error.test_irq_rings))
irq_enable(engine);
- irq_posted = true;
- }
b->irq_enabled = true;
}
test_bit(engine->id, &i915->gpu_error.missed_irq_rings))
mod_timer(&b->fake_irq, jiffies + 1);
- return irq_posted;
+ return engine->irq_posted;
}
static void __intel_breadcrumbs_disable_irq(struct intel_breadcrumbs *b)
* in case the seqno passed.
*/
__intel_breadcrumbs_enable_irq(b);
- wake_up_process(to_wait(next)->tsk);
+ if (READ_ONCE(engine->irq_posted))
+ wake_up_process(to_wait(next)->tsk);
}
do {