| From 89a1433aebda51050c4569740746560616c9f816 Mon Sep 17 00:00:00 2001 |
| From: Jesse Barnes <jbarnes@virtuousgeek.org> |
| Date: Tue, 23 Apr 2013 10:09:26 -0700 |
| Subject: 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> |
| (cherry picked from commit 52ceb908018d3ac3c19cea85d5e407705f0a79c3) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/i915_drv.h | 2 ++ |
| drivers/gpu/drm/i915/i915_irq.c | 11 +++++++++++ |
| drivers/gpu/drm/i915/intel_pm.c | 22 ++++++++++++++++++++++ |
| 3 files changed, 35 insertions(+) |
| |
| diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h |
| index 4060621e76e3..c123e9e0cd12 100644 |
| --- a/drivers/gpu/drm/i915/i915_drv.h |
| +++ b/drivers/gpu/drm/i915/i915_drv.h |
| @@ -654,6 +654,7 @@ struct i915_suspend_saved_registers { |
| |
| struct intel_gen6_power_mgmt { |
| struct work_struct work; |
| + struct delayed_work vlv_work; |
| u32 pm_iir; |
| /* lock - irqsave spinlock that protectects the work_struct and |
| * pm_iir. */ |
| @@ -664,6 +665,7 @@ struct intel_gen6_power_mgmt { |
| u8 cur_delay; |
| u8 min_delay; |
| u8 max_delay; |
| + u8 rpe_delay; |
| u8 hw_max; |
| |
| struct delayed_work delayed_resume_work; |
| diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c |
| index 1d42446e287c..4fe62a65a87a 100644 |
| --- a/drivers/gpu/drm/i915/i915_irq.c |
| +++ b/drivers/gpu/drm/i915/i915_irq.c |
| @@ -716,6 +716,17 @@ static void gen6_pm_rps_work(struct work_struct *work) |
| gen6_set_rps(dev_priv->dev, new_delay); |
| } |
| |
| + if (IS_VALLEYVIEW(dev_priv->dev)) { |
| + /* |
| + * On VLV, when we enter RC6 we may not be at the minimum |
| + * voltage level, so arm a timer to check. It should only |
| + * fire when there's activity or once after we've entered |
| + * RC6, and then won't be re-armed until the next RPS interrupt. |
| + */ |
| + mod_delayed_work(dev_priv->wq, &dev_priv->rps.vlv_work, |
| + msecs_to_jiffies(100)); |
| + } |
| + |
| mutex_unlock(&dev_priv->rps.hw_lock); |
| } |
| |
| diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c |
| index ca43c4e33c45..d5946860ce5b 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); |
| -- |
| 1.8.5.rc3 |
| |