[Intel-gfx] [PATCH v3 3/4] drm/i915/bdw: Ack interrupts before handling them (GEN8)

Daniel Vetter daniel at ffwll.ch
Wed Jun 18 00:24:37 CEST 2014


On Mon, Jun 16, 2014 at 04:10:59PM +0100, oscar.mateo at intel.com wrote:
> From: Oscar Mateo <oscar.mateo at intel.com>
> 
> Otherwise, we might receive a new interrupt before we have time to
> ack the first one, eventually missing it.
> 
> The right order should be:
> 
> 1 - Disable Master Interrupt Control.
> 2 - Find the category of interrupt that is pending.
> 3 - Find the source(s) of the interrupt and clear the Interrupt Identity bits (IIR)
> 4 - Process the interrupt(s) that had bits set in the IIRs.
> 5 - Re-enable Master Interrupt Control.
> 
> Without an atomic XCHG operation with mmio space, the above merely reduces the window
> in which we can miss an interrupt (especially when you consider how heavyweight the
> I915_READ/I915_WRITE operations are).
> 
> Spotted by Bob Beckett <robert.beckett at intel.com>.
> 
> v2: Add warning to commit message and comments to the code as per Chris Wilson's request.
> 
> v3: Improve the source code comment.
> 
> Signed-off-by: Oscar Mateo <oscar.mateo at intel.com>

This one had a small conflict with Chris' stall detection patch that I
fixed up while applying. Entire series merged, thanks.
-Daniel

