[Intel-gfx] [PATCH v2 1/4] drm/i915: Ack interrupts before handling them (GEN5 - GEN7)

Chris Wilson chris at chris-wilson.co.uk
Mon Jun 16 16:25:22 CEST 2014


On Mon, Jun 16, 2014 at 03:09:24PM +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.
> 
> According to BSPec, the right order should be:
> 
> 1 - Disable Master Interrupt Control.
> 2 - Find the source(s) of the interrupt.
> 3 - 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).
> 
> We maintain the "disable SDE interrupts when handling" hack since apparently it works.
> 
> 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.
> 
> Signed-off-by: Oscar Mateo <oscar.mateo at intel.com>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 5522cbf..7e9fba0 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2147,7 +2147,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
>  	 * do any I915_{READ,WRITE}. */
>  	intel_uncore_check_errors(dev);
>  
> -	/* disable master interrupt before clearing iir  */
> +	/* 1 - Disable master interrupt */

Sorry to be a nuisance, but I was thinking of more of theory of
operation block at the start of the function as well.

/* To handle irqs with the minimum of potential races with fresh
 * interrupts, we
 * 1 - Disable Master Interrupt Control.
 * 2 - Find the source(s) of the interrupt.
 * 3 - Clear the Interrupt Identity bits (IIR).
 * 4 - Process the interrupt(s) that had bits set in the IIRs.
 * 5 - Re-enable Master Interrupt Control.
 */

Since we have a number of similar irq handlers this can be in a comment
block in just the first handler. And then we leave condensed reminders
in each function. Actually it may work best with this t.o.p. repeated
each time.

>  	de_ier = I915_READ(DEIER);
>  	I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
>  	POSTING_READ(DEIER);
> @@ -2163,37 +2163,43 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
>  		POSTING_READ(SDEIER);
>  	}
>  
> +	/* 2 - Find the source(s) of the interrupt. */

/* Find, clear, then process each source of interrupt */

Then drop 3, 4 since we have the overview block and the ordering reminder
here.
>  	gt_iir = I915_READ(GTIIR);
>  	if (gt_iir) {
> +		/* 3 - Clear the Interrupt Identity bits (IIR) before trying to
> +		 * handle the interrupt (we have the IIR safely stored) */
> +		I915_WRITE(GTIIR, gt_iir);
> +		ret = IRQ_HANDLED;
> +		/* 4 - Process the interrupt(s) that had bits set in the IIRs. */
>  		if (INTEL_INFO(dev)->gen >= 6)
>  			snb_gt_irq_handler(dev, dev_priv, gt_iir);
>  		else
>  			ilk_gt_irq_handler(dev, dev_priv, gt_iir);
> -		I915_WRITE(GTIIR, gt_iir);
> -		ret = IRQ_HANDLED;
>  	}
>  
>  	de_iir = I915_READ(DEIIR);
>  	if (de_iir) {
> +		I915_WRITE(DEIIR, de_iir);
> +		ret = IRQ_HANDLED;
>  		if (INTEL_INFO(dev)->gen >= 7)
>  			ivb_display_irq_handler(dev, de_iir);
>  		else
>  			ilk_display_irq_handler(dev, de_iir);
> -		I915_WRITE(DEIIR, de_iir);
> -		ret = IRQ_HANDLED;
>  	}
>  
>  	if (INTEL_INFO(dev)->gen >= 6) {
>  		u32 pm_iir = I915_READ(GEN6_PMIIR);
>  		if (pm_iir) {
> -			gen6_rps_irq_handler(dev_priv, pm_iir);
>  			I915_WRITE(GEN6_PMIIR, pm_iir);
>  			ret = IRQ_HANDLED;
> +			gen6_rps_irq_handler(dev_priv, pm_iir);
>  		}
>  	}
>  
> +	/* 5 - Re-enable Master Interrupt Control */
/* Finally re-enable the master interrupt */
>  	I915_WRITE(DEIER, de_ier);
>  	POSTING_READ(DEIER);
> +
>  	if (!HAS_PCH_NOP(dev)) {
>  		I915_WRITE(SDEIER, sde_ier);
>  		POSTING_READ(SDEIER);

-- 
Chris Wilson, Intel Open Source Technology Centre



More information about the Intel-gfx mailing list