]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
PM: Check power.needs_force_resume in pm_runtime_force_suspend()
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 27 Jun 2025 19:19:31 +0000 (21:19 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 3 Jul 2025 15:10:40 +0000 (17:10 +0200)
Add a power.needs_force_resume check to pm_runtime_force_suspend() so
it need not rely on the runtime PM status of the device when deciding
whether or not to return early.

With the new check in place, pm_runtime_force_suspend() will also skip
devices with the runtime PM status equal to RPM_ACTIVE if they have
power.needs_force_resume set, so it won't need to change the RPM
status of the device to RPM_SUSPENDED in addition to setting
power.needs_force_resume in the case when pm_runtime_need_not_resume()
return false.

That allows the runtime PM status update to be removed from
pm_runtime_force_resume(), so the runtime PM status remains unchanged
between the pm_runtime_force_suspend() and pm_runtime_force_resume()
calls.

This change potentially unbreaks drivers that call pm_runtime_force_suspend()
from their ->remove() callbacks because currently, if the device being
unbound from its driver has a parent with enabled runtime PM and/or
(possibly) device links respecting runtime PM to suppliers, and it is
RPM_ACTIVE when the remove takes place, pm_runtime_force_suspend() will
not drop the parent's child count and the suppliers' runtime PM usage
counters after force-suspending the device unless pm_runtime_need_not_resume()
returns 'true' for it.  Moreover, because pm_runtime_force_suspend()
changes the device's runtime PM status to RPM_SUSPENDED, in the above
case pm_runtime_reinit() will not cause those counters to drop, so they
will remain nonzero forever effectively preventing the devices in
question from runtime-suspending going forward.

This change is also needed for pm_runtime_force_suspend() to work
with PCI PM and ACPI PM after subsequent changes.  Namely, say
DPM_FLAG_SMART_SUSPEND is set for a PCI device and its driver uses
pm_runtime_force_suspend() as its ->suspend() callback.  If
pm_runtime_force_suspend() changed the runtime PM status of the
device to RPM_SUSPENDED, pci_pm_suspend_noirq() would skip the
device due to the dev_pm_skip_suspend() check.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/1855933.VLH7GnMWUR@rjwysocki.net
drivers/base/power/runtime.c

index d863b13c2e05a047fe50c33499e025dcf1381005..f61b7fa183e016dcba3e6c1a91ef8f1d5ed302e3 100644 (file)
@@ -1969,7 +1969,7 @@ int pm_runtime_force_suspend(struct device *dev)
        int ret;
 
        pm_runtime_disable(dev);
-       if (pm_runtime_status_suspended(dev))
+       if (pm_runtime_status_suspended(dev) || dev->power.needs_force_resume)
                return 0;
 
        callback = RPM_GET_CALLBACK(dev, runtime_suspend);
@@ -1984,15 +1984,16 @@ int pm_runtime_force_suspend(struct device *dev)
        /*
         * If the device can stay in suspend after the system-wide transition
         * to the working state that will follow, drop the children counter of
-        * its parent, but set its status to RPM_SUSPENDED anyway in case this
-        * function will be called again for it in the meantime.
+        * its parent and the usage counters of its suppliers.  Otherwise, set
+        * power.needs_force_resume to let pm_runtime_force_resume() know that
+        * the device needs to be taken care of and to prevent this function
+        * from handling the device again in case the device is passed to it
+        * once more subsequently.
         */
-       if (pm_runtime_need_not_resume(dev)) {
+       if (pm_runtime_need_not_resume(dev))
                pm_runtime_set_suspended(dev);
-       } else {
-               __update_runtime_status(dev, RPM_SUSPENDED);
+       else
                dev->power.needs_force_resume = true;
-       }
 
        return 0;
 
@@ -2033,12 +2034,6 @@ int pm_runtime_force_resume(struct device *dev)
            pm_runtime_status_suspended(dev)))
                goto out;
 
-       /*
-        * The value of the parent's children counter is correct already, so
-        * just update the status of the device.
-        */
-       __update_runtime_status(dev, RPM_ACTIVE);
-
        callback = RPM_GET_CALLBACK(dev, runtime_resume);
 
        dev_pm_disable_wake_irq_check(dev, false);