Re: [PATCH 11/62] drm/i915/bdw: Implement interrupt changes

Daniel Vetter
2013-11-06T08:39:11Z

On Sat, Nov 02, 2013 at 09:07:09PM -0700, Ben Widawsky wrote:
> The interrupt handling implementation remains the same as previous
> generations with the 4 types of registers, status, identity, mask, and
> enable. However the layout of where the bits go have changed entirely.
> To address these changes, all of the interrupt vfuncs needed special
> gen8 code.
>
> The way it works is there is a top level status register now which
> informs the interrupt service routine which unit caused the interrupt,
> and therefore which interrupt registers to read to process the
> interrupt. For display the division is quite logical, a set of interrupt
> registers for each pipe, and in addition to those, a set each for "misc"
> and port.
>
> For GT the things get a bit hairy, as seen by the code. Each of the GT
> units has it's own bits defined. They all look *very similar* and
> resides in 16 bits of a GT register. As an example, RCS and BCS share
> register 0. To compact the code a bit, at a slight expense to
> complexity, this is exactly how the code works as well. 2 structures are
> added to the ring buffer so that our ring buffer interrupt handling code
> knows which ring shares the interrupt registers, and a shift value (ie.
> the top or bottom 16 bits of the register).
>
> The above allows us to kept the interrupt register caching scheme, the
> per interrupt enables, and the code to mask and unmask interrupts
> relatively clean (again at the cost of some more complexity).
>
> Most of the GT units mentioned above are command streamers, and so the
> symmetry should work quite well for even the yet to be implemented rings
> which Broadwell adds.
>
> v2: Fixes up a couple of bugs, and is more verbose about errors in the
> Broadwell interrupt handler.
>
> v3: fix DE_MISC IER offset
>
> v4: Simplify interrupts:
> I totally misread the docs the first time I implemented interrupts, and
> so this should greatly simplify the mess. Unlike GEN6, we never touch
> the regular mask registers in irq_get/put.
>
> v5: Rebased on to of recent pch hotplug setup changes.
>
> v6: Fixup on top of moving num_pipes to intel_info.
>
> v7: Rebased on top of Egbert Eich's hpd irq handling rework. Also
> wired up ibx_hpd_irq_setup for gen8.
>
> v8: Rebase on top of Jani's asle handling rework.
>
> v9: Rebase on top of Ben's VECS enabling for Haswell, where he
> unfortunately went OCD on the gt irq #defines. Not that they're still
> not yet fully consistent:
> - Used the GT_RENDER_ #defines + bdw shifts.
> - Dropped the shift from the L3_PARITY stuff, seemed clearer.
> - s/irq_refcount/irq_refcount.gt/
>
> v10: Squash in VECS enabling patches and the gen8_gt_irq_handler
> refactoring from Zhao Yakui <yakui.zhao@intel.com>
>
> v11: Rebase on top of the interrupt cleanups in upstream.
>
> v12: Rebase on top of Ben's DPF changes in upstream.
>
> v13: Drop bdw from the HAS_L3_DPF feature flag for now, it's unclear what
> exactly needs to be done. Requested by Ben.
>
> Signed-off-by: Ben Widawsky <ben@bwidawsk.net> (v4)
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

I've had to fix quite a few things here, and I've made myself a todo for
patches to write on top of this one here. See the v14 changelog entry.
-Daniel

