[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAJZ5v0iHsOw4_UbEWGk_-jPpc3q2K3fUXBs4T3JCooPGV10CHQ@mail.gmail.com>
Date: Tue, 18 Feb 2025 14:00:21 +0100
From: "Rafael J. Wysocki" <rafael@...nel.org>
To: Ulf Hansson <ulf.hansson@...aro.org>
Cc: "Rafael J. Wysocki" <rjw@...ysocki.net>, Linux PM <linux-pm@...r.kernel.org>,
LKML <linux-kernel@...r.kernel.org>, Alan Stern <stern@...land.harvard.edu>,
Bjorn Helgaas <helgaas@...nel.org>, Linux PCI <linux-pci@...r.kernel.org>,
Johan Hovold <johan@...nel.org>, Manivannan Sadhasivam <manivannan.sadhasivam@...aro.org>,
Jon Hunter <jonathanh@...dia.com>, Linux ACPI <linux-acpi@...r.kernel.org>,
Mika Westerberg <mika.westerberg@...ux.intel.com>,
Andy Shevchenko <andriy.shevchenko@...ux.intel.com>, Saravana Kannan <saravanak@...gle.com>
Subject: Re: [PATCH v1 3/3] PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally
On Tue, Feb 18, 2025 at 1:49 PM Ulf Hansson <ulf.hansson@...aro.org> wrote:
>
> + Saravana
>
> On Mon, 17 Feb 2025 at 21:19, Rafael J. Wysocki <rjw@...ysocki.net> wrote:
> >
> > From: Rafael J. Wysocki <rafael.j.wysocki@...el.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@...el.com>
> > ---
> > drivers/acpi/device_pm.c | 6 +---
> > drivers/base/power/main.c | 63 +++++++++++++++++++++++++++++++++++-----------
> > drivers/mfd/intel-lpss.c | 2 -
> > drivers/pci/pci-driver.c | 6 +---
> > include/linux/pm.h | 2 -
> > 5 files changed, 55 insertions(+), 24 deletions(-)
> >
> > --- a/drivers/acpi/device_pm.c
> > +++ b/drivers/acpi/device_pm.c
> > @@ -1161,8 +1161,7 @@
> > */
> > int acpi_subsys_suspend(struct device *dev)
> > {
> > - if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
> > - acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
> > + if (!dev->power.smart_suspend || acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
>
> Nitpick: Rather than checking the dev->power.smart_suspend flag
> directly here, perhaps we should provide a helper function that
> returns true when dev->power.smart_suspend is set? In this way, it's
> the PM core soley that operates on the flag.
I can add a wrapper around this, sure.
> > pm_runtime_resume(dev);
> >
> > return pm_generic_suspend(dev);
> > @@ -1320,8 +1319,7 @@
> > */
> > int acpi_subsys_poweroff(struct device *dev)
> > {
> > - if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
> > - acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
> > + if (!dev->power.smart_suspend || acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
> > pm_runtime_resume(dev);
> >
> > return pm_generic_poweroff(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->power.smart_suspend)
> > 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->power.smart_suspend)
> > + return;
> > +
> > + if (dev->parent && !pm_runtime_blocked(dev->parent) &&
> > + !dev->parent->power.ignore_children && !dev->parent->power.smart_suspend) {
> > + 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 (!pm_runtime_blocked(link->supplier) &&
> > + !link->supplier->power.smart_suspend) {
>
> This requires device_prepare() for all suppliers to be run before its
> consumer. Is that always the case?
Yes, it is by design.
> > + dev->power.smart_suspend = false;
> > + break;
> > + }
> > + }
> > +
> > + device_links_read_unlock(idx);
>
> From an execution overhead point of view, did you check if the above
> code had some measurable impact on the latency for dpm_prepare()?
It didn't on my systems.
For the vast majority of devices the overhead is just checking
power.no_pm_callbacks and DPM_FLAG_SMART_SUSPEND. For some,
pm_runtime_blocked() needs to be called which requires grabbing a
spinlock and there are only a few with power.smart_suspend set to
start with.
I'm wondering why you didn't have this concern regarding other changes
that involved walking suppliers or consumers, though.
Powered by blists - more mailing lists