drm/i915: Add power well SW/HW state verification

Verify that the refcount of all power wells match their HW enabled
state at the end of modeset HW state readout.

Also add documentation on how the reference count for each power well is
supposed to be acquired during initialization and HW state readout.

Suggested by Ander.

Cc: Ander Conselvan de Oliveira <conselvan2@gmail.com>
Cc: David Weinehall <david.weinehall@linux.intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Ander Conselvan de Oliveira <conselvan2@gmail.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1487345986-26511-6-git-send-email-imre.deak@intel.com
This commit is contained in:
Imre Deak 2017-02-17 17:39:46 +02:00
parent 16e849145d
commit 8d8c386c38
3 changed files with 87 additions and 1 deletions

View File

@ -15540,6 +15540,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev)
}
intel_display_set_init_power(dev_priv, false);
intel_power_domains_verify_state(dev_priv);
intel_fbc_init_pipe_state(dev_priv);
}

View File

@ -1693,6 +1693,7 @@ int intel_power_domains_init(struct drm_i915_private *);
void intel_power_domains_fini(struct drm_i915_private *);
void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume);
void intel_power_domains_suspend(struct drm_i915_private *dev_priv);
void intel_power_domains_verify_state(struct drm_i915_private *dev_priv);
void bxt_display_core_init(struct drm_i915_private *dev_priv, bool resume);
void bxt_display_core_uninit(struct drm_i915_private *dev_priv);
void intel_runtime_pm_enable(struct drm_i915_private *dev_priv);

View File

@ -2683,7 +2683,10 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
* @resume: Called from resume code paths or not
*
* This function initializes the hardware power domain state and enables all
* power domains using intel_display_set_init_power().
* power wells belonging to the INIT power domain. Power wells in other
* domains (and not in the INIT domain) are referenced or disabled during the
* modeset state HW readout. After that the reference count of each power well
* must match its HW enabled state, see intel_power_domains_verify_state().
*/
void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
{
@ -2736,6 +2739,86 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
bxt_display_core_uninit(dev_priv);
}
static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
struct i915_power_well *power_well;
for_each_power_well(dev_priv, power_well) {
enum intel_display_power_domain domain;
DRM_DEBUG_DRIVER("%-25s %d\n",
power_well->name, power_well->count);
for_each_power_domain(domain, power_well->domains)
DRM_DEBUG_DRIVER(" %-23s %d\n",
intel_display_power_domain_str(domain),
power_domains->domain_use_count[domain]);
}
}
/**
* intel_power_domains_verify_state - verify the HW/SW state for all power wells
* @dev_priv: i915 device instance
*
* Verify if the reference count of each power well matches its HW enabled
* state and the total refcount of the domains it belongs to. This must be
* called after modeset HW state sanitization, which is responsible for
* acquiring reference counts for any power wells in use and disabling the
* ones left on by BIOS but not required by any active output.
*/
void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
struct i915_power_well *power_well;
bool dump_domain_info;
mutex_lock(&power_domains->lock);
dump_domain_info = false;
for_each_power_well(dev_priv, power_well) {
enum intel_display_power_domain domain;
int domains_count;
bool enabled;
/*
* 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->domains)
continue;
enabled = power_well->ops->is_enabled(dev_priv, power_well);
if ((power_well->count || power_well->always_on) != enabled)
DRM_ERROR("power well %s state mismatch (refcount %d/enabled %d)",
power_well->name, power_well->count, enabled);
domains_count = 0;
for_each_power_domain(domain, power_well->domains)
domains_count += power_domains->domain_use_count[domain];
if (power_well->count != domains_count) {
DRM_ERROR("power well %s refcount/domain refcount mismatch "
"(refcount %d/domains refcount %d)\n",
power_well->name, power_well->count,
domains_count);
dump_domain_info = true;
}
}
if (dump_domain_info) {
static bool dumped;
if (!dumped) {
intel_power_domains_dump_info(dev_priv);
dumped = true;
}
}
mutex_unlock(&power_domains->lock);
}
/**
* intel_runtime_pm_get - grab a runtime pm reference
* @dev_priv: i915 device instance