> ---
> drivers/gpu/drm/i915/i915_drv.h | 5 +-
> drivers/gpu/drm/i915/i915_irq.c | 327 ++++++++++++++++++++++++++++++++
> drivers/gpu/drm/i915/i915_reg.h | 63 ++++++
> drivers/gpu/drm/i915/intel_ringbuffer.c | 90 +++++++--
> 4 files changed, 473 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index c1b178a..83d016c 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1315,7 +1315,10 @@ typedef struct drm_i915_private {
> struct mutex dpio_lock;
>
> /** Cached value of IMR to avoid reads in updating the bitfield */
> - u32 irq_mask;
> + union {
> + u32 irq_mask;
> + u32 de_irq_mask[I915_MAX_PIPES];
> + };
> u32 gt_irq_mask;
> u32 pm_irq_mask;
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index a9f0cb6..3f0c9e3 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1118,6 +1118,56 @@ static void snb_gt_irq_handler(struct drm_device *dev,
> ivybridge_parity_error_irq_handler(dev, gt_iir);
> }
>
> +static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
> + struct drm_i915_private *dev_priv,
> + u32 master_ctl)
> +{
> + u32 rcs, bcs, vcs;
> + uint32_t tmp = 0;
> + irqreturn_t ret = IRQ_NONE;
> +
> + if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
> + tmp = I915_READ(GEN8_GT_IIR(0));
> + if (tmp) {
> + ret = IRQ_HANDLED;
> + rcs = tmp >> GEN8_RCS_IRQ_SHIFT;
> + bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
> + if (rcs & GT_RENDER_USER_INTERRUPT)
> + notify_ring(dev, &dev_priv->ring[RCS]);
> + if (bcs & GT_RENDER_USER_INTERRUPT)
> + notify_ring(dev, &dev_priv->ring[BCS]);
> + I915_WRITE(GEN8_GT_IIR(0), tmp);
> + } else
> + DRM_ERROR("The master control interrupt lied (GT0)!\n");
> + }
> +
> + if (master_ctl & GEN8_GT_VCS1_IRQ) {
> + tmp = I915_READ(GEN8_GT_IIR(1));
> + if (tmp) {
> + ret = IRQ_HANDLED;
> + vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
> + if (vcs & GT_RENDER_USER_INTERRUPT)
> + notify_ring(dev, &dev_priv->ring[VCS]);
> + I915_WRITE(GEN8_GT_IIR(1), tmp);
> + } else
> + DRM_ERROR("The master control interrupt lied (GT1)!\n");
> + }
> +
> + if (master_ctl & GEN8_GT_VECS_IRQ) {
> + tmp = I915_READ(GEN8_GT_IIR(3));
> + if (tmp) {
> + ret = IRQ_HANDLED;
> + vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
> + if (vcs & GT_RENDER_USER_INTERRUPT)
> + notify_ring(dev, &dev_priv->ring[VECS]);
> + I915_WRITE(GEN8_GT_IIR(3), tmp);
> + } else
> + DRM_ERROR("The master control interrupt lied (GT3)!\n");
> + }
> +
> + return ret;
> +}
> +
> #define HPD_STORM_DETECT_PERIOD 1000
> #define HPD_STORM_THRESHOLD 5
>
> @@ -1699,6 +1749,85 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
> return ret;
> }
>
> +static irqreturn_t gen8_irq_handler(int irq, void *arg)
> +{
> + struct drm_device *dev = arg;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + u32 master_ctl;
> + irqreturn_t ret = IRQ_NONE;
> + uint32_t tmp = 0;
> +
> + atomic_inc(&dev_priv->irq_received);
> +
> + master_ctl = I915_READ(GEN8_MASTER_IRQ);
> + master_ctl &= ~DE_MASTER_IRQ_CONTROL;
> + if (!master_ctl)
> + return IRQ_NONE;
> +
> + if ((master_ctl & ~GEN8_RSVD_IRQS) == 0) {
> + DRM_ERROR("Only received RSVD IRQs 0x%08x\n", master_ctl);
> + return IRQ_NONE;
> + }
> +
> + I915_WRITE(GEN8_MASTER_IRQ, 0);
> +
> + /* NB: Posting read isn't necessary here because we're required to do
> + * another read no matter what
> + POSTING_READ(GEN8_MASTER_IRQ);
> + */
> +
> + ret = gen8_gt_irq_handler(dev, dev_priv, master_ctl);
> +
> + if (master_ctl & GEN8_DE_MISC_IRQ) {
> + tmp = I915_READ(GEN8_DE_MISC_IIR);
> + if (tmp) {
> + I915_WRITE(GEN8_DE_MISC_IIR, tmp);
> + ret = IRQ_HANDLED;
> + }
> +
> + if (tmp & GEN8_DE_MISC_GSE)
> + intel_opregion_asle_intr(dev);
> + else if (tmp)
> + DRM_ERROR("Unexpected DE Misc interrupt\n");
> + else
> + DRM_ERROR("The master control interrupt lied (DE MISC)!\n");
> +
> + }
> +
> + if (master_ctl & GEN8_DE_IRQS) {
> + int de_ret = 0;
> + int pipe;
> + for_each_pipe(pipe) {
> + uint32_t pipe_iir;
> +
> + pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
> + if (pipe_iir & _PIPE_VBLANK) {
> + drm_handle_vblank(dev, pipe);
> + }
> + if (pipe_iir & _PIPE_FLIP_DONE) {
> + intel_prepare_page_flip(dev, pipe);
> + intel_finish_page_flip_plane(dev, pipe);
> + }
> +
> + if (pipe_iir & GEN8_DE_PIPE_IRQ_ERRORS)
> + DRM_ERROR("Errors on pipe %c\n", 'A' + pipe);
> +
> + if (pipe_iir) {
> + de_ret++;
> + ret = IRQ_HANDLED;
> + I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
> + }
> + }
> + if (!de_ret)
> + DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
> + }
> +
> + I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
> + POSTING_READ(GEN8_MASTER_IRQ);
> +
> + return ret;
> +}
> +
> static void i915_error_wake_up(struct drm_i915_private *dev_priv,
> bool reset_completed)
> {
> @@ -2052,6 +2181,25 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
> return 0;
> }
>
> +static int gen8_enable_vblank(struct drm_device *dev, int pipe)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + unsigned long irqflags;
> + uint32_t imr;
> +
> + if (!i915_pipe_enabled(dev, pipe))
> + return -EINVAL;
> +
> + spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> + imr = I915_READ(GEN8_DE_PIPE_IMR(pipe));
> + if ((imr & _PIPE_VBLANK) == 1) {
> + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), imr & ~_PIPE_VBLANK);
> + POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
> + }
> + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> + return 0;
> +}
> +
> /* Called from drm generic code, passed 'crtc' which
> * we use as a pipe index
> */
> @@ -2100,6 +2248,24 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
> spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> }
>
> +static void gen8_disable_vblank(struct drm_device *dev, int pipe)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + unsigned long irqflags;
> + uint32_t imr;
> +
> + if (!i915_pipe_enabled(dev, pipe))
> + return;
> +
> + spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> + imr = I915_READ(GEN8_DE_PIPE_IMR(pipe));
> + if ((imr & _PIPE_VBLANK) == 0) {
> + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), imr | _PIPE_VBLANK);
> + POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
> + }
> + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +}
> +
> static u32
> ring_last_seqno(struct intel_ring_buffer *ring)
> {
> @@ -2430,6 +2596,51 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
> POSTING_READ(VLV_IER);
> }
>
> +static void gen8_irq_preinstall(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + int pipe;
> +
> + atomic_set(&dev_priv->irq_received, 0);
> +
> + I915_WRITE(GEN8_MASTER_IRQ, 0);
> + POSTING_READ(GEN8_MASTER_IRQ);
> +
> + /* IIR can theoretically queue up two events. Be paranoid */
> +#define GEN8_IRQ_INIT_NDX(type, which) \
> + I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
> + POSTING_READ(GEN8_##type##_IMR(which)); \
> + I915_WRITE(GEN8_##type##_IER(which), 0); \
> + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
> + POSTING_READ(GEN8_##type##_IIR(which)); \
> + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff)
> +
> +#define GEN8_IRQ_INIT(type) \
> + I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \
> + POSTING_READ(GEN8_##type##_IMR); \
> + I915_WRITE(GEN8_##type##_IER, 0); \
> + I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
> + POSTING_READ(GEN8_##type##_IIR); \
> + I915_WRITE(GEN8_##type##_IIR, 0xffffffff)
> +
> + GEN8_IRQ_INIT_NDX(GT, 0);
> + GEN8_IRQ_INIT_NDX(GT, 1);
> + GEN8_IRQ_INIT_NDX(GT, 2);
> + GEN8_IRQ_INIT_NDX(GT, 3);
> +
> + for_each_pipe(pipe) {
> + GEN8_IRQ_INIT_NDX(DE_PIPE, pipe);
> + }
> +
> + GEN8_IRQ_INIT(DE_PORT);
> + GEN8_IRQ_INIT(DE_MISC);
> + GEN8_IRQ_INIT(PCU);
> +#undef GEN8_IRQ_INIT
> +#undef GEN8_IRQ_INIT_NDX
> +
> + POSTING_READ(GEN8_PCU_IIR);
> +}
> +
> static void ibx_hpd_irq_setup(struct drm_device *dev)
> {
> drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> @@ -2635,6 +2846,114 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
> return 0;
> }
>
> +static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
> +{
> + int i;
> +
> + /* These are interrupts we'll toggle with the ring mask register */
> + uint32_t gt_interrupts[] = {
> + GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
> + GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
> + GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
> + GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
> + GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
> + 0,
> + GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
> + };
> +
> + for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) {
> + u32 tmp = I915_READ(GEN8_GT_IIR(i));
> + if (tmp)
> + DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n",
> + i, tmp);
> + I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]);
> + I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]);
> + }
> + POSTING_READ(GEN8_GT_IER(0));
> +}
> +
> +static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + uint32_t de_pipe_enables = _PIPE_FLIP_DONE |
> + _PIPE_SCAN_LINE_EVENT |
> + _PIPE_VBLANK |
> + GEN8_DE_PIPE_IRQ_ERRORS;
> + int pipe;
> + dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_enables;
> + dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_enables;
> + dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_enables;
> +
> + for_each_pipe(pipe) {
> + u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe));
> + if (tmp)
> + DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n",
> + pipe, tmp);
> + I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
> + I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables);
> + }
> + POSTING_READ(GEN8_DE_PIPE_ISR(0));
> +
> + I915_WRITE(GEN8_DE_PORT_IMR, ~_PORT_DP_A_HOTPLUG);
> + I915_WRITE(GEN8_DE_PORT_IER, _PORT_DP_A_HOTPLUG);
> + POSTING_READ(GEN8_DE_PORT_IER);
> +}
> +
> +static int gen8_irq_postinstall(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> +
> + gen8_gt_irq_postinstall(dev_priv);
> + gen8_de_irq_postinstall(dev_priv);
> +
> + ibx_irq_postinstall(dev);
> +
> + I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
> + POSTING_READ(GEN8_MASTER_IRQ);
> +
> + return 0;
> +}
> +
> +static void gen8_irq_uninstall(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + int pipe;
> +
> + if (!dev_priv)
> + return;
> +
> + atomic_set(&dev_priv->irq_received, 0);
> +
> + I915_WRITE(GEN8_MASTER_IRQ, 0);
> +
> +#define GEN8_IRQ_FINI_NDX(type, which) \
> + I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
> + I915_WRITE(GEN8_##type##_IER(which), 0); \
> + I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff)
> +
> +#define GEN8_IRQ_FINI(type) \
> + I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \
> + I915_WRITE(GEN8_##type##_IER, 0); \
> + I915_WRITE(GEN8_##type##_IIR, 0xffffffff)
> +
> + GEN8_IRQ_FINI_NDX(GT, 0);
> + GEN8_IRQ_FINI_NDX(GT, 1);
> + GEN8_IRQ_FINI_NDX(GT, 2);
> + GEN8_IRQ_FINI_NDX(GT, 3);
> +
> + for_each_pipe(pipe) {
> + GEN8_IRQ_FINI_NDX(DE_PIPE, pipe);
> + }
> +
> + GEN8_IRQ_FINI(DE_PORT);
> + GEN8_IRQ_FINI(DE_MISC);
> + GEN8_IRQ_FINI(PCU);
> +#undef GEN8_IRQ_FINI
> +#undef GEN8_IRQ_FINI_NDX
> +
> + POSTING_READ(GEN8_PCU_IIR);
> +}
> +
> static void valleyview_irq_uninstall(struct drm_device *dev)
> {
> drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> @@ -3414,6 +3733,14 @@ void intel_irq_init(struct drm_device *dev)
> dev->driver->enable_vblank = valleyview_enable_vblank;
> dev->driver->disable_vblank = valleyview_disable_vblank;
> dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
> + } else if (IS_GEN8(dev)) {
> + dev->driver->irq_handler = gen8_irq_handler;
> + dev->driver->irq_preinstall = gen8_irq_preinstall;
> + dev->driver->irq_postinstall = gen8_irq_postinstall;
> + dev->driver->irq_uninstall = gen8_irq_uninstall;
> + dev->driver->enable_vblank = gen8_enable_vblank;
> + dev->driver->disable_vblank = gen8_disable_vblank;
> + dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
> } else if (HAS_PCH_SPLIT(dev)) {
> dev->driver->irq_handler = ironlake_irq_handler;
> dev->driver->irq_preinstall = ironlake_irq_preinstall;
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index fb6ad89..b801b88 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -3989,6 +3989,69 @@
> #define GTIIR 0x44018
> #define GTIER 0x4401c
>
> +#define GEN8_MASTER_IRQ 0x44200
> +#define GEN8_PCU_IRQ (1<<30)
> +#define GEN8_DE_PCH_IRQ (1<<23)
> +#define GEN8_DE_MISC_IRQ (1<<22)
> +#define GEN8_DE_PORT_IRQ (1<<20)
> +#define GEN8_DE_PIPE_C_IRQ (1<<18)
> +#define GEN8_DE_PIPE_B_IRQ (1<<17)
> +#define GEN8_DE_PIPE_A_IRQ (1<<16)
> +#define GEN8_GT_VECS_IRQ (1<<6)
> +#define GEN8_GT_VCS2_IRQ (1<<3)
> +#define GEN8_GT_VCS1_IRQ (1<<2)
> +#define GEN8_GT_BCS_IRQ (1<<1)
> +#define GEN8_GT_RCS_IRQ (1<<0)
> +/* Lazy definition */
> +#define GEN8_GT_IRQS 0x000000ff
> +#define GEN8_DE_IRQS 0x01ff0000
> +#define GEN8_RSVD_IRQS 0xB700ff00
> +
> +#define GEN8_GT_ISR(which) (0x44300 + (0x10 * (which)))
> +#define GEN8_GT_IMR(which) (0x44304 + (0x10 * (which)))
> +#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
> +#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
> +
> +#define GEN8_BCS_IRQ_SHIFT 16
> +#define GEN8_RCS_IRQ_SHIFT 0
> +#define GEN8_VCS2_IRQ_SHIFT 16
> +#define GEN8_VCS1_IRQ_SHIFT 0
> +#define GEN8_VECS_IRQ_SHIFT 0
> +
> +#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
> +#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
> +#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe)))
> +#define GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe)))
> +#define _PIPE_UNDERRUN (1 << 31)
> +#define _PIPE_CDCLK_CRC_ERROR (1 << 29)
> +#define _PIPE_CURSOR_FAULT (1 << 10)
> +#define _PIPE_SPRITE_FAULT (1 << 9)
> +#define _PIPE_PRIMARY_FAULT (1 << 8)
> +#define _PIPE_SPRITE_FLIP_DONE (1 << 5)
> +#define _PIPE_FLIP_DONE (1 << 4)
> +#define _PIPE_SCAN_LINE_EVENT (1 << 3)
> +#define _PIPE_VBLANK (1 << 0)
> +#define GEN8_DE_PIPE_IRQ_ERRORS (_PIPE_UNDERRUN | _PIPE_CDCLK_CRC_ERROR | \
> + _PIPE_CURSOR_FAULT | _PIPE_SPRITE_FAULT | \
> + _PIPE_PRIMARY_FAULT)
> +
> +#define GEN8_DE_PORT_ISR 0x44440
> +#define GEN8_DE_PORT_IMR 0x44444
> +#define GEN8_DE_PORT_IIR 0x44448
> +#define GEN8_DE_PORT_IER 0x4444c
> +#define _PORT_DP_A_HOTPLUG (1 << 3)
> +
> +#define GEN8_DE_MISC_ISR 0x44460
> +#define GEN8_DE_MISC_IMR 0x44464
> +#define GEN8_DE_MISC_IIR 0x44468
> +#define GEN8_DE_MISC_IER 0x4446c
> +#define GEN8_DE_MISC_GSE (1 << 27)
> +
> +#define GEN8_PCU_ISR 0x444e0
> +#define GEN8_PCU_IMR 0x444e4
> +#define GEN8_PCU_IIR 0x444e8
> +#define GEN8_PCU_IER 0x444ec
> +
> #define ILK_DISPLAY_CHICKEN2 0x42004
> /* Required on all Ironlake and Sandybridge according to the B-Spec. */
> #define ILK_ELPIN_409_SELECT (1 << 25)
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 2dec134..b2161f2 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1066,6 +1066,48 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
> spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
> }
>
> +static bool
> +gen8_ring_get_irq(struct intel_ring_buffer *ring)
> +{
> + struct drm_device *dev = ring->dev;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + unsigned long flags;
> +
> + if (!dev->irq_enabled)
> + return false;
> +
> + spin_lock_irqsave(&dev_priv->irq_lock, flags);
> + if (ring->irq_refcount++ == 0) {
> + if (HAS_L3_DPF(dev) && ring->id == RCS)
> + I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
> + GT_RENDER_L3_PARITY_ERROR_INTERRUPT));
> + else
> + I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
> + POSTING_READ(RING_IMR(ring->mmio_base));
> + }
> + spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
> +
> + return true;
> +}
> +
> +static void
> +gen8_ring_put_irq(struct intel_ring_buffer *ring)
> +{
> + struct drm_device *dev = ring->dev;
> + drm_i915_private_t *dev_priv = dev->dev_private;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dev_priv->irq_lock, flags);
> + if (--ring->irq_refcount == 0) {
> + if (HAS_L3_DPF(dev) && ring->id == RCS)
> + I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
> + else
> + I915_WRITE_IMR(ring, ~0);
> + POSTING_READ(RING_IMR(ring->mmio_base));
> + }
> + spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
> +}
> +
> static int
> i965_dispatch_execbuffer(struct intel_ring_buffer *ring,
> u32 offset, u32 length,
> @@ -1732,8 +1774,13 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
> ring->flush = gen7_render_ring_flush;
> if (INTEL_INFO(dev)->gen == 6)
> ring->flush = gen6_render_ring_flush;
> - ring->irq_get = gen6_ring_get_irq;
> - ring->irq_put = gen6_ring_put_irq;
> + if (INTEL_INFO(dev)->gen >= 8) {
> + ring->irq_get = gen8_ring_get_irq;
> + ring->irq_put = gen8_ring_put_irq;
> + } else {
> + ring->irq_get = gen6_ring_get_irq;
> + ring->irq_put = gen6_ring_put_irq;
> + }
> ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
> ring->get_seqno = gen6_ring_get_seqno;
> ring->set_seqno = ring_set_seqno;
> @@ -1897,9 +1944,15 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
> ring->add_request = gen6_add_request;
> ring->get_seqno = gen6_ring_get_seqno;
> ring->set_seqno = ring_set_seqno;
> - ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
> - ring->irq_get = gen6_ring_get_irq;
> - ring->irq_put = gen6_ring_put_irq;
> + if (INTEL_INFO(dev)->gen >= 8) {
> + ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
> + ring->irq_get = gen8_ring_get_irq;
> + ring->irq_put = gen8_ring_put_irq;
> + } else {
> + ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
> + ring->irq_get = gen6_ring_get_irq;
> + ring->irq_put = gen6_ring_put_irq;
> + }
> ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
> ring->sync_to = gen6_ring_sync;
> ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR;
> @@ -1946,9 +1999,15 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
> ring->add_request = gen6_add_request;
> ring->get_seqno = gen6_ring_get_seqno;
> ring->set_seqno = ring_set_seqno;
> - ring->irq_enable_mask = GT_BLT_USER_INTERRUPT;
> - ring->irq_get = gen6_ring_get_irq;
> - ring->irq_put = gen6_ring_put_irq;
> + if (INTEL_INFO(dev)->gen >= 8) {
> + ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
> + ring->irq_get = gen8_ring_get_irq;
> + ring->irq_put = gen8_ring_put_irq;
> + } else {
> + ring->irq_enable_mask = GT_BLT_USER_INTERRUPT;
> + ring->irq_get = gen6_ring_get_irq;
> + ring->irq_put = gen6_ring_put_irq;
> + }
> ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
> ring->sync_to = gen6_ring_sync;
> ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR;
> @@ -1978,10 +2037,19 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev)
> ring->add_request = gen6_add_request;
> ring->get_seqno = gen6_ring_get_seqno;
> ring->set_seqno = ring_set_seqno;
> - ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
> - ring->irq_get = hsw_vebox_get_irq;
> - ring->irq_put = hsw_vebox_put_irq;
> ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
> +
> + if (INTEL_INFO(dev)->gen >= 8) {
> + ring->irq_enable_mask =
> + (GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT) |
> + GT_RENDER_CS_MASTER_ERROR_INTERRUPT;
> + ring->irq_get = gen8_ring_get_irq;
> + ring->irq_put = gen8_ring_put_irq;
> + } else {
> + ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
> + ring->irq_get = hsw_vebox_get_irq;
> + ring->irq_put = hsw_vebox_put_irq;
> + }
> ring->sync_to = gen6_ring_sync;
> ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER;
> ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV;
> --
> 1.8.4.2
>

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch