Re: [PATCH] drm/i915: Fix hibernation with ACPI S0 target state

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Mar 22, 2018 at 04:36:42PM +0200, Imre Deak wrote:
> After
> 
> commit dd9f31c7a3887950cbd0d49eb9d43f7a1518a356
> Author: Imre Deak <imre.deak@xxxxxxxxx>
> Date:   Wed Aug 16 17:46:07 2017 +0300
> 
>     drm/i915/gen9+: Set same power state before hibernation image
>     save/restore
> 
> during hibernation/suspend the power domain functionality got disabled,
> after which resume could leave it incorrectly disabled if the ACPI
> target state was S0 during suspend and i915 was not loaded by the loader
> kernel.
> 
> This was caused by not considering if we resumed from hibernation as the
> condition for power domains reiniting.
> 
> Fix this by simply tracking if we suspended power domains during system
> suspend and reinit power domains accordingly during resume. This will
> result in reiniting power domains always when resuming from hibernation,
> regardless of the platform and whether or not i915 is loaded by the
> loader kernel.
> 
> The reason we didn't catch this earlier is that the enabled/disabled
> state of power domains during PMSG_FREEZE/PMSG_QUIESCE is platform
> and kernel config dependent: on my SKL the target state is S4
> during PMSG_FREEZE and (with the driver loaded in the loader kernel)
> S0 during PMSG_QUIESCE. On the reporter's machine it's S0 during
> PMSG_FREEZE but (contrary to this) power domains are not initialized
> during PMSG_QUIESCE since i915 is not loaded in the loader kernel, or
> it's loaded but without the DMC firmware being available.
> 
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105196
> Reported-and-tested-by: amn-bas@xxxxxxxxxxx
> Fixes: dd9f31c7a388 ("drm/i915/gen9+: Set same power state before hibernation image save/restore")
> Cc: amn-bas@xxxxxxxxxxx
> Cc: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx>
> Cc: <stable@xxxxxxxxxxxxxxx>
> Signed-off-by: Imre Deak <imre.deak@xxxxxxxxx>

Make sense to me.
Reviewed-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx>

On thing I can't quite tell is what happens with switcheroo. Maybe it's
not even relevant for platforms with DC6 in which case I suppose it
should work correctly.

> ---
>  drivers/gpu/drm/i915/i915_drv.c | 22 ++++++++++------------
>  drivers/gpu/drm/i915/i915_drv.h |  2 +-
>  2 files changed, 11 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index a7d3275f45d2..f706cff4f01b 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -1612,15 +1612,12 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct pci_dev *pdev = dev_priv->drm.pdev;
> -	bool fw_csr;
>  	int ret;
>  
>  	disable_rpm_wakeref_asserts(dev_priv);
>  
>  	intel_display_set_init_power(dev_priv, false);
>  
> -	fw_csr = !IS_GEN9_LP(dev_priv) && !hibernation &&
> -		suspend_to_idle(dev_priv) && dev_priv->csr.dmc_payload;
>  	/*
>  	 * In case of firmware assisted context save/restore don't manually
>  	 * deinit the power domains. This also means the CSR/DMC firmware will
> @@ -1628,8 +1625,11 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
>  	 * also enable deeper system power states that would be blocked if the
>  	 * firmware was inactive.
>  	 */
> -	if (!fw_csr)
> +	if (IS_GEN9_LP(dev_priv) || hibernation || !suspend_to_idle(dev_priv) ||
> +	    dev_priv->csr.dmc_payload == NULL) {
>  		intel_power_domains_suspend(dev_priv);
> +		dev_priv->power_domains_suspended = true;
> +	}
>  
>  	ret = 0;
>  	if (IS_GEN9_LP(dev_priv))
> @@ -1641,8 +1641,10 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
>  
>  	if (ret) {
>  		DRM_ERROR("Suspend complete failed: %d\n", ret);
> -		if (!fw_csr)
> +		if (dev_priv->power_domains_suspended) {
>  			intel_power_domains_init_hw(dev_priv, true);
> +			dev_priv->power_domains_suspended = false;
> +		}
>  
>  		goto out;
>  	}
> @@ -1663,8 +1665,6 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
>  	if (!(hibernation && INTEL_GEN(dev_priv) < 6))
>  		pci_set_power_state(pdev, PCI_D3hot);
>  
> -	dev_priv->suspended_to_idle = suspend_to_idle(dev_priv);
> -
>  out:
>  	enable_rpm_wakeref_asserts(dev_priv);
>  
> @@ -1831,8 +1831,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
>  	intel_uncore_resume_early(dev_priv);
>  
>  	if (IS_GEN9_LP(dev_priv)) {
> -		if (!dev_priv->suspended_to_idle)
> -			gen9_sanitize_dc_state(dev_priv);
> +		gen9_sanitize_dc_state(dev_priv);
>  		bxt_disable_dc9(dev_priv);
>  	} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
>  		hsw_disable_pc8(dev_priv);
> @@ -1840,8 +1839,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
>  
>  	intel_uncore_sanitize(dev_priv);
>  
> -	if (IS_GEN9_LP(dev_priv) ||
> -	    !(dev_priv->suspended_to_idle && dev_priv->csr.dmc_payload))
> +	if (dev_priv->power_domains_suspended)
>  		intel_power_domains_init_hw(dev_priv, true);
>  	else
>  		intel_display_set_init_power(dev_priv, true);
> @@ -1851,7 +1849,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
>  	enable_rpm_wakeref_asserts(dev_priv);
>  
>  out:
> -	dev_priv->suspended_to_idle = false;
> +	dev_priv->power_domains_suspended = false;
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index c9c3b2ba6a86..3acc4bbec6b2 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1851,7 +1851,7 @@ struct drm_i915_private {
>  	u32 bxt_phy_grc;
>  
>  	u32 suspend_count;
> -	bool suspended_to_idle;
> +	bool power_domains_suspended;
>  	struct i915_suspend_saved_registers regfile;
>  	struct vlv_s0ix_state vlv_s0ix_state;
>  
> -- 
> 2.13.2

-- 
Ville Syrjälä
Intel OTC



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]