Commit bfafe93a authored by Imre Deak's avatar Imre Deak Committed by Jani Nikula

drm/i915: cache hw power well enabled state

Jesse noticed that the punit communication needed to query the VLV power
well status can cause substantial delays. Since we can query the state
frequently, for example during I2C transfers, maintain a cached version
of the HW state to get rid of this delay.

This fixes at least one reported regression where boot time increased by
~4 seconds due to frequent power well state queries on VLV during eDP
EDID read.

This regression has been introduced in

commit bb4932c4
Author: Imre Deak <imre.deak@intel.com>
Date:   Mon Apr 14 20:24:33 2014 +0300

    drm/i915: vlv: check port power domain instead of only D0 for eDP VDD on
Reported-by: default avatarJesse Barnes <jesse.barnes@intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent a497c3ba
...@@ -977,6 +977,8 @@ struct i915_power_well { ...@@ -977,6 +977,8 @@ struct i915_power_well {
bool always_on; bool always_on;
/* power well enable/disable usage count */ /* power well enable/disable usage count */
int count; int count;
/* cached hw enabled state */
bool hw_enabled;
unsigned long domains; unsigned long domains;
unsigned long data; unsigned long data;
const struct i915_power_well_ops *ops; const struct i915_power_well_ops *ops;
......
...@@ -12411,7 +12411,7 @@ intel_display_capture_error_state(struct drm_device *dev) ...@@ -12411,7 +12411,7 @@ intel_display_capture_error_state(struct drm_device *dev)
for_each_pipe(i) { for_each_pipe(i) {
error->pipe[i].power_domain_on = error->pipe[i].power_domain_on =
intel_display_power_enabled_sw(dev_priv, intel_display_power_enabled_unlocked(dev_priv,
POWER_DOMAIN_PIPE(i)); POWER_DOMAIN_PIPE(i));
if (!error->pipe[i].power_domain_on) if (!error->pipe[i].power_domain_on)
continue; continue;
...@@ -12447,7 +12447,7 @@ intel_display_capture_error_state(struct drm_device *dev) ...@@ -12447,7 +12447,7 @@ intel_display_capture_error_state(struct drm_device *dev)
enum transcoder cpu_transcoder = transcoders[i]; enum transcoder cpu_transcoder = transcoders[i];
error->transcoder[i].power_domain_on = error->transcoder[i].power_domain_on =
intel_display_power_enabled_sw(dev_priv, intel_display_power_enabled_unlocked(dev_priv,
POWER_DOMAIN_TRANSCODER(cpu_transcoder)); POWER_DOMAIN_TRANSCODER(cpu_transcoder));
if (!error->transcoder[i].power_domain_on) if (!error->transcoder[i].power_domain_on)
continue; continue;
......
...@@ -950,7 +950,7 @@ int intel_power_domains_init(struct drm_i915_private *); ...@@ -950,7 +950,7 @@ int intel_power_domains_init(struct drm_i915_private *);
void intel_power_domains_remove(struct drm_i915_private *); void intel_power_domains_remove(struct drm_i915_private *);
bool intel_display_power_enabled(struct drm_i915_private *dev_priv, bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain); enum intel_display_power_domain domain);
bool intel_display_power_enabled_sw(struct drm_i915_private *dev_priv, bool intel_display_power_enabled_unlocked(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain); enum intel_display_power_domain domain);
void intel_display_power_get(struct drm_i915_private *dev_priv, void intel_display_power_get(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain); enum intel_display_power_domain domain);
......
...@@ -5603,7 +5603,7 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv, ...@@ -5603,7 +5603,7 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
(HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
} }
bool intel_display_power_enabled_sw(struct drm_i915_private *dev_priv, bool intel_display_power_enabled_unlocked(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain) enum intel_display_power_domain domain)
{ {
struct i915_power_domains *power_domains; struct i915_power_domains *power_domains;
...@@ -5615,16 +5615,19 @@ bool intel_display_power_enabled_sw(struct drm_i915_private *dev_priv, ...@@ -5615,16 +5615,19 @@ bool intel_display_power_enabled_sw(struct drm_i915_private *dev_priv,
return false; return false;
power_domains = &dev_priv->power_domains; power_domains = &dev_priv->power_domains;
is_enabled = true; is_enabled = true;
for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
if (power_well->always_on) if (power_well->always_on)
continue; continue;
if (!power_well->count) { if (!power_well->hw_enabled) {
is_enabled = false; is_enabled = false;
break; break;
} }
} }
return is_enabled; return is_enabled;
} }
...@@ -5632,30 +5635,15 @@ bool intel_display_power_enabled(struct drm_i915_private *dev_priv, ...@@ -5632,30 +5635,15 @@ bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain) enum intel_display_power_domain domain)
{ {
struct i915_power_domains *power_domains; struct i915_power_domains *power_domains;
struct i915_power_well *power_well; bool ret;
bool is_enabled;
int i;
if (dev_priv->pm.suspended)
return false;
power_domains = &dev_priv->power_domains; power_domains = &dev_priv->power_domains;
is_enabled = true;
mutex_lock(&power_domains->lock); mutex_lock(&power_domains->lock);
for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { ret = intel_display_power_enabled_unlocked(dev_priv, domain);
if (power_well->always_on)
continue;
if (!power_well->ops->is_enabled(dev_priv, power_well)) {
is_enabled = false;
break;
}
}
mutex_unlock(&power_domains->lock); mutex_unlock(&power_domains->lock);
return is_enabled; return ret;
} }
/* /*
...@@ -5976,6 +5964,7 @@ void intel_display_power_get(struct drm_i915_private *dev_priv, ...@@ -5976,6 +5964,7 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
if (!power_well->count++) { if (!power_well->count++) {
DRM_DEBUG_KMS("enabling %s\n", power_well->name); DRM_DEBUG_KMS("enabling %s\n", power_well->name);
power_well->ops->enable(dev_priv, power_well); power_well->ops->enable(dev_priv, power_well);
power_well->hw_enabled = true;
} }
check_power_well_state(dev_priv, power_well); check_power_well_state(dev_priv, power_well);
...@@ -6005,6 +5994,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, ...@@ -6005,6 +5994,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
if (!--power_well->count && i915.disable_power_well) { if (!--power_well->count && i915.disable_power_well) {
DRM_DEBUG_KMS("disabling %s\n", power_well->name); DRM_DEBUG_KMS("disabling %s\n", power_well->name);
power_well->hw_enabled = false;
power_well->ops->disable(dev_priv, power_well); power_well->ops->disable(dev_priv, power_well);
} }
...@@ -6267,8 +6257,11 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv) ...@@ -6267,8 +6257,11 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
int i; int i;
mutex_lock(&power_domains->lock); mutex_lock(&power_domains->lock);
for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
power_well->ops->sync_hw(dev_priv, power_well); power_well->ops->sync_hw(dev_priv, power_well);
power_well->hw_enabled = power_well->ops->is_enabled(dev_priv,
power_well);
}
mutex_unlock(&power_domains->lock); mutex_unlock(&power_domains->lock);
} }
......
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