[PATCH 19/22] drm/i915: Keep all power wells off when display is disabled

José Roberto de Souza jose.souza at intel.com
Wed Sep 12 00:07:22 UTC 2018


There is just to power wells calls left after the previous chances:
- POWER_DOMAIN_INIT: used in load, unload, resume and supend driver paths
- POWER_DOMAIN_GT_IRQ: used by GEM to reduce interrupt latencies
Instead of adding severa more 'if (INTEL_INFO(dev_priv)->num_pipes)'
it will be handled in intel_display_power_get/put() and if any
erroneous call is added later a error message will be printed.

Just not enable power wells is not enough as BIOS/firmware can turn
on some power wells during boot, so we need to disable those to save
power and do avoid errors in intel_power_domains_verify_state().
So here disabling every non-real power well first as it could have
some dependency in a real power well and then disabling all power
wells in reverse other as required by spec.

Other important point is that it will not turn power wells on or off
but it will still grab and release runtime power managment references
this way kernel can power down the whole GPU when it is not in use.

Signed-off-by: José Roberto de Souza <jose.souza at intel.com>
---
 drivers/gpu/drm/i915/intel_runtime_pm.c | 75 +++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 13ee15ac95cc..8b1873d91395 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -1521,6 +1521,9 @@ __intel_display_power_get_domain(struct drm_i915_private *dev_priv,
 	struct i915_power_domains *power_domains = &dev_priv->power_domains;
 	struct i915_power_well *power_well;
 
+	if (!INTEL_INFO(dev_priv)->num_pipes)
+		DRM_ERROR("Enabling a power well with display disabled");
+
 	for_each_power_domain_well(dev_priv, power_well, BIT_ULL(domain))
 		intel_power_well_get(dev_priv, power_well);
 
@@ -1546,6 +1549,13 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
 
 	intel_runtime_pm_get(dev_priv);
 
+	/* With display disabled this should be the only 2 power domains
+	 * requested
+	 */
+	if ((domain == POWER_DOMAIN_INIT || domain == POWER_DOMAIN_GT_IRQ) &&
+	    !INTEL_INFO(dev_priv)->num_pipes)
+		return;
+
 	mutex_lock(&power_domains->lock);
 
 	__intel_display_power_get_domain(dev_priv, domain);
@@ -1606,6 +1616,10 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
 	struct i915_power_domains *power_domains;
 	struct i915_power_well *power_well;
 
+	if ((domain == POWER_DOMAIN_INIT || domain == POWER_DOMAIN_GT_IRQ) &&
+	    !INTEL_INFO(dev_priv)->num_pipes)
+		goto end;
+
 	power_domains = &dev_priv->power_domains;
 
 	mutex_lock(&power_domains->lock);
@@ -1620,6 +1634,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
 
 	mutex_unlock(&power_domains->lock);
 
+end:
 	intel_runtime_pm_put(dev_priv);
 }
 
@@ -3752,6 +3767,62 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
 
 static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv);
 
+static void
+intel_power_domains_disable_leftovers(struct drm_i915_private *dev_priv)
+{
+	struct i915_power_domains *power_domains = &dev_priv->power_domains;
+	struct i915_power_well *power_well;
+	int i;
+
+	mutex_lock(&power_domains->lock);
+
+	/* Disable everything that is enabled and is not a HW power_well */
+	for_each_power_well(dev_priv, power_well) {
+
+		WARN_ON(power_well->count);
+
+		/*
+		 * Power wells not belonging to any domain (like the MISC_IO
+		 * and PW1 power wells) are under FW control, so ignore them,
+		 * since their state can change asynchronously.
+		 */
+		if (!power_well->desc->domains || power_well->desc->always_on)
+			continue;
+
+		if (power_well->desc->id != DISP_PW_ID_NONE)
+			continue;
+
+		if (!power_well->hw_enabled)
+			continue;
+
+		intel_power_well_disable(dev_priv, power_well);
+	}
+
+	/* Disabled HW power wells in reverse order, so power well 2 is
+	 * disabled before power well 1 and so on as required by spec.
+	 */
+	for (i = power_domains->power_well_count - 1; i >= 0; i--) {
+		power_well = &power_domains->power_wells[i];
+
+		WARN_ON(power_well->count);
+
+		if (!power_well->desc->domains || power_well->desc->always_on)
+			continue;
+
+		if (power_well->desc->id == DISP_PW_ID_NONE)
+			continue;
+
+		if (!power_well->hw_enabled)
+			continue;
+
+		intel_power_well_disable(dev_priv, power_well);
+	}
+
+	mutex_unlock(&power_domains->lock);
+
+	intel_power_domains_verify_state(dev_priv);
+}
+
 /**
  * intel_power_domains_init_hw - initialize hardware power domain state
  * @dev_priv: i915 device instance
@@ -3813,6 +3884,10 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
 		intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
 	intel_power_domains_sync_hw(dev_priv);
 
+	/* Disable everything left enabled by BIOS/firmware */
+	if (!INTEL_INFO(dev_priv)->num_pipes)
+		intel_power_domains_disable_leftovers(dev_priv);
+
 	power_domains->initializing = false;
 }
 
-- 
2.18.0



More information about the Intel-gfx-trybot mailing list