Skip to content

Commit 03f1444

Browse files
committed
PM: sleep: Fix handling devices with direct_complete set on errors
When dpm_suspend() fails, some devices with power.direct_complete set may not have been handled by device_suspend() yet, so runtime PM has not been disabled for them yet even though power.direct_complete is set. Since device_resume() expects that runtime PM has been disabled for all devices with power.direct_complete set, it will attempt to reenable runtime PM for the devices that have not been processed by device_suspend() which does not make sense. Had those devices had runtime PM disabled before device_suspend() had run, device_resume() would have inadvertently enable runtime PM for them, but this is not expected to happen because it would require ->prepare() callbacks to return positive values for devices with runtime PM disabled, which would be invalid. In practice, this issue is most likely benign because pm_runtime_enable() will not allow the "disable depth" counter to underflow, but it causes a warning message to be printed for each affected device. To allow device_resume() to distinguish the "direct complete" devices that have been processed by device_suspend() from those which have not been handled by it, make device_suspend() set power.is_suspended for "direct complete" devices. Next, move the power.is_suspended check in device_resume() before the power.direct_complete check in it to make it skip the "direct complete" devices that have not been handled by device_suspend(). This change is based on a preliminary patch from Saravana Kannan. Fixes: aae4518 ("PM / sleep: Mechanism to avoid resuming runtime-suspended devices unnecessarily") Link: https://lore.kernel.org/linux-pm/20241114220921.2529905-2-saravanak@google.com/ Reported-by: Saravana Kannan <saravanak@google.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Saravana Kannan <saravanak@google.com> Link: https://patch.msgid.link/12627587.O9o76ZdvQC@rjwysocki.net
1 parent 956af86 commit 03f1444

File tree

1 file changed

+4
-4
lines changed

1 file changed

+4
-4
lines changed

drivers/base/power/main.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,9 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
938938
if (dev->power.syscore)
939939
goto Complete;
940940

941+
if (!dev->power.is_suspended)
942+
goto Complete;
943+
941944
if (dev->power.direct_complete) {
942945
/*
943946
* Allow new children to be added under the device after this
@@ -963,9 +966,6 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
963966
*/
964967
dev->power.is_prepared = false;
965968

966-
if (!dev->power.is_suspended)
967-
goto Unlock;
968-
969969
if (dev->pm_domain) {
970970
info = "power domain ";
971971
callback = pm_op(&dev->pm_domain->ops, state);
@@ -1005,7 +1005,6 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
10051005
error = dpm_run_callback(callback, dev, state, info);
10061006
dev->power.is_suspended = false;
10071007

1008-
Unlock:
10091008
device_unlock(dev);
10101009
dpm_watchdog_clear(&wd);
10111010

@@ -1669,6 +1668,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
16691668
pm_runtime_disable(dev);
16701669
if (pm_runtime_status_suspended(dev)) {
16711670
pm_dev_dbg(dev, state, "direct-complete ");
1671+
dev->power.is_suspended = true;
16721672
goto Complete;
16731673
}
16741674

0 commit comments

Comments
 (0)