[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