[Intel-gfx] [PATCH 3/3] drm/i915: Skip pipestats for GT operations in chv/vlv irq handler

Ville Syrjälä ville.syrjala at linux.intel.com
Thu Sep 14 16:02:12 UTC 2017


On Wed, Sep 13, 2017 at 07:18:46PM +0100, Chris Wilson wrote:
> When handling context-switch interrupts, we are very latency sensitive;
> every unnecessary mmio (uncached) read contributes toward a large
> decrease in request throughput. An example is gem_exec_whisper, which
> ping-pongs between the engines, where avoiding the pipe underflow
> checking reduces the runtime of the test from 29s to 22s. On the other
> hand, we are now not checking for pipe underflows at 100KHz, more or
> less reducing it to a check every pageflip (60Hz) or modeset at worst.
> 
> add/remove: 0/0 grow/shrink: 1/2 up/down: 24/-40 (-16)
> function                                     old     new   delta
> valleyview_pipestat_irq_ack                  259     283     +24
> valleyview_irq_handler                       521     517      -4
> cherryview_irq_handler                       457     421     -36
> 
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
> Cc: Mika Kuoppala <mika.kuoppala at intel.com>
> Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_irq.c | 123 ++++++++++++++++++++++++----------------
>  1 file changed, 73 insertions(+), 50 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index e1d503b7352e..345d73bd4039 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1703,16 +1703,17 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
>  	}
>  }
>  
> -static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
> +static bool valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
>  					u32 iir, u32 pipe_stats[I915_MAX_PIPES])
>  {
> +	bool handled = false;
>  	int pipe;
>  
>  	spin_lock(&dev_priv->irq_lock);
>  
>  	if (!dev_priv->display_irqs_enabled) {
>  		spin_unlock(&dev_priv->irq_lock);
> -		return;
> +		return false;
>  	}
>  
>  	for_each_pipe(dev_priv, pipe) {
> @@ -1744,8 +1745,10 @@ static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
>  		if (iir & iir_bit)
>  			mask |= dev_priv->pipestat_irq_mask[pipe];
>  
> -		if (!mask)
> +		if (!mask) {
> +			pipe_stats[pipe] = 0;
>  			continue;
> +		}
>  
>  		reg = PIPESTAT(pipe);
>  		mask |= PIPESTAT_INT_ENABLE_MASK;
> @@ -1757,8 +1760,12 @@ static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
>  		if (pipe_stats[pipe] & (PIPE_FIFO_UNDERRUN_STATUS |
>  					PIPESTAT_INT_STATUS_MASK))
>  			I915_WRITE(reg, pipe_stats[pipe]);
> +
> +		handled = true;
>  	}
>  	spin_unlock(&dev_priv->irq_lock);
> +
> +	return handled;
>  }
>  
>  static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
> @@ -1836,8 +1843,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
>  
>  	do {
>  		u32 iir, gt_iir, pm_iir;
> -		u32 pipe_stats[I915_MAX_PIPES] = {};
> +		u32 pipe_stats[I915_MAX_PIPES];
>  		u32 hotplug_status = 0;
> +		bool has_pipe_stats;
>  		u32 ier = 0;
>  
>  		gt_iir = I915_READ(GTIIR);
> @@ -1876,7 +1884,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
>  
>  		/* Call regardless, as some status bits might not be
>  		 * signalled in iir */
> -		valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
> +		has_pipe_stats =
> +			valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
>  
>  		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
>  			   I915_LPE_PIPE_B_INTERRUPT))
> @@ -1901,7 +1910,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
>  		if (hotplug_status)
>  			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
>  
> -		valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
> +		if (has_pipe_stats)
> +			valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
>  	} while (0);
>  
>  	enable_rpm_wakeref_asserts(dev_priv);
> @@ -1914,27 +1924,14 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
>  	struct drm_device *dev = arg;
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	irqreturn_t ret = IRQ_NONE;
> +	u32 master_ctl;
>  
>  	if (!intel_irqs_enabled(dev_priv))
>  		return IRQ_NONE;
>  
> -	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
> -	disable_rpm_wakeref_asserts(dev_priv);
> -
> +	master_ctl = I915_READ_FW(GEN8_MASTER_IRQ);
>  	do {
> -		u32 master_ctl, iir;
> -		u32 gt_iir[4] = {};
> -		u32 pipe_stats[I915_MAX_PIPES] = {};
> -		u32 hotplug_status = 0;
> -		u32 ier = 0;
> -
> -		master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
> -		iir = I915_READ(VLV_IIR);
> -
> -		if (master_ctl == 0 && iir == 0)
> -			break;
> -
> -		ret = IRQ_HANDLED;
> +		u32 iir;
>  
>  		/*
>  		 * Theory on interrupt generation, based on empirical evidence:
> @@ -1949,44 +1946,70 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
>  		 * don't end up clearing all the VLV_IIR and GEN8_MASTER_IRQ_CONTROL
>  		 * bits this time around.
>  		 */
> -		I915_WRITE(GEN8_MASTER_IRQ, 0);
> -		ier = I915_READ(VLV_IER);
> -		I915_WRITE(VLV_IER, 0);
> +		if (master_ctl & ~GEN8_MASTER_IRQ_CONTROL) {
> +			u32 gt_iir[4];
>  
> -		gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
> +			I915_WRITE_FW(GEN8_MASTER_IRQ, 0);
>  
> -		if (iir & I915_DISPLAY_PORT_INTERRUPT)
> -			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
> +			gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
>  
> -		/* Call regardless, as some status bits might not be
> -		 * signalled in iir */
> -		valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
> +			I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
> +			ret = IRQ_HANDLED;

I suspect this won't work correctly. If I'm correct on how the edge
triggering works we really need to have both MASTER_IRQ_CONTROL and IER
disabled at the same time. Otherwise one can prevent the other from
generating an edge to the CPU interrupt logic.

>  
> -		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
> -			   I915_LPE_PIPE_B_INTERRUPT |
> -			   I915_LPE_PIPE_C_INTERRUPT))
> -			intel_lpe_audio_irq_handler(dev_priv);
> +			gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
> +			master_ctl = 0;
> +		}
>  
> -		/*
> -		 * VLV_IIR is single buffered, and reflects the level
> -		 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
> -		 */
> -		if (iir)
> -			I915_WRITE(VLV_IIR, iir);
> +		iir = I915_READ_FW(VLV_IIR);
> +		if (iir) {
> +			u32 pipe_stats[I915_MAX_PIPES];
> +			u32 hotplug_status = 0;
> +			bool has_pipe_stats = false;
> +			u32 ier;
>  
> -		I915_WRITE(VLV_IER, ier);
> -		I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
> -		POSTING_READ(GEN8_MASTER_IRQ);
> +			/*
> +			 * IRQs are synced during runtime_suspend,
> +			 * we don't require a wakeref
> +			 */
> +			disable_rpm_wakeref_asserts(dev_priv);
>  
> -		gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
>  
> -		if (hotplug_status)
> -			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
> +			ier = I915_READ_FW(VLV_IER);
> +			I915_WRITE_FW(VLV_IER, 0);
>  
> -		valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
> -	} while (0);
> +			if (iir & I915_DISPLAY_PORT_INTERRUPT)
> +				hotplug_status = i9xx_hpd_irq_ack(dev_priv);
>  
> -	enable_rpm_wakeref_asserts(dev_priv);
> +			if (iir & (I915_LPE_PIPE_A_INTERRUPT |
> +				   I915_LPE_PIPE_B_INTERRUPT |
> +				   I915_LPE_PIPE_C_INTERRUPT))
> +				intel_lpe_audio_irq_handler(dev_priv);
> +
> +			/*
> +			 * Call regardless, as some status bits might not be
> +			 * signalled in iir.
> +			 */
> +			has_pipe_stats =
> +				valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
> +
> +			/*
> +			 * VLV_IIR is single buffered, and reflects the level
> +			 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
> +			 */
> +			I915_WRITE_FW(VLV_IIR, iir);
> +			I915_WRITE_FW(VLV_IER, ier);
> +			ret = IRQ_HANDLED;
> +
> +			if (hotplug_status)
> +				i9xx_hpd_irq_handler(dev_priv, hotplug_status);
> +
> +			if (has_pipe_stats)
> +				valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
> +
> +			enable_rpm_wakeref_asserts(dev_priv);
> +			master_ctl = I915_READ_FW(GEN8_MASTER_IRQ);
> +		}
> +	} while (master_ctl & ~GEN8_MASTER_IRQ_CONTROL);
>  
>  	return ret;
>  }
> -- 
> 2.14.1

-- 
Ville Syrjälä
Intel OTC


More information about the Intel-gfx mailing list