* 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 {