[Intel-gfx] [PATCH 11/62] drm/i915/bdw: Implement interrupt changes

Daniel Vetter daniel at ffwll.ch
Wed Nov 6 09:39:37 CET 2013


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 at 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 at bwidawsk.net> (v4)
> Signed-off-by: Daniel Vetter <daniel.vetter at 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



More information about the Intel-gfx mailing list