Skip to content

Commit 5b2b6ba

Browse files
committed
PM: sleep: Rearrange suspend/resume error handling in the core
JIRA: https://issues.redhat.com/browse/RHEL-109251 commit dbd4bcc Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Date: Thu, 17 Jul 2025 19:59:49 +0000 Notice that device_suspend_noirq(), device_suspend_late() and device_suspend() all set async_error on errors, so they don't really need to return a value. Accordingly, make them all void and use async_error in their callers instead of their return values. Moreover, since async_error is updated concurrently without locking during asynchronous suspend and resume processing, use READ_ONCE() and WRITE_ONCE() for accessing it in those places to ensure that all of the accesses will be carried out as expected. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Saravana Kannan <saravanak@google.com> Link: https://patch.msgid.link/6198088.lOV4Wx5bFT@rjwysocki.net Signed-off-by: Mark Langsdorf <mlangsdo@redhat.com>
1 parent 9cdae71 commit 5b2b6ba

File tree

1 file changed

+35
-44
lines changed

1 file changed

+35
-44
lines changed

drivers/base/power/main.c

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
781781
TRACE_RESUME(error);
782782

783783
if (error) {
784-
async_error = error;
784+
WRITE_ONCE(async_error, error);
785785
dpm_save_failed_dev(dev_name(dev));
786786
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
787787
}
@@ -838,7 +838,7 @@ static void dpm_noirq_resume_devices(pm_message_t state)
838838
mutex_unlock(&dpm_list_mtx);
839839
async_synchronize_full();
840840
dpm_show_time(starttime, state, 0, "noirq");
841-
if (async_error)
841+
if (READ_ONCE(async_error))
842842
dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
843843

844844
trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false);
@@ -924,7 +924,7 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
924924
complete_all(&dev->power.completion);
925925

926926
if (error) {
927-
async_error = error;
927+
WRITE_ONCE(async_error, error);
928928
dpm_save_failed_dev(dev_name(dev));
929929
pm_dev_err(dev, state, async ? " async early" : " early", error);
930930
}
@@ -985,7 +985,7 @@ void dpm_resume_early(pm_message_t state)
985985
mutex_unlock(&dpm_list_mtx);
986986
async_synchronize_full();
987987
dpm_show_time(starttime, state, 0, "early");
988-
if (async_error)
988+
if (READ_ONCE(async_error))
989989
dpm_save_failed_step(SUSPEND_RESUME_EARLY);
990990

991991
trace_suspend_resume(TPS("dpm_resume_early"), state.event, false);
@@ -1100,7 +1100,7 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
11001100
TRACE_RESUME(error);
11011101

11021102
if (error) {
1103-
async_error = error;
1103+
WRITE_ONCE(async_error, error);
11041104
dpm_save_failed_dev(dev_name(dev));
11051105
pm_dev_err(dev, state, async ? " async" : "", error);
11061106
}
@@ -1164,7 +1164,7 @@ void dpm_resume(pm_message_t state)
11641164
mutex_unlock(&dpm_list_mtx);
11651165
async_synchronize_full();
11661166
dpm_show_time(starttime, state, 0, NULL);
1167-
if (async_error)
1167+
if (READ_ONCE(async_error))
11681168
dpm_save_failed_step(SUSPEND_RESUME);
11691169

