[Intel-gfx] [PATCH 2/2] drm/i915: load a ring frequency scaling table v2

Ben Widawsky ben at bwidawsk.net
Tue Jun 28 20:21:41 CEST 2011


On Tue, Jun 28, 2011 at 10:59:13AM -0700, Jesse Barnes wrote:
> The ring frequency scaling table tells the PCU to treat certain GPU
> frequencies as if they were a given CPU frequency for purposes of
> scaling the ring frequency.  Normally the PCU will scale the ring
> frequency based on the CPU P-state, but with the table present, it will
> also take the GPU frequency into account.
> 
> The main downside of keeping the ring frequency high while the CPU is
> at a low frequency (or asleep altogether) is increased power
> consumption.  But then if you're keeping your GPU busy, you probably
> want the extra performance.
> 
> v2:
>   - add units to debug table header (from Eric)
>   - use tsc_khz as a fallback if the cpufreq driver doesn't give us a freq
>     (from Chris)
> 
> Tested-by: Eric Anholt <eric at anholt.net>
> Reviewed-by: Eric Anholt <eric at anholt.net>
> Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c  |   43 +++++++++++++++++++++++++
>  drivers/gpu/drm/i915/i915_reg.h      |    4 ++-
>  drivers/gpu/drm/i915/i915_suspend.c  |    4 ++-
>  drivers/gpu/drm/i915/intel_display.c |   57 +++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_drv.h     |    1 +
>  5 files changed, 106 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 4d46441..4d3ddff 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -1123,6 +1123,48 @@ static int i915_emon_status(struct seq_file *m, void *unused)
>  	return 0;
>  }
>  
> +static int i915_ring_freq_table(struct seq_file *m, void *unused)
> +{
> +	struct drm_info_node *node = (struct drm_info_node *) m->private;
> +	struct drm_device *dev = node->minor->dev;
> +	drm_i915_private_t *dev_priv = dev->dev_private;
> +	int ret;
> +	int gpu_freq, ia_freq;
> +
> +	if (!IS_GEN6(dev)) {
> +		seq_printf(m, "unsupported on this chipset\n");
> +		return 0;
> +	}
> +
> +	ret = mutex_lock_interruptible(&dev->struct_mutex);
> +	if (ret)
> +		return ret;
> +
> +	gen6_gt_force_wake_get(dev_priv);
> +
> +	seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n");
> +
> +	for (gpu_freq = dev_priv->min_delay; gpu_freq <= dev_priv->max_delay;
> +	     gpu_freq++) {
> +		I915_WRITE(GEN6_PCODE_DATA, gpu_freq);
> +		I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
> +			   GEN6_PCODE_READ_MIN_FREQ_TABLE);
> +		if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
> +			      GEN6_PCODE_READY) == 0, 10)) {
> +			DRM_ERROR("pcode write of freq table timed out\n");
> +			continue;
> +		}
> +		ia_freq = I915_READ(GEN6_PCODE_DATA);
> +		seq_printf(m, "%d\t\t%d\n", gpu_freq * 50, ia_freq * 100);
> +	}
> +
> +	gen6_gt_force_wake_put(dev_priv);
> +
> +	mutex_unlock(&dev->struct_mutex);
> +
> +	return 0;
> +}
> +
>  static int i915_gfxec(struct seq_file *m, void *unused)
>  {
>  	struct drm_info_node *node = (struct drm_info_node *) m->private;

You shouldn't need any of the forcewake stuff here, unless I'm missing
something.

> @@ -7159,6 +7160,58 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
>  	mutex_unlock(&dev_priv->dev->struct_mutex);
>  }
>  
> +void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
> +{
> +	int min_freq = 15;
> +	int gpu_freq, ia_freq, max_ia_freq;
> +	int scaling_factor = 180;
> +
> +	max_ia_freq = cpufreq_quick_get_max(0);
> +	/* default to 3GHz if none found, PCU will ensure we don't go over */
> +	if (!max_ia_freq)
> +		max_ia_freq = tsc_khz;
> +
> +	/* Convert from kHz to MHz */
> +	max_ia_freq /= 1000;
> +
> +	mutex_lock(&dev_priv->dev->struct_mutex);
> +	gen6_gt_force_wake_get(dev_priv);
> +
> +	/*
> +	 * For each potential GPU frequency, load a ring frequency we'd like
> +	 * to use for memory access.  We do this by specifying the IA frequency
> +	 * the PCU should use as a reference to determine the ring frequency.
> +	 */
> +	for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
> +	     gpu_freq--) {
> +		int diff = dev_priv->max_delay - gpu_freq;
> +
> +		/*
> +		 * For GPU frequencies less than 750MHz, just use the lowest
> +		 * ring freq.
> +		 */
> +		if (gpu_freq < min_freq)
> +			ia_freq = 800;
> +		else
> +			ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
> +		ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
> +
> +		I915_WRITE(GEN6_PCODE_DATA,
> +			   (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
> +			   gpu_freq);
> +		I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
> +			   GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
> +		if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
> +			      GEN6_PCODE_READY) == 0, 10)) {
> +			DRM_ERROR("pcode write of freq table timed out\n");
> +			continue;
> +		}
> +	}
> +
> +	gen6_gt_force_wake_put(dev_priv);
> +	mutex_unlock(&dev_priv->dev->struct_mutex);
> +}
> +
>  static void ironlake_init_clock_gating(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;


Same: you shouldn't need any of the forcewake stuff here, unless I'm
missing something.




More information about the Intel-gfx mailing list