Skip to content

Commit 74c0b3b

Browse files
committed
PM: sleep: Rearrange suspend/resume error handling in the core
JIRA: https://issues.redhat.com/browse/RHEL-109250 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 ddc6a6e commit 74c0b3b

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();
@@ -1401,7 +1401,7 @@ static void async_suspend_noirq(void *data, async_cookie_t cookie);
14011401
* The driver of @dev will not receive interrupts while this function is being
14021402
* executed.
14031403
*/
1404-
static int device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
1404+
static void device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
14051405
{
14061406
pm_callback_t callback = NULL;
14071407
const char *info = NULL;
@@ -1412,7 +1412,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
14121412

14131413
dpm_wait_for_subordinate(dev, async);
14141414

1415-
if (async_error)
1415+
if (READ_ONCE(async_error))
14161416
goto Complete;
14171417

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

1474-
if (error || async_error)
1475-
return error;
1474+
if (error || READ_ONCE(async_error))
1475+
return;
14761476

14771477
dpm_async_suspend_superior(dev, async_suspend_noirq);
1478-
1479-
return 0;
14801478
}
14811479

14821480
static void async_suspend_noirq(void *data, async_cookie_t cookie)
@@ -1491,7 +1489,7 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
14911489
{
14921490
ktime_t starttime = ktime_get();
14931491
struct device *dev;
1494-
int error = 0;
1492+
int error;
14951493

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

@@ -1522,13 +1520,13 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
15221520

15231521
mutex_unlock(&dpm_list_mtx);
15241522

1525-
error = device_suspend_noirq(dev, state, false);
1523+
device_suspend_noirq(dev, state, false);
15261524

15271525
put_device(dev);
15281526

15291527
mutex_lock(&dpm_list_mtx);
15301528

1531-
if (error || async_error) {
1529+
if (READ_ONCE(async_error)) {
15321530
dpm_async_suspend_complete_all(&dpm_late_early_list);
15331531
/*
15341532
* Move all devices to the target list to resume them
@@ -1542,9 +1540,8 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
15421540
mutex_unlock(&dpm_list_mtx);
15431541

15441542
async_synchronize_full();
1545-
if (!error)
1546-
error = async_error;
15471543

1544+
error = READ_ONCE(async_error);
15481545
if (error)
15491546
dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
15501547

@@ -1599,7 +1596,7 @@ static void async_suspend_late(void *data, async_cookie_t cookie);
15991596
*
16001597
* Runtime PM is disabled for @dev while this function is being executed.
16011598
*/
1602-
static int device_suspend_late(struct device *dev, pm_message_t state, bool async)
1599+
static void device_suspend_late(struct device *dev, pm_message_t state, bool async)
16031600
{
16041601
pm_callback_t callback = NULL;
16051602
const char *info = NULL;
@@ -1616,11 +1613,11 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16161613

16171614
dpm_wait_for_subordinate(dev, async);
16181615

1619-
if (async_error)
1616+
if (READ_ONCE(async_error))
16201617
goto Complete;
16211618

16221619
if (pm_wakeup_pending()) {
1623-
async_error = -EBUSY;
1620+
WRITE_ONCE(async_error, -EBUSY);
16241621
goto Complete;
16251622
}
16261623

@@ -1654,7 +1651,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16541651
Run:
16551652
error = dpm_run_callback(callback, dev, state, info);
16561653
if (error) {
1657-
async_error = error;
1654+
WRITE_ONCE(async_error, error);
16581655
dpm_save_failed_dev(dev_name(dev));
16591656
pm_dev_err(dev, state, async ? " async late" : " late", error);
16601657
goto Complete;
@@ -1668,12 +1665,10 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16681665
TRACE_SUSPEND(error);
16691666
complete_all(&dev->power.completion);
16701667

1671-
if (error || async_error)
1672-
return error;
1668+
if (error || READ_ONCE(async_error))
1669+
return;
16731670

16741671
dpm_async_suspend_superior(dev, async_suspend_late);
1675-
1676-
return 0;
16771672
}
16781673

16791674
static void async_suspend_late(void *data, async_cookie_t cookie)
@@ -1692,7 +1687,7 @@ int dpm_suspend_late(pm_message_t state)
16921687
{
16931688
ktime_t starttime = ktime_get();
16941689
struct device *dev;
1695-
int error = 0;
1690+
int error;
16961691

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

@@ -1725,13 +1720,13 @@ int dpm_suspend_late(pm_message_t state)
17251720

17261721
mutex_unlock(&dpm_list_mtx);
17271722

1728-
error = device_suspend_late(dev, state, false);
1723+
device_suspend_late(dev, state, false);
17291724

17301725
put_device(dev);
17311726

17321727
mutex_lock(&dpm_list_mtx);
17331728

1734-
if (error || async_error) {
1729+
if (READ_ONCE(async_error)) {
17351730
dpm_async_suspend_complete_all(&dpm_suspended_list);
17361731
/*
17371732
* Move all devices to the target list to resume them
@@ -1745,9 +1740,8 @@ int dpm_suspend_late(pm_message_t state)
17451740
mutex_unlock(&dpm_list_mtx);
17461741

17471742
async_synchronize_full();
1748-
if (!error)
1749-
error = async_error;
17501743

1744+
error = READ_ONCE(async_error);
17511745
if (error) {
17521746
dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
17531747
dpm_resume_early(resume_event(state));
@@ -1836,7 +1830,7 @@ static void async_suspend(void *data, async_cookie_t cookie);
18361830
* @state: PM transition of the system being carried out.
18371831
* @async: If true, the device is being suspended asynchronously.
18381832
*/
1839-
static int device_suspend(struct device *dev, pm_message_t state, bool async)
1833+
static void device_suspend(struct device *dev, pm_message_t state, bool async)
18401834
{
18411835
pm_callback_t callback = NULL;
18421836
const char *info = NULL;
@@ -1848,7 +1842,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
18481842

18491843
dpm_wait_for_subordinate(dev, async);
18501844

1851-
if (async_error) {
1845+
if (READ_ONCE(async_error)) {
18521846
dev->power.direct_complete = false;
18531847
goto Complete;
18541848
}
@@ -1868,7 +1862,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
18681862

18691863
if (pm_wakeup_pending()) {
18701864
dev->power.direct_complete = false;
1871-
async_error = -EBUSY;
1865+
WRITE_ONCE(async_error, -EBUSY);
18721866
goto Complete;
18731867
}
18741868

@@ -1952,20 +1946,18 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
19521946

19531947
Complete:
19541948
if (error) {
1955-
async_error = error;
1949+
WRITE_ONCE(async_error, error);
19561950
dpm_save_failed_dev(dev_name(dev));
19571951
pm_dev_err(dev, state, async ? " async" : "", error);
19581952
}
19591953

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

1963-
if (error || async_error)
1964-
return error;
1957+
if (error || READ_ONCE(async_error))
1958+
return;
19651959

19661960
dpm_async_suspend_superior(dev, async_suspend);
1967-
1968-
return 0;
19691961
}
19701962

19711963
static void async_suspend(void *data, async_cookie_t cookie)
@@ -1984,7 +1976,7 @@ int dpm_suspend(pm_message_t state)
19841976
{
19851977
ktime_t starttime = ktime_get();
19861978
struct device *dev;
1987-
int error = 0;
1979+
int error;
19881980

19891981
trace_suspend_resume(TPS("dpm_suspend"), state.event, true);
19901982
might_sleep();
@@ -2019,13 +2011,13 @@ int dpm_suspend(pm_message_t state)
20192011

20202012
mutex_unlock(&dpm_list_mtx);
20212013

2022-
error = device_suspend(dev, state, false);
2014+
device_suspend(dev, state, false);
20232015

20242016
put_device(dev);
20252017

20262018
mutex_lock(&dpm_list_mtx);
20272019

2028-
if (error || async_error) {
2020+
if (READ_ONCE(async_error)) {
20292021
dpm_async_suspend_complete_all(&dpm_prepared_list);
20302022
/*
20312023
* Move all devices to the target list to resume them
@@ -2039,9 +2031,8 @@ int dpm_suspend(pm_message_t state)
20392031
mutex_unlock(&dpm_list_mtx);
20402032

20412033
async_synchronize_full();
2042-
if (!error)
2043-
error = async_error;
20442034

2035+
error = READ_ONCE(async_error);
20452036
if (error)
20462037
dpm_save_failed_step(SUSPEND_SUSPEND);
20472038

0 commit comments

Comments
 (0)