Commit 31c77388 authored by Ben Widawsky's avatar Ben Widawsky Committed by Daniel Vetter

drm/i915: Better overclock support

Most importantly this will allow users to set overclock frequencies in
sysfs. Previously the max was limited by the RP0 max as opposed to the
overclock max. This is useful if one wants to either limit the max
overclock frequency, or set the minimum frequency to be in the overclock
range. It also fixes an issue where if one sets the max frequency to be
below the overclock max, they wouldn't be able to set back the proper
overclock max.

In addition I've added a couple of other bits:
Show the overclock freq. as max in sysfs
Print the overclock max in debugfs.
Print a warning if the user sets the min frequency to be in the
overclock range.

In this patch I've decided to store the hw_max when we read it from the
pcode at init. The reason I do this is the pcode reads can fail, and are
slow.

v2: Report when user requested overclocked max (Daniel)
Remove when user sets min to overclock range (Daniel)

Reported-by: freezer from #intel-gfx on irc
Signed-off-by: default avatarBen Widawsky <ben@bwidawsk.net>
Reviewed-by: default avatarMika Kuoppala <mika.kuoppala@intel.com>
[danvet: Fixup the s/100MHz/50MHz/ confusion in an unrelated comment
that Mika spotted.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 2c55c336
...@@ -1006,6 +1006,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) ...@@ -1006,6 +1006,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
max_freq = rp_state_cap & 0xff; max_freq = rp_state_cap & 0xff;
seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
max_freq * GT_FREQUENCY_MULTIPLIER); max_freq * GT_FREQUENCY_MULTIPLIER);
seq_printf(m, "Max overclocked frequency: %dMHz\n",
dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
} else { } else {
seq_printf(m, "no P-state info available\n"); seq_printf(m, "no P-state info available\n");
} }
......
...@@ -668,6 +668,7 @@ struct intel_gen6_power_mgmt { ...@@ -668,6 +668,7 @@ struct intel_gen6_power_mgmt {
u8 cur_delay; u8 cur_delay;
u8 min_delay; u8 min_delay;
u8 max_delay; u8 max_delay;
u8 hw_max;
struct delayed_work delayed_resume_work; struct delayed_work delayed_resume_work;
......
...@@ -226,7 +226,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute ...@@ -226,7 +226,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
int ret; int ret;
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; ret = dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret); return snprintf(buf, PAGE_SIZE, "%d\n", ret);
...@@ -239,7 +239,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, ...@@ -239,7 +239,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev); struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
struct drm_device *dev = minor->dev; struct drm_device *dev = minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 val, rp_state_cap, hw_max, hw_min; u32 val, rp_state_cap, hw_max, hw_min, non_oc_max;
ssize_t ret; ssize_t ret;
ret = kstrtou32(buf, 0, &val); ret = kstrtou32(buf, 0, &val);
...@@ -251,7 +251,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, ...@@ -251,7 +251,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
hw_max = (rp_state_cap & 0xff); hw_max = dev_priv->rps.hw_max;
non_oc_max = (rp_state_cap & 0xff);
hw_min = ((rp_state_cap & 0xff0000) >> 16); hw_min = ((rp_state_cap & 0xff0000) >> 16);
if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) { if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) {
...@@ -259,6 +260,10 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, ...@@ -259,6 +260,10 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
return -EINVAL; return -EINVAL;
} }
if (val > non_oc_max)
DRM_DEBUG("User requested overclocking to %d\n",
val * GT_FREQUENCY_MULTIPLIER);
if (dev_priv->rps.cur_delay > val) if (dev_priv->rps.cur_delay > val)
gen6_set_rps(dev_priv->dev, val); gen6_set_rps(dev_priv->dev, val);
...@@ -302,7 +307,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, ...@@ -302,7 +307,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
hw_max = (rp_state_cap & 0xff); hw_max = dev_priv->rps.hw_max;
hw_min = ((rp_state_cap & 0xff0000) >> 16); hw_min = ((rp_state_cap & 0xff0000) >> 16);
if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
......
...@@ -2558,8 +2558,8 @@ static void gen6_enable_rps(struct drm_device *dev) ...@@ -2558,8 +2558,8 @@ static void gen6_enable_rps(struct drm_device *dev)
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
/* In units of 100MHz */ /* In units of 50MHz */
dev_priv->rps.max_delay = rp_state_cap & 0xff; dev_priv->rps.hw_max = dev_priv->rps.max_delay = rp_state_cap & 0xff;
dev_priv->rps.min_delay = (rp_state_cap & 0xff0000) >> 16; dev_priv->rps.min_delay = (rp_state_cap & 0xff0000) >> 16;
dev_priv->rps.cur_delay = 0; dev_priv->rps.cur_delay = 0;
...@@ -2646,6 +2646,7 @@ static void gen6_enable_rps(struct drm_device *dev) ...@@ -2646,6 +2646,7 @@ static void gen6_enable_rps(struct drm_device *dev)
DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max from %dMHz to %dMHz\n", DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max from %dMHz to %dMHz\n",
(dev_priv->rps.max_delay & 0xff) * 50, (dev_priv->rps.max_delay & 0xff) * 50,
(pcu_mbox & 0xff) * 50); (pcu_mbox & 0xff) * 50);
dev_priv->rps.hw_max = pcu_mbox & 0xff;
dev_priv->rps.max_delay = pcu_mbox & 0xff; dev_priv->rps.max_delay = pcu_mbox & 0xff;
} }
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment