drm/i915/ringbuffer: Move irq seqno barrier to the GPU for gen5
authorChris Wilson <chris@chris-wilson.co.uk>
Fri, 28 Dec 2018 17:16:40 +0000 (17:16 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 31 Dec 2018 15:35:45 +0000 (15:35 +0000)
The irq_seqno_barrier is a tradeoff between doing work on every request
(on the GPU) and doing work after every interrupt (on the CPU). We
presume we have many more requests than interrupts! However, for
Ironlake, the workaround is a pretty hideous usleep() and so even though
it was found we need to repeat the MI_STORE_DWORD_IMM 8 times, or about
1us of GPU time, doing so is preferrable than requiring a sleep of
125-250us on the CPU where we desire to respond immediately (ideally from
within the interrupt handler)!

The additional MI_STORE_DWORD_IMM also have the side-effect of flushing
MI operations from userspace which are not caught by MI_FLUSH!

Testcase: igt/gem_sync
Testcase: igt/gem_exec_whisper
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181228171641.16531-5-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/intel_ringbuffer.c

index dd996103d49581e084f90a7632e3293bbf08b445..13ac01b67eadcb39d5592004829a30aa001b4011 100644 (file)
@@ -881,26 +881,29 @@ static void i9xx_emit_breadcrumb(struct i915_request *rq, u32 *cs)
        rq->tail = intel_ring_offset(rq, cs);
        assert_ring_tail_valid(rq->ring, rq->tail);
 }
-
 static const int i9xx_emit_breadcrumb_sz = 6;
 
-static void
-gen5_seqno_barrier(struct intel_engine_cs *engine)
+#define GEN5_WA_STORES 8 /* must be at least 1! */
+static void gen5_emit_breadcrumb(struct i915_request *rq, u32 *cs)
 {
-       /* MI_STORE are internally buffered by the GPU and not flushed
-        * either by MI_FLUSH or SyncFlush or any other combination of
-        * MI commands.
-        *
-        * "Only the submission of the store operation is guaranteed.
-        * The write result will be complete (coherent) some time later
-        * (this is practically a finite period but there is no guaranteed
-        * latency)."
-        *
-        * Empirically, we observe that we need a delay of at least 75us to
-        * be sure that the seqno write is visible by the CPU.
-        */
-       usleep_range(125, 250);
+       int i;
+
+       *cs++ = MI_FLUSH;
+
+       BUILD_BUG_ON(GEN5_WA_STORES < 1);
+       for (i = 0; i < GEN5_WA_STORES; i++) {
+               *cs++ = MI_STORE_DWORD_INDEX;
+               *cs++ = I915_GEM_HWS_INDEX_ADDR;
+               *cs++ = rq->global_seqno;
+       }
+
+       *cs++ = MI_USER_INTERRUPT;
+
+       rq->tail = intel_ring_offset(rq, cs);
+       assert_ring_tail_valid(rq->ring, rq->tail);
 }
+static const int gen5_emit_breadcrumb_sz = GEN5_WA_STORES * 3 + 2;
+#undef GEN5_WA_STORES
 
 static void
 gen5_irq_enable(struct intel_engine_cs *engine)
@@ -2148,7 +2151,6 @@ static void intel_ring_init_irq(struct drm_i915_private *dev_priv,
        } else if (INTEL_GEN(dev_priv) >= 5) {
                engine->irq_enable = gen5_irq_enable;
                engine->irq_disable = gen5_irq_disable;
-               engine->irq_seqno_barrier = gen5_seqno_barrier;
        } else if (INTEL_GEN(dev_priv) >= 3) {
                engine->irq_enable = i9xx_irq_enable;
                engine->irq_disable = i9xx_irq_disable;
@@ -2191,6 +2193,10 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv,
 
        engine->emit_breadcrumb = i9xx_emit_breadcrumb;
        engine->emit_breadcrumb_sz = i9xx_emit_breadcrumb_sz;
+       if (IS_GEN(dev_priv, 5)) {
+               engine->emit_breadcrumb = gen5_emit_breadcrumb;
+               engine->emit_breadcrumb_sz = gen5_emit_breadcrumb_sz;
+       }
 
        engine->set_default_submission = i9xx_set_default_submission;