On Tue, Oct 15, 2013 at 06:55:27PM +0100, Damien Lespiau wrote:
> From: Shuang He <shuang...@intel.com>
> 
> 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...@intel.com>
> Signed-off-by: Damien Lespiau <damien.lesp...@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c | 33 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/i915_drv.h     | 16 ++++++++++++++++
>  drivers/gpu/drm/i915/i915_irq.c     | 35 +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/i915_reg.h     | 36 +++++++++++++++++++++++++++++++++++-
>  4 files changed, 119 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c 
> b/drivers/gpu/drm/i915/i915_debugfs.c
> index 72d0458..e1d45aa 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -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)
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 6106d3d..6855d91 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1219,6 +1219,18 @@ 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];
> +     enum intel_pipe_crc_source source;
> +     atomic_t slot;
> +};
> +
>  typedef struct drm_i915_private {
>       struct drm_device *dev;
>       struct kmem_cache *slab;
> @@ -1423,6 +1435,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

Should we keep this in intel_crtc perhaps?

>  } drm_i915_private_t;
>  
>  static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 26753b6..d2074f1 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -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;

Looks like using atomic_t for 'slot' doesn't really help us in any way.

> +     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);
>  }
>  
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 13153c3..4d01eaf 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -722,8 +722,11 @@
>  #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))
>  
> @@ -1835,6 +1838,38 @@
>   * 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)
> @@ -1857,7 +1892,6 @@
>  #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)
> -- 
> 1.8.3.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to