summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_pm.c
diff options
context:
space:
mode:
authorJesse Barnes2013-04-23 19:09:26 +0200
committerDaniel Vetter2013-04-24 11:03:38 +0200
commit52ceb908018d3ac3c19cea85d5e407705f0a79c3 (patch)
treea0e892b1b1130add7d0a1f067a5ed909fdb6c79d /drivers/gpu/drm/i915/intel_pm.c
parentdrm/i915: Turn HAS_FPGA_DBG_UNCLAIMED into a device_info flag (diff)
downloadkernel-qcow2-linux-52ceb908018d3ac3c19cea85d5e407705f0a79c3.tar.gz
kernel-qcow2-linux-52ceb908018d3ac3c19cea85d5e407705f0a79c3.tar.xz
kernel-qcow2-linux-52ceb908018d3ac3c19cea85d5e407705f0a79c3.zip
drm/i915: make sure GPU freq drops to minimum after entering RC6 v4
On VLV, the Punit doesn't automatically drop the GPU to it's minimum voltage level when entering RC6, so we arm a timer to do it for us from the RPS interrupt handler. It'll generally only fire when we go idle (or if for some reason there's a long delay between RPS interrupts), but won't be re-armed again until the next RPS event, so shouldn't affect power consumption after we go idle and it triggers. v2: use delayed work instead of timer + work queue combo (Ville) v3: fix up delayed work cancel (must be outside lock) (Daniel) fix up delayed work handling func for delayed work (Jesse) v4: cancel delayed work before RPS shutdown (Jani) pass delay not absolute time to mod_delayed_work (Jani) Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_pm.c')
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 2557926553b3..93b01e197f42 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2822,6 +2822,23 @@ int valleyview_rps_min_freq(struct drm_i915_private *dev_priv)
return val & 0xff;
}
+static void vlv_rps_timer_work(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+ rps.vlv_work.work);
+
+ /*
+ * Timer fired, we must be idle. Drop to min voltage state.
+ * Note: we use RPe here since it should match the
+ * Vmin we were shooting for. That should give us better
+ * perf when we come back out of RC6 than if we used the
+ * min freq available.
+ */
+ mutex_lock(&dev_priv->rps.hw_lock);
+ valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
static void valleyview_enable_rps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2886,6 +2903,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
rpe = valleyview_rps_rpe_freq(dev_priv);
DRM_DEBUG_DRIVER("RPe GPU freq: %d\n",
vlv_gpu_freq(dev_priv->mem_freq, rpe));
+ dev_priv->rps.rpe_delay = rpe;
val = valleyview_rps_min_freq(dev_priv);
DRM_DEBUG_DRIVER("min GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq,
@@ -2895,6 +2913,8 @@ static void valleyview_enable_rps(struct drm_device *dev)
DRM_DEBUG_DRIVER("setting GPU freq to %d\n",
vlv_gpu_freq(dev_priv->mem_freq, rpe));
+ INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work);
+
valleyview_set_rps(dev_priv->dev, rpe);
/* requires MSI enabled */
@@ -3637,6 +3657,8 @@ void intel_disable_gt_powersave(struct drm_device *dev)
ironlake_disable_rc6(dev);
} else if (INTEL_INFO(dev)->gen >= 6) {
cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
+ if (IS_VALLEYVIEW(dev))
+ cancel_delayed_work_sync(&dev_priv->rps.vlv_work);
mutex_lock(&dev_priv->rps.hw_lock);
gen6_disable_rps(dev);
mutex_unlock(&dev_priv->rps.hw_lock);