On Tue, Oct 15, 2013 at 06:55:27PM +0100, Damien Lespiau wrote: > From: Shuang He <shuang.he@xxxxxxxxx> > > 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@xxxxxxxxx> > Signed-off-by: Damien Lespiau <damien.lespiau@xxxxxxxxx> > --- > 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@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx