drm/i915: Track the wakeref used to initialise display power domains
authorChris Wilson <chris@chris-wilson.co.uk>
Mon, 14 Jan 2019 14:21:25 +0000 (14:21 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 14 Jan 2019 16:18:38 +0000 (16:18 +0000)
On module load and unload, we grab the POWER_DOMAIN_INIT powerwells and
transfer them to the runtime-pm code. We can use our wakeref tracking to
verify that the wakeref is indeed passed from init to enable, and
disable to fini; and across suspend.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190114142129.24398-17-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_runtime_pm.c

index e846608ee6aa6b916dfd144730a42f75ae1a1203..926acd5b6e5d649ae7683281ae91b0294d36bd2c 100644 (file)
@@ -2699,6 +2699,9 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused)
        if (!HAS_RUNTIME_PM(dev_priv))
                seq_puts(m, "Runtime power management not supported\n");
 
+       seq_printf(m, "Runtime power status: %s\n",
+                  enableddisabled(!dev_priv->power_domains.wakeref));
+
        seq_printf(m, "GPU idle: %s (epoch %u)\n",
                   yesno(!dev_priv->gt.awake), dev_priv->gt.epoch);
        seq_printf(m, "IRQs disabled: %s\n",
index 0aedbb88eb5b0f5b14b6bd256d0f0a8ba65b3603..97200411dfadbd3ff654de378552cd824c9462cc 100644 (file)
@@ -822,6 +822,8 @@ struct i915_power_domains {
        bool display_core_suspended;
        int power_well_count;
 
+       intel_wakeref_t wakeref;
+
        struct mutex lock;
        int domain_use_count[POWER_DOMAIN_NUM];
        struct i915_power_well *power_wells;
index 6aeceab37000121ff174d1c4af988fc5994f6ac3..79f00610860b9988e803131899b03719d6bce341 100644 (file)
@@ -3997,7 +3997,7 @@ static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv);
 
 /**
  * intel_power_domains_init_hw - initialize hardware power domain state
- * @dev_priv: i915 device instance
+ * @i915: i915 device instance
  * @resume: Called from resume code paths or not
  *
  * This function initializes the hardware power domain state and enables all
@@ -4011,30 +4011,31 @@ static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv);
  * intel_power_domains_enable()) and must be paired with
  * intel_power_domains_fini_hw().
  */
-void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
+void intel_power_domains_init_hw(struct drm_i915_private *i915, bool resume)
 {
-       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       struct i915_power_domains *power_domains = &i915->power_domains;
 
        power_domains->initializing = true;
 
-       if (IS_ICELAKE(dev_priv)) {
-               icl_display_core_init(dev_priv, resume);
-       } else if (IS_CANNONLAKE(dev_priv)) {
-               cnl_display_core_init(dev_priv, resume);
-       } else if (IS_GEN9_BC(dev_priv)) {
-               skl_display_core_init(dev_priv, resume);
-       } else if (IS_GEN9_LP(dev_priv)) {
-               bxt_display_core_init(dev_priv, resume);
-       } else if (IS_CHERRYVIEW(dev_priv)) {
+       if (IS_ICELAKE(i915)) {
+               icl_display_core_init(i915, resume);
+       } else if (IS_CANNONLAKE(i915)) {
+               cnl_display_core_init(i915, resume);
+       } else if (IS_GEN9_BC(i915)) {
+               skl_display_core_init(i915, resume);
+       } else if (IS_GEN9_LP(i915)) {
+               bxt_display_core_init(i915, resume);
+       } else if (IS_CHERRYVIEW(i915)) {
                mutex_lock(&power_domains->lock);
-               chv_phy_control_init(dev_priv);
+               chv_phy_control_init(i915);
                mutex_unlock(&power_domains->lock);
-       } else if (IS_VALLEYVIEW(dev_priv)) {
+       } else if (IS_VALLEYVIEW(i915)) {
                mutex_lock(&power_domains->lock);
-               vlv_cmnlane_wa(dev_priv);
+               vlv_cmnlane_wa(i915);
                mutex_unlock(&power_domains->lock);
-       } else if (IS_IVYBRIDGE(dev_priv) || INTEL_GEN(dev_priv) >= 7)
-               intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv));
+       } else if (IS_IVYBRIDGE(i915) || INTEL_GEN(i915) >= 7) {
+               intel_pch_reset_handshake(i915, !HAS_PCH_NOP(i915));
+       }
 
        /*
         * Keep all power wells enabled for any dependent HW access during
@@ -4042,18 +4043,20 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
         * resources powered until display HW readout is complete. We drop
         * this reference in intel_power_domains_enable().
         */
-       intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+       power_domains->wakeref =
+               intel_display_power_get(i915, POWER_DOMAIN_INIT);
+
        /* Disable power support if the user asked so. */
        if (!i915_modparams.disable_power_well)
-               intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
-       intel_power_domains_sync_hw(dev_priv);
+               intel_display_power_get(i915, POWER_DOMAIN_INIT);
+       intel_power_domains_sync_hw(i915);
 
        power_domains->initializing = false;
 }
 
 /**
  * intel_power_domains_fini_hw - deinitialize hw power domain state
- * @dev_priv: i915 device instance
+ * @i915: i915 device instance
  *
  * De-initializes the display power domain HW state. It also ensures that the
  * device stays powered up so that the driver can be reloaded.
@@ -4062,21 +4065,24 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
  * intel_power_domains_disable()) and must be paired with
  * intel_power_domains_init_hw().
  */
-void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv)
+void intel_power_domains_fini_hw(struct drm_i915_private *i915)
 {
-       /* Keep the power well enabled, but cancel its rpm wakeref. */
-       intel_runtime_pm_put_unchecked(dev_priv);
+       intel_wakeref_t wakeref __maybe_unused =
+               fetch_and_zero(&i915->power_domains.wakeref);
 
        /* Remove the refcount we took to keep power well support disabled. */
        if (!i915_modparams.disable_power_well)
-               intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
+               intel_display_power_put_unchecked(i915, POWER_DOMAIN_INIT);
+
+       intel_power_domains_verify_state(i915);
 
-       intel_power_domains_verify_state(dev_priv);
+       /* Keep the power well enabled, but cancel its rpm wakeref. */
+       intel_runtime_pm_put(i915, wakeref);
 }
 
 /**
  * intel_power_domains_enable - enable toggling of display power wells
- * @dev_priv: i915 device instance
+ * @i915: i915 device instance
  *
  * Enable the ondemand enabling/disabling of the display power wells. Note that
  * power wells not belonging to POWER_DOMAIN_INIT are allowed to be toggled
@@ -4086,30 +4092,36 @@ void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv)
  * of display HW readout (which will acquire the power references reflecting
  * the current HW state).
  */
-void intel_power_domains_enable(struct drm_i915_private *dev_priv)
+void intel_power_domains_enable(struct drm_i915_private *i915)
 {
-       intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
+       intel_wakeref_t wakeref __maybe_unused =
+               fetch_and_zero(&i915->power_domains.wakeref);
 
-       intel_power_domains_verify_state(dev_priv);
+       intel_display_power_put(i915, POWER_DOMAIN_INIT, wakeref);
+       intel_power_domains_verify_state(i915);
 }
 
 /**
  * intel_power_domains_disable - disable toggling of display power wells
- * @dev_priv: i915 device instance
+ * @i915: i915 device instance
  *
  * Disable the ondemand enabling/disabling of the display power wells. See
  * intel_power_domains_enable() for which power wells this call controls.
  */
-void intel_power_domains_disable(struct drm_i915_private *dev_priv)
+void intel_power_domains_disable(struct drm_i915_private *i915)
 {
-       intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+       struct i915_power_domains *power_domains = &i915->power_domains;
 
-       intel_power_domains_verify_state(dev_priv);
+       WARN_ON(power_domains->wakeref);
+       power_domains->wakeref =
+               intel_display_power_get(i915, POWER_DOMAIN_INIT);
+
+       intel_power_domains_verify_state(i915);
 }
 
 /**
  * intel_power_domains_suspend - suspend power domain state
- * @dev_priv: i915 device instance
+ * @i915: i915 device instance
  * @suspend_mode: specifies the target suspend state (idle, mem, hibernation)
  *
  * This function prepares the hardware power domain state before entering
@@ -4118,12 +4130,14 @@ void intel_power_domains_disable(struct drm_i915_private *dev_priv)
  * It must be called with power domains already disabled (after a call to
  * intel_power_domains_disable()) and paired with intel_power_domains_resume().
  */
-void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
+void intel_power_domains_suspend(struct drm_i915_private *i915,
                                 enum i915_drm_suspend_mode suspend_mode)
 {
-       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       struct i915_power_domains *power_domains = &i915->power_domains;
+       intel_wakeref_t wakeref __maybe_unused =
+               fetch_and_zero(&power_domains->wakeref);
 
-       intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
+       intel_display_power_put(i915, POWER_DOMAIN_INIT, wakeref);
 
        /*
         * In case of suspend-to-idle (aka S0ix) on a DMC platform without DC9
@@ -4132,10 +4146,10 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
         * resources as required and also enable deeper system power states
         * that would be blocked if the firmware was inactive.
         */
-       if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC9) &&
+       if (!(i915->csr.allowed_dc_mask & DC_STATE_EN_DC9) &&
            suspend_mode == I915_DRM_SUSPEND_IDLE &&
-           dev_priv->csr.dmc_payload != NULL) {
-               intel_power_domains_verify_state(dev_priv);
+           i915->csr.dmc_payload) {
+               intel_power_domains_verify_state(i915);
                return;
        }
 
