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 2909b123baf50147391e06923bc70b1a991098af..359f6e8b9b006de01533e1ddc5df6a7e370406c0 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 476c64c4844c5e6c7e906d396cb7cfafbde7ed29..627fe35781b4b92b1272a8bec3282dae2a3a8bc9 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 23f2ea0f0651f8cf29e64a6a152d3f553a3fbd02..566f61b9e47c2ddd15d706d68ca4b4974e7fd197 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 ac5688e8b01dcf41c3c9e2529e2b2219fb731447..7aa6e97c2c7298d0b7ae5eb6ecb2f2809fde9225 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 d42d821c64d6b917b5077c51b92ff5bd6cabb373..ddc48590ea60f5ee6ac8ebc005a47c9dffc2b53a 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,