summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorPaulo Zanoni2014-03-08 00:08:05 +0100
committerDaniel Vetter2014-03-19 16:38:25 +0100
commita8a8bd547e6323c56295e1c5a03e30e765d42325 (patch)
treed53997a1ec2b907d28a4cd6cc9bd4f6cd075fd18 /drivers/gpu/drm/i915/intel_display.c
parentdrm/i915: extract __hsw_do_{en, dis}able_package_c8 (diff)
downloadkernel-qcow2-linux-a8a8bd547e6323c56295e1c5a03e30e765d42325.tar.gz
kernel-qcow2-linux-a8a8bd547e6323c56295e1c5a03e30e765d42325.tar.xz
kernel-qcow2-linux-a8a8bd547e6323c56295e1c5a03e30e765d42325.zip
drm/i915: make PC8 be part of runtime PM suspend/resume
Currently, when our driver becomes idle for i915.pc8_timeout (default: 5s) we enable PC8, so we save some power, but not everything we can. Then, while PC8 is enabled, if we stay idle for more autosuspend_delay_ms (default: 10s) we'll enter runtime PM and put the graphics device in D3 state, saving even more power. The two features are separate things with increasing levels of power savings, but if we disable PC8 we'll never get into D3. While from the modularity point of view it would be nice to keep these features as separate, we have reasons to merge them: - We are not aware of anybody wanting a "PC8 without D3" environment. - If we keep both features as separate, we'll have to to test both PC8 and PC8+D3 code paths. We're already having a major pain to make QA do automated testing of just one thing, testing both paths will cost even more. - Only Haswell+ supports PC8, so if we want to add runtime PM support to, for example, IVB, we'll have to copy some code from the PC8 feature to runtime PM, so merging both features as a single thing will make it easier for enabling runtime PM on other platforms. This patch only does the very basic steps required to have PC8 and runtime PM merged on a single feature: the next patches will take care of cleaning up everything. v2: - Rebase. v3: - Rebase. - Fully remove the deprecated i915 params since Daniel doesn't consider them as part of the ABI. v4: - Rebase. - Fix typo in the commit message. v5: - Rebase, again. - Add a huge comment explaining the different forcewake usage (Chris, Daniel). - Use open-coded forcewake functions (Daniel). Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Imre Deak <imre.deak@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c65
1 files changed, 29 insertions, 36 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index da68ccfd5aa9..1f79d1d51ea7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6960,6 +6960,7 @@ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
{
uint32_t val;
+ unsigned long irqflags;
val = I915_READ(LCPLL_CTL);
@@ -6967,9 +6968,22 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
return;
- /* Make sure we're not on PC8 state before disabling PC8, otherwise
- * we'll hang the machine! */
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ /*
+ * Make sure we're not on PC8 state before disabling PC8, otherwise
+ * we'll hang the machine. To prevent PC8 state, just enable force_wake.
+ *
+ * The other problem is that hsw_restore_lcpll() is called as part of
+ * the runtime PM resume sequence, so we can't just call
+ * gen6_gt_force_wake_get() because that function calls
+ * intel_runtime_pm_get(), and we can't change the runtime PM refcount
+ * while we are on the resume sequence. So to solve this problem we have
+ * to call special forcewake code that doesn't touch runtime PM and
+ * doesn't enable the forcewake delayed work.
+ */
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ if (dev_priv->uncore.forcewake_count++ == 0)
+ dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
if (val & LCPLL_POWER_DOWN_ALLOW) {
val &= ~LCPLL_POWER_DOWN_ALLOW;
@@ -7003,14 +7017,20 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
DRM_ERROR("Switching back to LCPLL failed\n");
}
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ /* See the big comment above. */
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ if (--dev_priv->uncore.forcewake_count == 0)
+ dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
-static void __hsw_do_enable_pc8(struct drm_i915_private *dev_priv)
+void __hsw_do_enable_pc8(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
uint32_t val;
+ WARN_ON(!HAS_PC8(dev));
+
DRM_DEBUG_KMS("Enabling package C8+\n");
dev_priv->pc8.enabled = true;
@@ -7026,22 +7046,6 @@ static void __hsw_do_enable_pc8(struct drm_i915_private *dev_priv)
hsw_disable_lcpll(dev_priv, true, true);
}
-void hsw_enable_pc8_work(struct work_struct *__work)
-{
- struct drm_i915_private *dev_priv =
- container_of(to_delayed_work(__work), struct drm_i915_private,
- pc8.enable_work);
- struct drm_device *dev = dev_priv->dev;
-
- WARN_ON(!HAS_PC8(dev));
-
- if (dev_priv->pc8.enabled)
- return;
-
- __hsw_do_enable_pc8(dev_priv);
- intel_runtime_pm_put(dev_priv);
-}
-
static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv)
{
WARN_ON(!mutex_is_locked(&dev_priv->pc8.lock));
@@ -7052,15 +7056,16 @@ static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv)
if (dev_priv->pc8.disable_count != 0)
return;
- schedule_delayed_work(&dev_priv->pc8.enable_work,
- msecs_to_jiffies(i915.pc8_timeout));
+ intel_runtime_pm_put(dev_priv);
}
-static void __hsw_do_disable_package_c8(struct drm_i915_private *dev_priv)
+void __hsw_do_disable_pc8(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
uint32_t val;
+ WARN_ON(!HAS_PC8(dev));
+
DRM_DEBUG_KMS("Disabling package C8+\n");
hsw_restore_lcpll(dev_priv);
@@ -7083,8 +7088,6 @@ static void __hsw_do_disable_package_c8(struct drm_i915_private *dev_priv)
static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = dev_priv->dev;
-
WARN_ON(!mutex_is_locked(&dev_priv->pc8.lock));
WARN(dev_priv->pc8.disable_count < 0,
"pc8.disable_count: %d\n", dev_priv->pc8.disable_count);
@@ -7093,14 +7096,7 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
if (dev_priv->pc8.disable_count != 1)
return;
- WARN_ON(!HAS_PC8(dev));
-
- cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
- if (!dev_priv->pc8.enabled)
- return;
-
intel_runtime_pm_get(dev_priv);
- __hsw_do_disable_package_c8(dev_priv);
}
void hsw_enable_package_c8(struct drm_i915_private *dev_priv)
@@ -7158,9 +7154,6 @@ static void hsw_update_package_c8(struct drm_device *dev)
if (!HAS_PC8(dev_priv->dev))
return;
- if (!i915.enable_pc8)
- return;
-
mutex_lock(&dev_priv->pc8.lock);
allow = hsw_can_enable_package_c8(dev_priv);