@@ -4144,25 +4158,25 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
         * power wells if power domains must be deinitialized for suspend.
         */
        if (!i915_modparams.disable_power_well) {
-               intel_display_power_put_unchecked(dev_priv, POWER_DOMAIN_INIT);
-               intel_power_domains_verify_state(dev_priv);
+               intel_display_power_put_unchecked(i915, POWER_DOMAIN_INIT);
+               intel_power_domains_verify_state(i915);
        }
 
-       if (IS_ICELAKE(dev_priv))
-               icl_display_core_uninit(dev_priv);
-       else if (IS_CANNONLAKE(dev_priv))
-               cnl_display_core_uninit(dev_priv);
-       else if (IS_GEN9_BC(dev_priv))
-               skl_display_core_uninit(dev_priv);
-       else if (IS_GEN9_LP(dev_priv))
-               bxt_display_core_uninit(dev_priv);
+       if (IS_ICELAKE(i915))
+               icl_display_core_uninit(i915);
+       else if (IS_CANNONLAKE(i915))
+               cnl_display_core_uninit(i915);
+       else if (IS_GEN9_BC(i915))
+               skl_display_core_uninit(i915);
+       else if (IS_GEN9_LP(i915))
+               bxt_display_core_uninit(i915);
 
        power_domains->display_core_suspended = true;
 }
 
 /**
  * intel_power_domains_resume - resume power domain state
- * @dev_priv: i915 device instance
+ * @i915: i915 device instance
  *
  * This function resume the hardware power domain state during system resume.
  *
@@ -4170,28 +4184,30 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
  * intel_power_domains_enable()) and must be paired with
  * intel_power_domains_suspend().
  */
-void intel_power_domains_resume(struct drm_i915_private *dev_priv)
+void intel_power_domains_resume(struct drm_i915_private *i915)
 {
-       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       struct i915_power_domains *power_domains = &i915->power_domains;
 
        if (power_domains->display_core_suspended) {
-               intel_power_domains_init_hw(dev_priv, true);
+               intel_power_domains_init_hw(i915, true);
                power_domains->display_core_suspended = false;
        } else {
-               intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+               WARN_ON(power_domains->wakeref);
+               power_domains->wakeref =
+                       intel_display_power_get(i915, POWER_DOMAIN_INIT);
        }
 
-       intel_power_domains_verify_state(dev_priv);
+       intel_power_domains_verify_state(i915);
 }
 
 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
 
-static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv)
+static void intel_power_domains_dump_info(struct drm_i915_private *i915)
 {
-       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       struct i915_power_domains *power_domains = &i915->power_domains;
        struct i915_power_well *power_well;
 
-       for_each_power_well(dev_priv, power_well) {
+       for_each_power_well(i915, power_well) {
                enum intel_display_power_domain domain;
 
                DRM_DEBUG_DRIVER("%-25s %d\n",
@@ -4206,7 +4222,7 @@ static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv)
 
 /**
  * intel_power_domains_verify_state - verify the HW/SW state for all power wells
- * @dev_priv: i915 device instance
+ * @i915: 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
@@ -4214,22 +4230,21 @@ static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv)
  * acquiring reference counts for any power wells in use and disabling the
  * ones left on by BIOS but not required by any active output.
  */
-static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
+static void intel_power_domains_verify_state(struct drm_i915_private *i915)
 {
-       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       struct i915_power_domains *power_domains = &i915->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) {
+       for_each_power_well(i915, power_well) {
                enum intel_display_power_domain domain;
                int domains_count;
                bool enabled;
 
-               enabled = power_well->desc->ops->is_enabled(dev_priv,
-                                                           power_well);
+               enabled = power_well->desc->ops->is_enabled(i915, power_well);
                if ((power_well->count || power_well->desc->always_on) !=
                    enabled)
                        DRM_ERROR("power well %s state mismatch (refcount %d/enabled %d)",
@@ -4253,7 +4268,7 @@ static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
                static bool dumped;
 
                if (!dumped) {
-                       intel_power_domains_dump_info(dev_priv);
+                       intel_power_domains_dump_info(i915);
                        dumped = true;
                }
        }
@@ -4263,7 +4278,7 @@ static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
 
 #else
 
-static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
+static void intel_power_domains_verify_state(struct drm_i915_private *i915)
 {
 }