drm/i915: Capture the overlay status upon a GPU hang.
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 4 Aug 2010 19:26:07 +0000 (20:26 +0100)
committerEric Anholt <eric@anholt.net>
Mon, 9 Aug 2010 18:24:31 +0000 (11:24 -0700)
v2: Add the interrupt status and address.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Eric Anholt <eric@anholt.net>
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/intel_overlay.c

index 9214119c01540fb5244d3ca383adb1c5ee04722c..92d5605a34d11a6fcecbbae4149220c44ac86740 100644 (file)
@@ -467,6 +467,9 @@ static int i915_error_state(struct seq_file *m, void *unused)
                }
        }
 
+       if (error->overlay)
+               intel_overlay_print_error_state(m, error->overlay);
+
 out:
        spin_unlock_irqrestore(&dev_priv->error_lock, flags);
 
index 5cd593f826efb64679fdb910db5bafbfb726da4f..151056501a5f2299f4e2d8469e4091a8c54d0670 100644 (file)
@@ -113,6 +113,9 @@ struct intel_opregion {
        int enabled;
 };
 
+struct intel_overlay;
+struct intel_overlay_error_state;
+
 struct drm_i915_master_private {
        drm_local_map_t *sarea;
        struct _drm_i915_sarea *sarea_priv;
@@ -166,6 +169,7 @@ struct drm_i915_error_state {
                u32 purgeable:1;
        } *active_bo;
        u32 active_bo_count;
+       struct intel_overlay_error_state *overlay;
 };
 
 struct drm_i915_display_funcs {
@@ -186,8 +190,6 @@ struct drm_i915_display_funcs {
        /* clock gating init */
 };
 
-struct intel_overlay;
-
 struct intel_device_info {
        u8 is_mobile : 1;
        u8 is_i8xx : 1;
@@ -1069,6 +1071,10 @@ extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
 extern void intel_detect_pch (struct drm_device *dev);
 extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
 
+/* overlay */
+extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
+extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+
 /**
  * Lock test for when it's just for synchronization of ring access.
  *
index 85785a8844ed5e422c99ca96a4a88e5d6a404a1a..854ab1e92fd9aa56e8da0b0316c4c08cd4dbca8e 100644 (file)
@@ -489,6 +489,7 @@ i915_error_state_free(struct drm_device *dev,
        i915_error_object_free(error->batchbuffer[1]);
        i915_error_object_free(error->ringbuffer);
        kfree(error->active_bo);
+       kfree(error->overlay);
        kfree(error);
 }
 
@@ -667,6 +668,8 @@ static void i915_capture_error_state(struct drm_device *dev)
 
        do_gettimeofday(&error->time);
 
+       error->overlay = intel_overlay_capture_error_state(dev);
+
        spin_lock_irqsave(&dev_priv->error_lock, flags);
        if (dev_priv->first_error == NULL) {
                dev_priv->first_error = error;
index d39aea24eabe3b2d0bc9bf42bc6344d6457bd3ec..9ae61aa05a1f29cf265a3f4c9a3f33435540728f 100644 (file)
@@ -1416,3 +1416,99 @@ void intel_cleanup_overlay(struct drm_device *dev)
                kfree(dev_priv->overlay);
        }
 }
+
+struct intel_overlay_error_state {
+       struct overlay_registers regs;
+       unsigned long base;
+       u32 dovsta;
+       u32 isr;
+};
+
+struct intel_overlay_error_state *
+intel_overlay_capture_error_state(struct drm_device *dev)
+{
+        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_overlay *overlay = dev_priv->overlay;
+       struct intel_overlay_error_state *error;
+       struct overlay_registers __iomem *regs;
+
+       if (!overlay || !overlay->active)
+               return NULL;
+
+       error = kmalloc(sizeof(*error), GFP_ATOMIC);
+       if (error == NULL)
+               return NULL;
+
+       error->dovsta = I915_READ(DOVSTA);
+       error->isr = I915_READ(ISR);
+       if (OVERLAY_NONPHYSICAL(overlay->dev))
+               error->base = (long) overlay->reg_bo->gtt_offset;
+       else
+               error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
+
+       regs = intel_overlay_map_regs_atomic(overlay);
+       if (!regs)
+               goto err;
+
+       memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
+       intel_overlay_unmap_regs_atomic(overlay);
+
+       return error;
+
+err:
+       kfree(error);
+       return NULL;
+}
+
+void
+intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error)
+{
+       seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
+                  error->dovsta, error->isr);
+       seq_printf(m, "  Register file at 0x%08lx:\n",
+                  error->base);
+
+#define P(x) seq_printf(m, "    " #x ":        0x%08x\n", error->regs.x)
+       P(OBUF_0Y);
+       P(OBUF_1Y);
+       P(OBUF_0U);
+       P(OBUF_0V);
+       P(OBUF_1U);
+       P(OBUF_1V);
+       P(OSTRIDE);
+       P(YRGB_VPH);
+       P(UV_VPH);
+       P(HORZ_PH);
+       P(INIT_PHS);
+       P(DWINPOS);
+       P(DWINSZ);
+       P(SWIDTH);
+       P(SWIDTHSW);
+       P(SHEIGHT);
+       P(YRGBSCALE);
+       P(UVSCALE);
+       P(OCLRC0);
+       P(OCLRC1);
+       P(DCLRKV);
+       P(DCLRKM);
+       P(SCLRKVH);
+       P(SCLRKVL);
+       P(SCLRKEN);
+       P(OCONFIG);
+       P(OCMD);
+       P(OSTART_0Y);
+       P(OSTART_1Y);
+       P(OSTART_0U);
+       P(OSTART_0V);
+       P(OSTART_1U);
+       P(OSTART_1V);
+       P(OTILEOFF_0Y);
+       P(OTILEOFF_1Y);
+       P(OTILEOFF_0U);
+       P(OTILEOFF_0V);
+       P(OTILEOFF_1U);
+       P(OTILEOFF_1V);
+       P(FASTHSCALE);
+       P(UVSCALEV);
+#undef P
+}