drm/i915: Add comments to explain the BSD tail write workaround
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 5 Jul 2012 16:14:01 +0000 (17:14 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 20 Jul 2012 10:21:37 +0000 (12:21 +0200)
Having had to dive into the bspec to understand what each stage of the
workaround meant, and how that the ring broadcasting IDLE corresponded
with the GT powering down the ring (i.e. rc6) add comments to aide
the next reader.

And since the register "is used to control all aspects of PSMI and power
saving functions" that makes it quite interesting to inspect with
regards to RC6 hangs, so add it to the error-state.

v2: Rediscover the piece of magic, set the RNCID to 0 before waiting for
the ring to wake up.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_ringbuffer.c

index 2909b12..359f6e8 100644 (file)
@@ -676,6 +676,7 @@ static void i915_ring_error_state(struct seq_file *m,
        seq_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
        seq_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
        if (INTEL_INFO(dev)->gen >= 6) {
+               seq_printf(m, "  RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
                seq_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
                seq_printf(m, "  SYNC_0: 0x%08x\n",
                           error->semaphore_mboxes[ring][0]);
index 476c64c..627fe35 100644 (file)
@@ -190,6 +190,7 @@ struct drm_i915_error_state {
        u32 instdone[I915_NUM_RINGS];
        u32 acthd[I915_NUM_RINGS];
        u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1];
+       u32 rc_psmi[I915_NUM_RINGS]; /* sleep state */
        /* our own tracking of ring head and tail */
        u32 cpu_ring_head[I915_NUM_RINGS];
        u32 cpu_ring_tail[I915_NUM_RINGS];
index 23f2ea0..566f61b 100644 (file)
@@ -1067,6 +1067,7 @@ static void i915_record_ring_state(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (INTEL_INFO(dev)->gen >= 6) {
+               error->rc_psmi[ring->id] = I915_READ(ring->mmio_base + 0x50);
                error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
                error->semaphore_mboxes[ring->id][0]
                        = I915_READ(RING_SYNC_0(ring->mmio_base));
index ac5688e..7aa6e97 100644 (file)
 #define   GEN6_BLITTER_FBC_NOTIFY                      (1<<3)
 
 #define GEN6_BSD_SLEEP_PSMI_CONTROL    0x12050
-#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK      (1 << 16)
-#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE          (1 << 0)
-#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE           0
-#define   GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR                   (1 << 3)
+#define   GEN6_BSD_SLEEP_MSG_DISABLE   (1 << 0)
+#define   GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2)
+#define   GEN6_BSD_SLEEP_INDICATOR     (1 << 3)
+#define   GEN6_BSD_GO_INDICATOR                (1 << 4)
 
 #define GEN6_BSD_HWSTAM                        0x12098
 #define GEN6_BSD_IMR                   0x120a8
index d42d821..ddc4859 100644 (file)
@@ -1270,20 +1270,31 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
 
        /* Every tail move must follow the sequence below */
+
+       /* Disable notification that the ring is IDLE. The GT
+        * will then assume that it is busy and bring it out of rc6.
+        */
        I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
-               GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
-               GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE);
-       I915_WRITE(GEN6_BSD_RNCID, 0x0);
+                  _MASKED_BIT_ENABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
+
+       /* Clear the context id. Here be magic! */
+       I915_WRITE64(GEN6_BSD_RNCID, 0x0);
 
+       /* Wait for the ring not to be idle, i.e. for it to wake up. */
        if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
-               GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR) == 0,
-               50))
-       DRM_ERROR("timed out waiting for IDLE Indicator\n");
+                     GEN6_BSD_SLEEP_INDICATOR) == 0,
+                    50))
+               DRM_ERROR("timed out waiting for the BSD ring to wake up\n");
 
+       /* Now that the ring is fully powered up, update the tail */
        I915_WRITE_TAIL(ring, value);
+       POSTING_READ(RING_TAIL(ring->mmio_base));
+
+       /* Let the ring send IDLE messages to the GT again,
+        * and so let it sleep to conserve power when idle.
+        */
        I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
-               GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
-               GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE);
+                  _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
 }
 
 static int gen6_ring_flush(struct intel_ring_buffer *ring,