drm/i915: Expose latest 200 CRC value for pipe through debugfs
authorShuang He <shuang.he@intel.com>
Tue, 15 Oct 2013 17:55:27 +0000 (18:55 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 16 Oct 2013 11:31:42 +0000 (13:31 +0200)
There are several points in the display pipeline where CRCs can be
computed on the bits flowing there. For instance, it's usually possible
to compute the CRCs of the primary plane, the sprite plane or the CRCs
of the bits after the panel fitter (collectively called pipe CRCs).

v2: Quite a bit of rework here and there (Damien)

Signed-off-by: Shuang He <shuang.he@intel.com>
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
[danvet: Fix intermediate compile file reported by Wu Fengguang's
kernel builder.]
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

index 72d04588eccbd2fd79be772e4cae50cbfc6bc6ad..e1d45aaf6881ac0ff325e5562c8f64307e737971 100644 (file)
@@ -1732,6 +1732,36 @@ static int i915_pc8_status(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int i915_pipe_crc(struct seq_file *m, void *data)
+{
+       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;
+       enum pipe pipe = (enum pipe)node->info_ent->data;
+       const struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
+       int i;
+       int start;
+
+       if (!IS_IVYBRIDGE(dev)) {
+               seq_puts(m, "unsupported\n");
+               return 0;
+       }
+
+       start = atomic_read(&pipe_crc->slot) + 1;
+       seq_puts(m, " timestamp     CRC1     CRC2     CRC3     CRC4     CRC5\n");
+       for (i = 0; i < INTEL_PIPE_CRC_ENTRIES_NR; i++) {
+               const struct intel_pipe_crc_entry *entry =
+                       &pipe_crc->entries[(start + i) %
+                                          INTEL_PIPE_CRC_ENTRIES_NR];
+
+               seq_printf(m, "%12u %8x %8x %8x %8x %8x\n", entry->timestamp,
+                          entry->crc[0], entry->crc[1], entry->crc[2],
+                          entry->crc[3], entry->crc[4]);
+       }
+
+       return 0;
+}
+
 static int
 i915_wedged_get(void *data, u64 *val)
 {
@@ -2247,6 +2277,9 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_edp_psr_status", i915_edp_psr_status, 0},
        {"i915_energy_uJ", i915_energy_uJ, 0},
        {"i915_pc8_status", i915_pc8_status, 0},
+       {"i915_pipe_A_crc", i915_pipe_crc, 0, (void *)PIPE_A},
+       {"i915_pipe_B_crc", i915_pipe_crc, 0, (void *)PIPE_B},
+       {"i915_pipe_C_crc", i915_pipe_crc, 0, (void *)PIPE_C},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
index 3d374aa1a2b007982a84d86734c650afc05d7a61..b040ef82208f220e56f3b7368f4f34689f1c5680 100644 (file)
@@ -1217,6 +1217,17 @@ struct i915_package_c8 {
        } regsave;
 };
 
+struct intel_pipe_crc_entry {
+       uint32_t timestamp;
+       uint32_t crc[5];
+};
+
+#define INTEL_PIPE_CRC_ENTRIES_NR      200
+struct intel_pipe_crc {
+       struct intel_pipe_crc_entry entries[INTEL_PIPE_CRC_ENTRIES_NR];
+       atomic_t slot;
+};
+
 typedef struct drm_i915_private {
        struct drm_device *dev;
        struct kmem_cache *slab;
@@ -1421,6 +1432,10 @@ typedef struct drm_i915_private {
        struct i915_dri1_state dri1;
        /* Old ums support infrastructure, same warning applies. */
        struct i915_ums_state ums;
+
+#ifdef CONFIG_DEBUG_FS
+       struct intel_pipe_crc pipe_crc[I915_MAX_PIPES];
+#endif
 } drm_i915_private_t;
 
 static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
index 26753b6ac0a150c9989bf7f1f289f7d94a6c5c23..d2074f129a364f1eb4c6f2156165ca742f4d38da 100644 (file)
@@ -1188,6 +1188,32 @@ static void dp_aux_irq_handler(struct drm_device *dev)
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
+#if defined(CONFIG_DEBUG_FS)
+static void ivb_pipe_crc_update(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
+       struct intel_pipe_crc_entry *entry;
+       ktime_t now;
+       int ts, slot;
+
+       now = ktime_get();
+       ts = ktime_to_us(now);
+
+       slot = (atomic_read(&pipe_crc->slot) + 1) % INTEL_PIPE_CRC_ENTRIES_NR;
+       entry = &pipe_crc->entries[slot];
+       entry->timestamp = ts;
+       entry->crc[0] = I915_READ(PIPE_CRC_RES_1_IVB(pipe));
+       entry->crc[1] = I915_READ(PIPE_CRC_RES_2_IVB(pipe));
+       entry->crc[2] = I915_READ(PIPE_CRC_RES_3_IVB(pipe));
+       entry->crc[3] = I915_READ(PIPE_CRC_RES_4_IVB(pipe));
+       entry->crc[4] = I915_READ(PIPE_CRC_RES_5_IVB(pipe));
+       atomic_set(&dev_priv->pipe_crc[pipe].slot, slot);
+}
+#else
+static void ivb_pipe_crc_update(struct drm_device *dev, int pipe) {}
+#endif
+
 /* The RPS events need forcewake, so we add them to a work queue and mask their
  * IMR bits until the work is done. Other interrupts can be processed without
  * the work queue. */
@@ -1366,6 +1392,15 @@ static void ivb_err_int_handler(struct drm_device *dev)
                if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false))
                        DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n");
 
+       if (err_int & ERR_INT_PIPE_CRC_DONE_A)
+               ivb_pipe_crc_update(dev, PIPE_A);
+
+       if (err_int & ERR_INT_PIPE_CRC_DONE_B)
+               ivb_pipe_crc_update(dev, PIPE_B);
+
+       if (err_int & ERR_INT_PIPE_CRC_DONE_C)
+               ivb_pipe_crc_update(dev, PIPE_C);
+
        I915_WRITE(GEN7_ERR_INT, err_int);
 }
 
