Skip to content

Commit f384497

Browse files
committed
PM: sleep: core: Fix runtime PM enabling in device_resume_early()
Runtime PM should only be enabled in device_resume_early() if it has been disabled for the given device by device_suspend_late(). Otherwise, it may cause runtime PM callbacks to run prematurely in some cases which leads to further functional issues. Make two changes to address this problem. First, reorder device_suspend_late() to only disable runtime PM for a device when it is going to look for the device's callback or if the device is a "syscore" one. In all of the other cases, disabling runtime PM for the device is not in fact necessary. However, if the device's callback returns an error and the power.is_late_suspended flag is not going to be set, enable runtime PM so it only remains disabled when power.is_late_suspended is set. Second, make device_resume_early() only enable runtime PM for the devices with the power.is_late_suspended flag set. Fixes: 443046d ("PM: sleep: Make suspend of devices more asynchronous") Reported-by: Rose Wu <[email protected]> Closes: https://lore.kernel.org/linux-pm/[email protected]/ Cc: 6.16+ <[email protected]> # 6.16+ Reviewed-by: Ulf Hansson <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 6a23ae0 commit f384497

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

drivers/base/power/main.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -888,12 +888,15 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
888888
TRACE_DEVICE(dev);
889889
TRACE_RESUME(0);
890890

891-
if (dev->power.syscore || dev->power.direct_complete)
891+
if (dev->power.direct_complete)
892892
goto Out;
893893

894894
if (!dev->power.is_late_suspended)
895895
goto Out;
896896

897+
if (dev->power.syscore)
898+
goto Skip;
899+
897900
if (!dpm_wait_for_superior(dev, async))
898901
goto Out;
899902

@@ -926,11 +929,11 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
926929

927930
Skip:
928931
dev->power.is_late_suspended = false;
932+
pm_runtime_enable(dev);
929933

930934
Out:
931935
TRACE_RESUME(error);
932936

933-
pm_runtime_enable(dev);
934937
complete_all(&dev->power.completion);
935938

936939
if (error) {
@@ -1615,12 +1618,6 @@ static void device_suspend_late(struct device *dev, pm_message_t state, bool asy
16151618
TRACE_DEVICE(dev);
16161619
TRACE_SUSPEND(0);
16171620

1618-
/*
1619-
* Disable runtime PM for the device without checking if there is a
1620-
* pending resume request for it.
1621-
*/
1622-
__pm_runtime_disable(dev, false);
1623-
16241621
dpm_wait_for_subordinate(dev, async);
16251622

16261623
if (READ_ONCE(async_error))
@@ -1631,9 +1628,18 @@ static void device_suspend_late(struct device *dev, pm_message_t state, bool asy
16311628
goto Complete;
16321629
}
16331630

1634-
if (dev->power.syscore || dev->power.direct_complete)
1631+
if (dev->power.direct_complete)
16351632
goto Complete;
16361633

1634+
/*
1635+
* Disable runtime PM for the device without checking if there is a
1636+
* pending resume request for it.
1637+
*/
1638+
__pm_runtime_disable(dev, false);
1639+
1640+
if (dev->power.syscore)
1641+
goto Skip;
1642+
16371643
if (dev->pm_domain) {
16381644
info = "late power domain ";
16391645
callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -1664,6 +1670,7 @@ static void device_suspend_late(struct device *dev, pm_message_t state, bool asy
16641670
WRITE_ONCE(async_error, error);
16651671
dpm_save_failed_dev(dev_name(dev));
16661672
pm_dev_err(dev, state, async ? " async late" : " late", error);
1673+
pm_runtime_enable(dev);
16671674
goto Complete;
16681675
}
16691676
dpm_propagate_wakeup_to_parent(dev);

0 commit comments

Comments
 (0)