11701170
cpufreq_resume();
@@ -1400,7 +1400,7 @@ static void async_suspend_noirq(void *data, async_cookie_t cookie);
14001400
* The driver of @dev will not receive interrupts while this function is being
14011401
* executed.
14021402
*/
1403-
static int device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
1403+
static void device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
14041404
{
14051405
pm_callback_t callback = NULL;
14061406
const char *info = NULL;
@@ -1411,7 +1411,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
14111411

14121412
dpm_wait_for_subordinate(dev, async);
14131413

1414-
if (async_error)
1414+
if (READ_ONCE(async_error))
14151415
goto Complete;
14161416

14171417
if (dev->power.syscore || dev->power.direct_complete)
@@ -1444,7 +1444,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
14441444
Run:
14451445
error = dpm_run_callback(callback, dev, state, info);
14461446
if (error) {
1447-
async_error = error;
1447+
WRITE_ONCE(async_error, error);
14481448
dpm_save_failed_dev(dev_name(dev));
14491449
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
14501450
goto Complete;
@@ -1470,12 +1470,10 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
14701470
complete_all(&dev->power.completion);
14711471
TRACE_SUSPEND(error);
14721472

1473-
if (error || async_error)
1474-
return error;
1473+
if (error || READ_ONCE(async_error))
1474+
return;
14751475

14761476
dpm_async_suspend_superior(dev, async_suspend_noirq);
1477-
1478-
return 0;
14791477
}
14801478

14811479
static void async_suspend_noirq(void *data, async_cookie_t cookie)
@@ -1490,7 +1488,7 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
14901488
{
14911489
ktime_t starttime = ktime_get();
14921490
struct device *dev;
1493-
int error = 0;
1491+
int error;
14941492

14951493
trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);
14961494

@@ -1521,13 +1519,13 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
15211519

15221520
mutex_unlock(&dpm_list_mtx);
15231521

1524-
error = device_suspend_noirq(dev, state, false);
1522+
device_suspend_noirq(dev, state, false);
15251523

15261524
put_device(dev);
15271525

15281526
mutex_lock(&dpm_list_mtx);
15291527

1530-
if (error || async_error) {
1528+
if (READ_ONCE(async_error)) {
15311529
dpm_async_suspend_complete_all(&dpm_late_early_list);
15321530
/*
15331531
* Move all devices to the target list to resume them
@@ -1541,9 +1539,8 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
15411539
mutex_unlock(&dpm_list_mtx);
15421540

15431541
async_synchronize_full();
1544-
if (!error)
1545-
error = async_error;
15461542

1543+
error = READ_ONCE(async_error);
15471544
if (error)
15481545
dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
15491546

@@ -1598,7 +1595,7 @@ static void async_suspend_late(void *data, async_cookie_t cookie);
15981595
*
15991596
* Runtime PM is disabled for @dev while this function is being executed.
16001597
*/
1601-
static int device_suspend_late(struct device *dev, pm_message_t state, bool async)
1598+
static void device_suspend_late(struct device *dev, pm_message_t state, bool async)
16021599
{
16031600
pm_callback_t callback = NULL;
16041601
const char *info = NULL;
@@ -1615,11 +1612,11 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16151612

16161613
dpm_wait_for_subordinate(dev, async);
16171614

1618-
if (async_error)
1615+
if (READ_ONCE(async_error))
16191616
goto Complete;
16201617

16211618
if (pm_wakeup_pending()) {
1622-
async_error = -EBUSY;
1619+
WRITE_ONCE(async_error, -EBUSY);
16231620
goto Complete;
16241621
}
16251622

@@ -1653,7 +1650,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16531650
Run:
16541651
error = dpm_run_callback(callback, dev, state, info);
16551652
if (error) {
1656-
async_error = error;
1653+
WRITE_ONCE(async_error, error);
16571654
dpm_save_failed_dev(dev_name(dev));
16581655
pm_dev_err(dev, state, async ? " async late" : " late", error);
16591656
goto Complete;
@@ -1667,12 +1664,10 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16671664
TRACE_SUSPEND(error);
16681665
complete_all(&dev->power.completion);
16691666

1670-
if (error || async_error)
1671-
return error;
1667+
if (error || READ_ONCE(async_error))
1668+
return;
16721669

16731670
dpm_async_suspend_superior(dev, async_suspend_late);
1674-
1675-
return 0;
16761671
}
16771672

16781673
static void async_suspend_late(void *data, async_cookie_t cookie)
@@ -1691,7 +1686,7 @@ int dpm_suspend_late(pm_message_t state)
16911686
{
16921687
ktime_t starttime = ktime_get();
16931688
struct device *dev;
1694-
int error = 0;
1689+
int error;
16951690

16961691
trace_suspend_resume(TPS("dpm_suspend_late"), state.event, true);
16971692

@@ -1724,13 +1719,13 @@ int dpm_suspend_late(pm_message_t state)
17241719

17251720
mutex_unlock(&dpm_list_mtx);
17261721

1727-
error = device_suspend_late(dev, state, false);
1722+
device_suspend_late(dev, state, false);
17281723

17291724
put_device(dev);
17301725

17311726
mutex_lock(&dpm_list_mtx);
17321727

1733-
if (error || async_error) {
1728+
if (READ_ONCE(async_error)) {
17341729
dpm_async_suspend_complete_all(&dpm_suspended_list);
17351730
/*
17361731
* Move all devices to the target list to resume them
@@ -1744,9 +1739,8 @@ int dpm_suspend_late(pm_message_t state)
17441739
mutex_unlock(&dpm_list_mtx);
17451740

17461741
async_synchronize_full();
1747-
if (!error)
1748-
error = async_error;
17491742

1743+
error = READ_ONCE(async_error);
17501744
if (error) {
17511745
dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
17521746
dpm_resume_early(resume_event(state));
@@ -1835,7 +1829,7 @@ static void async_suspend(void *data, async_cookie_t cookie);
18351829
* @state: PM transition of the system being carried out.
18361830
* @async: If true, the device is being suspended asynchronously.
18371831
*/
1838-
static int device_suspend(struct device *dev, pm_message_t state, bool async)
1832+
static void device_suspend(struct device *dev, pm_message_t state, bool async)
18391833
{
18401834
pm_callback_t callback = NULL;
18411835
const char *info = NULL;
@@ -1847,7 +1841,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
18471841

18481842
dpm_wait_for_subordinate(dev, async);
18491843

1850-
if (async_error) {
1844+
if (READ_ONCE(async_error)) {
18511845
dev->power.direct_complete = false;
18521846
goto Complete;
18531847
}
@@ -1867,7 +1861,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
18671861

18681862
if (pm_wakeup_pending()) {
18691863
dev->power.direct_complete = false;
1870-
async_error = -EBUSY;
1864+
WRITE_ONCE(async_error, -EBUSY);
18711865
goto Complete;
18721866
}
18731867

@@ -1951,20 +1945,18 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
19511945

19521946
Complete:
19531947
if (error) {
1954-
async_error = error;
1948+
WRITE_ONCE(async_error, error);
19551949
dpm_save_failed_dev(dev_name(dev));
19561950
pm_dev_err(dev, state, async ? " async" : "", error);
19571951
}
19581952

19591953
complete_all(&dev->power.completion);
19601954
TRACE_SUSPEND(error);
19611955

1962-
if (error || async_error)
1963-
return error;
1956+
if (error || READ_ONCE(async_error))
1957+
return;
19641958

19651959
dpm_async_suspend_superior(dev, async_suspend);
1966-
1967-
return 0;
19681960
}
19691961

19701962
static void async_suspend(void *data, async_cookie_t cookie)
@@ -1983,7 +1975,7 @@ int dpm_suspend(pm_message_t state)
19831975
{
19841976
ktime_t starttime = ktime_get();
19851977
struct device *dev;
1986-
int error = 0;
1978+
int error;
19871979

19881980
trace_suspend_resume(TPS("dpm_suspend"), state.event, true);
19891981
might_sleep();
@@ -2018,13 +2010,13 @@ int dpm_suspend(pm_message_t state)
20182010

20192011
mutex_unlock(&dpm_list_mtx);
20202012

2021-
error = device_suspend(dev, state, false);
2013+
device_suspend(dev, state, false);
20222014

20232015
put_device(dev);
20242016

20252017
mutex_lock(&dpm_list_mtx);
20262018

2027-
if (error || async_error) {
2019+
if (READ_ONCE(async_error)) {
20282020
dpm_async_suspend_complete_all(&dpm_prepared_list);
20292021
/*
20302022
* Move all devices to the target list to resume them
@@ -2038,9 +2030,8 @@ int dpm_suspend(pm_message_t state)
20382030
mutex_unlock(&dpm_list_mtx);
20392031

20402032
async_synchronize_full();
2041-
if (!error)
2042-
error = async_error;
20432033

2034+
error = READ_ONCE(async_error);
20442035
if (error)
20452036
dpm_save_failed_step(SUSPEND_SUSPEND);
20462037

0 commit comments

Comments
 (0)