index 88f76714dba363c128eb93a1476b770c9c273dff..8161521003ed6986c583f104d0961f1e76870516 100644 (file)
 #define GEN7_ERR_INT   0x44040
 #define   ERR_INT_POISON               (1<<31)
 #define   ERR_INT_MMIO_UNCLAIMED       (1<<13)
+#define   ERR_INT_PIPE_CRC_DONE_C      (1<<8)
 #define   ERR_INT_FIFO_UNDERRUN_C      (1<<6)
+#define   ERR_INT_PIPE_CRC_DONE_B      (1<<5)
 #define   ERR_INT_FIFO_UNDERRUN_B      (1<<3)
+#define   ERR_INT_PIPE_CRC_DONE_A      (1<<2)
 #define   ERR_INT_FIFO_UNDERRUN_A      (1<<0)
 #define   ERR_INT_FIFO_UNDERRUN(pipe)  (1<<(pipe*3))
 
  * Display engine regs
  */
 
+/* Pipe A CRC regs */
+#define _PIPE_CRC_CTL_A                (dev_priv->info->display_mmio_offset + 0x60050)
+#define   PIPE_CRC_ENABLE              (1 << 31)
+#define   PIPE_CRC_SOURCE_PRIMARY_IVB  (0 << 29)
+#define   PIPE_CRC_SOURCE_SPRITE_IVB   (1 << 29)
+#define   PIPE_CRC_SOURCE_PF_IVB       (2 << 29)
+#define _PIPE_CRC_RES_1_A_IVB  (dev_priv->info->display_mmio_offset + 0x60064)
+#define _PIPE_CRC_RES_2_A_IVB  (dev_priv->info->display_mmio_offset + 0x60068)
+#define _PIPE_CRC_RES_3_A_IVB  (dev_priv->info->display_mmio_offset + 0x6006c)
+#define _PIPE_CRC_RES_4_A_IVB  (dev_priv->info->display_mmio_offset + 0x60070)
+#define _PIPE_CRC_RES_5_A_IVB  (dev_priv->info->display_mmio_offset + 0x60074)
+
+/* Pipe B CRC regs */
+#define _PIPE_CRC_CTL_B                (dev_priv->info->display_mmio_offset + 0x61050)
+#define _PIPE_CRC_RES_1_B_IVB  (dev_priv->info->display_mmio_offset + 0x61064)
+#define _PIPE_CRC_RES_2_B_IVB  (dev_priv->info->display_mmio_offset + 0x61068)
+#define _PIPE_CRC_RES_3_B_IVB  (dev_priv->info->display_mmio_offset + 0x6106c)
+#define _PIPE_CRC_RES_4_B_IVB  (dev_priv->info->display_mmio_offset + 0x61070)
+#define _PIPE_CRC_RES_5_B_IVB  (dev_priv->info->display_mmio_offset + 0x61074)
+
+#define PIPE_CRC_CTL(pipe)     _PIPE(pipe, _PIPE_CRC_CTL_A, _PIPE_CRC_CTL_B)
+#define PIPE_CRC_RES_1_IVB(pipe)       \
+       _PIPE(pipe, _PIPE_CRC_RES_1_A_IVB, _PIPE_CRC_RES_1_B_IVB)
+#define PIPE_CRC_RES_2_IVB(pipe)       \
+       _PIPE(pipe, _PIPE_CRC_RES_2_A_IVB, _PIPE_CRC_RES_2_B_IVB)
+#define PIPE_CRC_RES_3_IVB(pipe)       \
+       _PIPE(pipe, _PIPE_CRC_RES_3_A_IVB, _PIPE_CRC_RES_3_B_IVB)
+#define PIPE_CRC_RES_4_IVB(pipe)       \
+       _PIPE(pipe, _PIPE_CRC_RES_4_A_IVB, _PIPE_CRC_RES_4_B_IVB)
+#define PIPE_CRC_RES_5_IVB(pipe)       \
+       _PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB)
+
 /* Pipe A timing regs */
 #define _HTOTAL_A      (dev_priv->info->display_mmio_offset + 0x60000)
 #define _HBLANK_A      (dev_priv->info->display_mmio_offset + 0x60004)
 #define _BCLRPAT_B     (dev_priv->info->display_mmio_offset + 0x61020)
 #define _VSYNCSHIFT_B  (dev_priv->info->display_mmio_offset + 0x61028)
 
-
 #define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B)
 #define HBLANK(trans) _TRANSCODER(trans, _HBLANK_A, _HBLANK_B)
 #define HSYNC(trans) _TRANSCODER(trans, _HSYNC_A, _HSYNC_B)