drm/i915/bdw: Export workaround data to debugfs
authorArun Siluvery <arun.siluvery@linux.intel.com>
Tue, 26 Aug 2014 13:44:51 +0000 (14:44 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 3 Sep 2014 09:04:44 +0000 (11:04 +0200)
The workarounds that are applied are exported to a debugfs file;
this is used to verify their state after the test case (reset or
suspend/resume etc). This patch is only required to support i-g-t.

Signed-off-by: Arun Siluvery <arun.siluvery@linux.intel.com>
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/intel_ringbuffer.c

index 9d93af126f9cb0ed24f36ccfe01a41de0add2a30..1467cc1a47a9f57c857b669a2529cb3df519be62 100644 (file)
@@ -2628,6 +2628,45 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int intel_wa_registers(struct seq_file *m, void *unused)
+{
+       int i;
+       int ret;
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!IS_BROADWELL(dev)) {
+               DRM_DEBUG_DRIVER("Workaround table not available !!\n");
+               return -EINVAL;
+       }
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       intel_runtime_pm_get(dev_priv);
+
+       seq_printf(m, "Workarounds applied: %d\n", dev_priv->num_wa_regs);
+       for (i = 0; i < dev_priv->num_wa_regs; ++i) {
+               u32 addr, mask;
+
+               addr = dev_priv->intel_wa_regs[i].addr;
+               mask = dev_priv->intel_wa_regs[i].mask;
+               dev_priv->intel_wa_regs[i].value = I915_READ(addr) | mask;
+               if (dev_priv->intel_wa_regs[i].addr)
+                       seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X\n",
+                                  dev_priv->intel_wa_regs[i].addr,
+                                  dev_priv->intel_wa_regs[i].value,
+                                  dev_priv->intel_wa_regs[i].mask);
+       }
+
+       intel_runtime_pm_put(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
 struct pipe_crc_info {
        const char *name;
        struct drm_device *dev;
@@ -4159,6 +4198,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_semaphore_status", i915_semaphore_status, 0},
        {"i915_shared_dplls_info", i915_shared_dplls_info, 0},
        {"i915_dp_mst_info", i915_dp_mst_info, 0},
+       {"intel_wa_registers", intel_wa_registers, 0}
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
index f13f30d65172a6f01c8b2ed8bb8c40ac0050114d..95820652e153054e0bbabb7a02f9a2dd0a6a4f4f 100644 (file)
@@ -1556,6 +1556,20 @@ struct drm_i915_private {
        struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
        int dpio_phy_iosf_port[I915_NUM_PHYS_VLV];
 
+       /*
+        * workarounds are currently applied at different places and
+        * changes are being done to consolidate them so exact count is
+        * not clear at this point, use a max value for now.
+        */
+#define I915_MAX_WA_REGS  16
+       struct {
+               u32 addr;
+               u32 value;
+               /* bitmask representing WA bits */
+               u32 mask;
+       } intel_wa_regs[I915_MAX_WA_REGS];
+       u32 num_wa_regs;
+
        /* Reclocking support */
        bool render_reclock_avail;
        bool lvds_downclock_avail;
index 1d5bfdb4fe9787bd1c3507696e37b649d90dc7dd..14b517d61b4e99f2249207124c5eb43d39ef9354 100644 (file)
@@ -660,20 +660,40 @@ err:
 static inline void intel_ring_emit_wa(struct intel_engine_cs *ring,
                                       u32 addr, u32 value)
 {
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->num_wa_regs > I915_MAX_WA_REGS)
+               return;
+
        intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
        intel_ring_emit(ring, addr);
        intel_ring_emit(ring, value);
+
+       dev_priv->intel_wa_regs[dev_priv->num_wa_regs].addr = addr;
+       dev_priv->intel_wa_regs[dev_priv->num_wa_regs].mask = (value) & 0xFFFF;
+       /* value is updated with the status of remaining bits of this
+        * register when it is read from debugfs file
+        */
+       dev_priv->intel_wa_regs[dev_priv->num_wa_regs].value = value;
+       dev_priv->num_wa_regs++;
+
+       return;
 }
 
 static int gen8_init_workarounds(struct intel_engine_cs *ring)
 {
        int ret;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        /*
         * workarounds applied in this fn are part of register state context,
         * they need to be re-initialized followed by gpu reset, suspend/resume,
         * module reload.
         */
+       dev_priv->num_wa_regs = 0;
+       memset(dev_priv->intel_wa_regs, 0, sizeof(dev_priv->intel_wa_regs));
 
        /*
         * update the number of dwords required based on the
@@ -732,6 +752,9 @@ static int gen8_init_workarounds(struct intel_engine_cs *ring)
 
        intel_ring_advance(ring);
 
+       DRM_DEBUG_DRIVER("Number of Workarounds applied: %d\n",
+                        dev_priv->num_wa_regs);
+
        return 0;
 }