All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bjorn Helgaas <helgaas@kernel.org>
To: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Linux PM <linux-pm@vger.kernel.org>,
	LKML <linux-kernel@vger.kernel.org>,
	Alan Stern <stern@rowland.harvard.edu>,
	Linux PCI <linux-pci@vger.kernel.org>,
	Ulf Hansson <ulf.hansson@linaro.org>,
	Johan Hovold <johan@kernel.org>,
	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>,
	Jon Hunter <jonathanh@nvidia.com>,
	Linux ACPI <linux-acpi@vger.kernel.org>,
	Mika Westerberg <mika.westerberg@linux.intel.com>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Subject: Re: [PATCH v2 3/4] PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally
Date: Tue, 18 Feb 2025 16:20:11 -0600	[thread overview]
Message-ID: <20250218222011.GA196831@bhelgaas> (raw)
In-Reply-To: <1914558.tdWV9SEqCh@rjwysocki.net>

On Tue, Feb 18, 2025 at 09:16:48PM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> A recent discussion has revealed that using DPM_FLAG_SMART_SUSPEND
> unconditionally is generally problematic because it may lead to
> situations in which the device's runtime PM information is internally
> inconsistent or does not reflect its real state [1].
> 
> For this reason, change the handling of DPM_FLAG_SMART_SUSPEND so that
> it is only taken into account if it is consistently set by the drivers
> of all devices having any PM callbacks throughout dependency graphs in
> accordance with the following rules:
> 
>  - The "smart suspend" feature is only enabled for devices whose drivers
>    ask for it (that is, set DPM_FLAG_SMART_SUSPEND) and for devices
>    without PM callbacks unless they have never had runtime PM enabled.
> 
>  - The "smart suspend" feature is not enabled for a device if it has not
>    been enabled for the device's parent unless the parent does not take
>    children into account or it has never had runtime PM enabled.
> 
>  - The "smart suspend" feature is not enabled for a device if it has not
>    been enabled for one of the device's suppliers taking runtime PM into
>    account unless that supplier has never had runtime PM enabled.
> 
> Namely, introduce a new device PM flag called smart_suspend that is only
> set if the above conditions are met and update all DPM_FLAG_SMART_SUSPEND
> users to check power.smart_suspend instead of directly checking the
> latter.
> 
> At the same time, drop the power.set_active flage introduced recently
> in commit 3775fc538f53 ("PM: sleep: core: Synchronize runtime PM status
> of parents and children") because it is now sufficient to check
> power.smart_suspend along with the dev_pm_skip_resume() return value
> to decide whether or not pm_runtime_set_active() needs to be called
> for the device.
> 
> Link: https://lore.kernel.org/linux-pm/CAPDyKFroyU3YDSfw_Y6k3giVfajg3NQGwNWeteJWqpW29BojhQ@mail.gmail.com/  [1]
> Fixes: 7585946243d6 ("PM: sleep: core: Restrict power.set_active propagation")
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Acked-by: Bjorn Helgaas <bhelgaas@google.com> # drivers/pci

> ---
> 
> v1 -> v2:
>    * Add helper function for reading power.smart_suspend() (Ulf), add the R-by.
>    * Rearrange conditionals in device_prepare_smart_suspend() so that the checks
>      involving locking are done last.
> 
> ---
>  drivers/acpi/device_pm.c  |    4 +-
>  drivers/base/power/main.c |   63 +++++++++++++++++++++++++++++++++++-----------
>  drivers/mfd/intel-lpss.c  |    2 -
>  drivers/pci/pci-driver.c  |    6 +---
>  include/linux/device.h    |    5 +++
>  include/linux/pm.h        |    2 -
>  6 files changed, 60 insertions(+), 22 deletions(-)
> 
> --- a/drivers/acpi/device_pm.c
> +++ b/drivers/acpi/device_pm.c
> @@ -1161,7 +1161,7 @@
>   */
>  int acpi_subsys_suspend(struct device *dev)
>  {
> -	if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
> +	if (!dev_pm_smart_suspend(dev) ||
>  	    acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
>  		pm_runtime_resume(dev);
>  
> @@ -1320,7 +1320,7 @@
>   */
>  int acpi_subsys_poweroff(struct device *dev)
>  {
> -	if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
> +	if (!dev_pm_smart_suspend(dev) ||
>  	    acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
>  		pm_runtime_resume(dev);
>  
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -656,15 +656,13 @@
>  	 * so change its status accordingly.
>  	 *
>  	 * Otherwise, the device is going to be resumed, so set its PM-runtime
> -	 * status to "active" unless its power.set_active flag is clear, in
> +	 * status to "active" unless its power.smart_suspend flag is clear, in
>  	 * which case it is not necessary to update its PM-runtime status.
>  	 */
> -	if (skip_resume) {
> +	if (skip_resume)
>  		pm_runtime_set_suspended(dev);
> -	} else if (dev->power.set_active) {
> +	else if (dev_pm_smart_suspend(dev))
>  		pm_runtime_set_active(dev);
> -		dev->power.set_active = false;
> -	}
>  
>  	if (dev->pm_domain) {
>  		info = "noirq power domain ";
> @@ -1282,14 +1280,8 @@
>  	      dev->power.may_skip_resume))
>  		dev->power.must_resume = true;
>  
> -	if (dev->power.must_resume) {
> -		if (dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) {
> -			dev->power.set_active = true;
> -			if (dev->parent && !dev->parent->power.ignore_children)
> -				dev->parent->power.set_active = true;
> -		}
> +	if (dev->power.must_resume)
>  		dpm_superior_set_must_resume(dev);
> -	}
>  
>  Complete:
>  	complete_all(&dev->power.completion);
> @@ -1797,6 +1789,49 @@
>  	return error;
>  }
>  
> +static void device_prepare_smart_suspend(struct device *dev)
> +{
> +	struct device_link *link;
> +	int idx;
> +
> +	/*
> +	 * The "smart suspend" feature is enabled for devices whose drivers ask
> +	 * for it and for devices without PM callbacks unless runtime PM is
> +	 * disabled and enabling it is blocked for them.
> +	 *
> +	 * However, if "smart suspend" is not enabled for the device's parent
> +	 * or any of its suppliers that take runtime PM into account, it cannot
> +	 * be enabled for the device either.
> +	 */
> +	dev->power.smart_suspend = (dev->power.no_pm_callbacks ||
> +		dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) &&
> +		!pm_runtime_blocked(dev);
> +
> +	if (!dev_pm_smart_suspend(dev))
> +		return;
> +
> +	if (dev->parent && !dev_pm_smart_suspend(dev->parent) &&
> +	    !dev->parent->power.ignore_children && !pm_runtime_blocked(dev->parent)) {
> +		dev->power.smart_suspend = false;
> +		return;
> +	}
> +
> +	idx = device_links_read_lock();
> +
> +	list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
> +		if (!(link->flags | DL_FLAG_PM_RUNTIME))
> +			continue;
> +
> +		if (!dev_pm_smart_suspend(link->supplier) &&
> +		    !pm_runtime_blocked(link->supplier)) {
> +			dev->power.smart_suspend = false;
> +			break;
> +		}
> +	}
> +
> +	device_links_read_unlock(idx);
> +}
> +
>  /**
>   * device_prepare - Prepare a device for system power transition.
>   * @dev: Device to handle.
> @@ -1858,6 +1893,7 @@
>  		pm_runtime_put(dev);
>  		return ret;
>  	}
> +	device_prepare_smart_suspend(dev);
>  	/*
>  	 * A positive return value from ->prepare() means "this device appears
>  	 * to be runtime-suspended and its state is fine, so if it really is
> @@ -2033,6 +2069,5 @@
>  
>  bool dev_pm_skip_suspend(struct device *dev)
>  {
> -	return dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) &&
> -		pm_runtime_status_suspended(dev);
> +	return dev_pm_smart_suspend(dev) && pm_runtime_status_suspended(dev);
>  }
> --- a/drivers/mfd/intel-lpss.c
> +++ b/drivers/mfd/intel-lpss.c
> @@ -480,7 +480,7 @@
>  
>  static int resume_lpss_device(struct device *dev, void *data)
>  {
> -	if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
> +	if (!dev_pm_smart_suspend(dev))
>  		pm_runtime_resume(dev);
>  
>  	return 0;
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -812,8 +812,7 @@
>  	 * suspend callbacks can cope with runtime-suspended devices, it is
>  	 * better to resume the device from runtime suspend here.
>  	 */
> -	if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
> -	    pci_dev_need_resume(pci_dev)) {
> +	if (!dev_pm_smart_suspend(dev) || pci_dev_need_resume(pci_dev)) {
>  		pm_runtime_resume(dev);
>  		pci_dev->state_saved = false;
>  	} else {
> @@ -1151,8 +1150,7 @@
>  	}
>  
>  	/* The reason to do that is the same as in pci_pm_suspend(). */
> -	if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
> -	    pci_dev_need_resume(pci_dev)) {
> +	if (!dev_pm_smart_suspend(dev) || pci_dev_need_resume(pci_dev)) {
>  		pm_runtime_resume(dev);
>  		pci_dev->state_saved = false;
>  	} else {
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -1025,6 +1025,11 @@
>  	return !!(dev->power.driver_flags & flags);
>  }
>  
> +static inline bool dev_pm_smart_suspend(struct device *dev)
> +{
> +	return dev->power.smart_suspend;
> +}
> +
>  static inline void device_lock(struct device *dev)
>  {
>  	mutex_lock(&dev->mutex);
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -680,8 +680,8 @@
>  	bool			syscore:1;
>  	bool			no_pm_callbacks:1;	/* Owned by the PM core */
>  	bool			async_in_progress:1;	/* Owned by the PM core */
> +	bool			smart_suspend:1;	/* Owned by the PM core */
>  	bool			must_resume:1;		/* Owned by the PM core */
> -	bool			set_active:1;		/* Owned by the PM core */
>  	bool			may_skip_resume:1;	/* Set by subsystems */
>  #else
>  	bool			should_wakeup:1;
> 
> 
> 

  reply	other threads:[~2025-02-18 22:20 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-18 20:09 [PATCH v2 0/4] PM: Use DPM_FLAG_SMART_SUSPEND conditionally Rafael J. Wysocki
2025-02-18 20:11 ` [PATCH v2 1/4] PM: Block enabling of runtime PM during system suspend Rafael J. Wysocki
2025-02-18 20:13 ` [PATCH v2 2/4] PM: runtime: Introduce pm_runtime_blocked() Rafael J. Wysocki
2025-02-18 20:16 ` [PATCH v2 3/4] PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally Rafael J. Wysocki
2025-02-18 22:20   ` Bjorn Helgaas [this message]
2025-02-19 12:14     ` Rafael J. Wysocki
2025-02-18 20:20 ` [PATCH v2 4/4] PM: sleep: Avoid unnecessary checks in device_prepare_smart_suspend() Rafael J. Wysocki
2025-03-03 11:35   ` Ulf Hansson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250218222011.GA196831@bhelgaas \
    --to=helgaas@kernel.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=johan@kernel.org \
    --cc=jonathanh@nvidia.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=manivannan.sadhasivam@linaro.org \
    --cc=mika.westerberg@linux.intel.com \
    --cc=rjw@rjwysocki.net \
    --cc=stern@rowland.harvard.edu \
    --cc=ulf.hansson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.