> ---
>  drivers/gpu/drm/i915/i915_irq.c | 91 ++++++++++++++++++++---------------------
>  1 file changed, 45 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 20f7c05..46fe3ad 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1462,6 +1462,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>  	if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
>  		tmp = I915_READ(GEN8_GT_IIR(0));
>  		if (tmp) {
> +			I915_WRITE(GEN8_GT_IIR(0), tmp);
>  			ret = IRQ_HANDLED;
>  			rcs = tmp >> GEN8_RCS_IRQ_SHIFT;
>  			bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
> @@ -1469,7 +1470,6 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>  				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");
>  	}
> @@ -1477,6 +1477,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>  	if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
>  		tmp = I915_READ(GEN8_GT_IIR(1));
>  		if (tmp) {
> +			I915_WRITE(GEN8_GT_IIR(1), tmp);
>  			ret = IRQ_HANDLED;
>  			vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
>  			if (vcs & GT_RENDER_USER_INTERRUPT)
> @@ -1484,7 +1485,6 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>  			vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
>  			if (vcs & GT_RENDER_USER_INTERRUPT)
>  				notify_ring(dev, &dev_priv->ring[VCS2]);
> -			I915_WRITE(GEN8_GT_IIR(1), tmp);
>  		} else
>  			DRM_ERROR("The master control interrupt lied (GT1)!\n");
>  	}
> @@ -1492,10 +1492,10 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>  	if (master_ctl & GEN8_GT_PM_IRQ) {
>  		tmp = I915_READ(GEN8_GT_IIR(2));
>  		if (tmp & dev_priv->pm_rps_events) {
> -			ret = IRQ_HANDLED;
> -			gen8_rps_irq_handler(dev_priv, tmp);
>  			I915_WRITE(GEN8_GT_IIR(2),
>  				   tmp & dev_priv->pm_rps_events);
> +			ret = IRQ_HANDLED;
> +			gen8_rps_irq_handler(dev_priv, tmp);
>  		} else
>  			DRM_ERROR("The master control interrupt lied (PM)!\n");
>  	}
> @@ -1503,11 +1503,11 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
>  	if (master_ctl & GEN8_GT_VECS_IRQ) {
>  		tmp = I915_READ(GEN8_GT_IIR(3));
>  		if (tmp) {
> +			I915_WRITE(GEN8_GT_IIR(3), 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");
>  	}
> @@ -2238,36 +2238,36 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
>  	I915_WRITE(GEN8_MASTER_IRQ, 0);
>  	POSTING_READ(GEN8_MASTER_IRQ);
>  
> +	/* Find, clear, then process each source of interrupt */
> +
>  	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 & 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 (tmp) {
>  			I915_WRITE(GEN8_DE_MISC_IIR, tmp);
>  			ret = IRQ_HANDLED;
> +			if (tmp & GEN8_DE_MISC_GSE)
> +				intel_opregion_asle_intr(dev);
> +			else
> +				DRM_ERROR("Unexpected DE Misc interrupt\n");
>  		}
> +		else
> +			DRM_ERROR("The master control interrupt lied (DE MISC)!\n");
>  	}
>  
>  	if (master_ctl & GEN8_DE_PORT_IRQ) {
>  		tmp = I915_READ(GEN8_DE_PORT_IIR);
> -		if (tmp & GEN8_AUX_CHANNEL_A)
> -			dp_aux_irq_handler(dev);
> -		else if (tmp)
> -			DRM_ERROR("Unexpected DE Port interrupt\n");
> -		else
> -			DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
> -
>  		if (tmp) {
>  			I915_WRITE(GEN8_DE_PORT_IIR, tmp);
>  			ret = IRQ_HANDLED;
> +			if (tmp & GEN8_AUX_CHANNEL_A)
> +				dp_aux_irq_handler(dev);
> +			else
> +				DRM_ERROR("Unexpected DE Port interrupt\n");
>  		}
> +		else
> +			DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
>  	}
>  
>  	for_each_pipe(pipe) {
> @@ -2277,33 +2277,32 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
>  			continue;
>  
>  		pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
> -		if (pipe_iir & GEN8_PIPE_VBLANK)
> -			intel_pipe_handle_vblank(dev, pipe);
> -
> -		if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
> -			intel_prepare_page_flip(dev, pipe);
> -			intel_finish_page_flip_plane(dev, pipe);
> -		}
> +		if (pipe_iir) {
> +			ret = IRQ_HANDLED;
> +			I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
> +			if (pipe_iir & GEN8_PIPE_VBLANK)
> +				intel_pipe_handle_vblank(dev, pipe);
>  
> -		if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE)
> -			hsw_pipe_crc_irq_handler(dev, pipe);
> +			if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
> +				intel_prepare_page_flip(dev, pipe);
> +				intel_finish_page_flip_plane(dev, pipe);
> +			}
>  
> -		if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
> -			if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
> -								  false))
> -				DRM_ERROR("Pipe %c FIFO underrun\n",
> -					  pipe_name(pipe));
> -		}
> +			if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE)
> +				hsw_pipe_crc_irq_handler(dev, pipe);
>  
> -		if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
> -			DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
> -				  pipe_name(pipe),
> -				  pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS);
> -		}
> +			if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
> +				if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
> +									  false))
> +					DRM_ERROR("Pipe %c FIFO underrun\n",
> +						  pipe_name(pipe));
> +			}
>  
> -		if (pipe_iir) {
> -			ret = IRQ_HANDLED;
> -			I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
> +			if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
> +				DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
> +					  pipe_name(pipe),
> +					  pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS);
> +			}
>  		} else
>  			DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
>  	}
> @@ -2315,13 +2314,13 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
>  		 * on older pch-split platforms. But this needs testing.
>  		 */
>  		u32 pch_iir = I915_READ(SDEIIR);
> -
> -		cpt_irq_handler(dev, pch_iir);
> -
>  		if (pch_iir) {
>  			I915_WRITE(SDEIIR, pch_iir);
>  			ret = IRQ_HANDLED;
> -		}
> +			cpt_irq_handler(dev, pch_iir);
> +		} else
> +			DRM_ERROR("The master control interrupt lied (SDE)!\n");
> +
>  	}
>  
>  	I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
> -- 
> 1.9.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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



More information about the Intel-gfx mailing list