[Intel-gfx] [PATCH] drm/i915: Always update RPS interrupts thresholds along with frequency

Ben Widawsky ben at bwidawsk.net
Sun Apr 29 04:18:30 CEST 2012


On Sat, 28 Apr 2012 08:56:39 +0100
Chris Wilson <chris at chris-wilson.co.uk> wrote:

> In order to avoid missed down-interrupts when coming out of RC6, it is
> advised that we always reset the down-threshold upon a PM event. This
> is due to that the PM unit goes through a little dance when coming
> out of RC6, it first brings the GPU up at the lowest frequency then a
> short time later it restores the thresholds. During that interval, the
> down-interval may expire and the interrupt be suppressed.
> 
> Now aware of the dance taking place within the GPU when coming out of
> RC6, one wonders what other writes need to be queued in the fifo
> buffer in order to be properly sequenced; setting the RP state
> appears to be one.
> 
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44006
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

I tried really hard to review this, but it was too much. The code
definitely is cleaner as a result, so this is:
Acked-by: Ben Widawsky <ben at bwidawsk.net>

> ---
>  drivers/gpu/drm/i915/i915_irq.c |   37 +++++--------------------
>  drivers/gpu/drm/i915/intel_pm.c |   57
> +++++++++++++++++++++++++++------------ 2 files changed, 47
> insertions(+), 47 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c
> b/drivers/gpu/drm/i915/i915_irq.c index c2511fe..1ea39e4 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -353,8 +353,8 @@ static void gen6_pm_rps_work(struct work_struct
> *work) {
>  	drm_i915_private_t *dev_priv = container_of(work,
> drm_i915_private_t, rps_work);
> -	u8 new_delay = dev_priv->cur_delay;
>  	u32 pm_iir, pm_imr;
> +	u8 new_delay;
>  
>  	spin_lock_irq(&dev_priv->rps_lock);
>  	pm_iir = dev_priv->pm_iir;
> @@ -363,41 +363,18 @@ static void gen6_pm_rps_work(struct work_struct
> *work) I915_WRITE(GEN6_PMIMR, 0);
>  	spin_unlock_irq(&dev_priv->rps_lock);
>  
> -	if (!pm_iir)
> +	if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0)
>  		return;
>  
>  	mutex_lock(&dev_priv->dev->struct_mutex);
> -	if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
> -		if (dev_priv->cur_delay != dev_priv->max_delay)
> -			new_delay = dev_priv->cur_delay + 1;
> -		if (new_delay > dev_priv->max_delay)
> -			new_delay = dev_priv->max_delay;
> -	} else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD |
> GEN6_PM_RP_DOWN_TIMEOUT)) {
> -		gen6_gt_force_wake_get(dev_priv);
> -		if (dev_priv->cur_delay != dev_priv->min_delay)
> -			new_delay = dev_priv->cur_delay - 1;
> -		if (new_delay < dev_priv->min_delay) {
> -			new_delay = dev_priv->min_delay;
> -			I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
> -
> I915_READ(GEN6_RP_INTERRUPT_LIMITS) |
> -				   ((new_delay << 16) & 0x3f0000));
> -		} else {
> -			/* Make sure we continue to get down
> interrupts
> -			 * until we hit the minimum frequency */
> -			I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
> -
> I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
> -		}
> -		gen6_gt_force_wake_put(dev_priv);
> -	}
> +
> +	if (pm_iir & GEN6_PM_RP_UP_THRESHOLD)
> +		new_delay = dev_priv->cur_delay + 1;
> +	else
> +		new_delay = dev_priv->cur_delay - 1;
>  
>  	gen6_set_rps(dev_priv->dev, new_delay);
> -	dev_priv->cur_delay = new_delay;
>  
> -	/*
> -	 * rps_lock not held here because clearing is
> non-destructive. There is
> -	 * an *extremely* unlikely race with gen6_rps_enable() that
> is prevented
> -	 * by holding struct_mutex for the duration of the write.
> -	 */
>  	mutex_unlock(&dev_priv->dev->struct_mutex);
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_pm.c
> b/drivers/gpu/drm/i915/intel_pm.c index 3b05ba3..5e6b0c8 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2127,10 +2127,33 @@ void ironlake_disable_drps(struct drm_device
> *dev) void gen6_set_rps(struct drm_device *dev, u8 val)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> -	u32 swreq;
> +	u32 limits;
>  
> -	swreq = (val & 0x3ff) << 25;
> -	I915_WRITE(GEN6_RPNSWREQ, swreq);
> +	limits = 0;
> +	if (val >= dev_priv->max_delay)
> +		val = dev_priv->max_delay;
> +	else
> +		limits |= dev_priv->max_delay << 24;
> +
> +	if (val <= dev_priv->min_delay)
> +		val = dev_priv->min_delay;
> +	else
> +		limits |= dev_priv->min_delay << 16;
> +
> +	if (val == dev_priv->cur_delay)
> +		return;
> +
> +	I915_WRITE(GEN6_RPNSWREQ,
> +		   GEN6_FREQUENCY(val) |
> +		   GEN6_OFFSET(0) |
> +		   GEN6_AGGRESSIVE_TURBO);
> +
> +	/* Make sure we continue to get interrupts
> +	 * until we hit the minimum or maximum frequencies.
> +	 */
> +	I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits);
> +
> +	dev_priv->cur_delay = val;
>  }
>  
>  void gen6_disable_rps(struct drm_device *dev)
> @@ -2183,11 +2206,10 @@ int intel_enable_rc6(const struct drm_device
> *dev) 
>  void gen6_enable_rps(struct drm_i915_private *dev_priv)
>  {
> -	u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
> -	u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
> +	u32 rp_state_cap;
> +	u32 gt_perf_status;
>  	u32 pcu_mbox, rc6_mask = 0;
>  	u32 gtfifodbg;
> -	int cur_freq, min_freq, max_freq;
>  	int rc6_mode;
>  	int i;
>  
> @@ -2208,6 +2230,14 @@ void gen6_enable_rps(struct drm_i915_private
> *dev_priv) 
>  	gen6_gt_force_wake_get(dev_priv);
>  
> +	rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
> +	gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
> +
> +	/* In units of 100MHz */
> +	dev_priv->max_delay = rp_state_cap & 0xff;
> +	dev_priv->min_delay = (rp_state_cap & 0xff0000) >> 16;
> +	dev_priv->cur_delay = 0;
> +
>  	/* disable the counters and set deterministic thresholds */
>  	I915_WRITE(GEN6_RC_CONTROL, 0);
>  
> @@ -2255,8 +2285,8 @@ void gen6_enable_rps(struct drm_i915_private
> *dev_priv) 
>  	I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
>  	I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
> -		   18 << 24 |
> -		   6 << 16);
> +		   dev_priv->max_delay << 24 |
> +		   dev_priv->min_delay << 16);
>  	I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
>  	I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
>  	I915_WRITE(GEN6_RP_UP_EI, 100000);
> @@ -2282,10 +2312,6 @@ void gen6_enable_rps(struct drm_i915_private
> *dev_priv) 500))
>  		DRM_ERROR("timeout waiting for pcode mailbox to
> finish\n"); 
> -	min_freq = (rp_state_cap & 0xff0000) >> 16;
> -	max_freq = rp_state_cap & 0xff;
> -	cur_freq = (gt_perf_status & 0xff00) >> 8;
> -
>  	/* Check for overclock support */
>  	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
> GEN6_PCODE_READY) == 0, 500))
> @@ -2296,14 +2322,11 @@ void gen6_enable_rps(struct drm_i915_private
> *dev_priv) 500))
>  		DRM_ERROR("timeout waiting for pcode mailbox to
> finish\n"); if (pcu_mbox & (1<<31)) { /* OC supported */
> -		max_freq = pcu_mbox & 0xff;
> +		dev_priv->max_delay = pcu_mbox & 0xff;
>  		DRM_DEBUG_DRIVER("overclocking supported, adjusting
> frequency max to %dMHz\n", pcu_mbox * 50); }
>  
> -	/* In units of 100MHz */
> -	dev_priv->max_delay = max_freq;
> -	dev_priv->min_delay = min_freq;
> -	dev_priv->cur_delay = cur_freq;
> +	gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8);
>  
>  	/* requires MSI enabled */
>  	I915_WRITE(GEN6_PMIER,




More information about the Intel-gfx mailing list