Skip to content

Commit dbd4bcc

Browse files
committed
PM: sleep: Rearrange suspend/resume error handling in the core
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
1 parent 7c1f7c2 commit dbd4bcc

1 file changed

Lines changed: 35 additions & 44 deletions

File tree

drivers/base/power/main.c

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

769769
if (error) {
770-
async_error = error;
770+
WRITE_ONCE(async_error, error);
771771
dpm_save_failed_dev(dev_name(dev));
772772
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
773773
}
@@ -824,7 +824,7 @@ static void dpm_noirq_resume_devices(pm_message_t state)
824824
mutex_unlock(&dpm_list_mtx);
825825
async_synchronize_full();
826826
dpm_show_time(starttime, state, 0, "noirq");
827-
if (async_error)
827+
if (READ_ONCE(async_error))
828828
dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
829829

830830
trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false);
@@ -910,7 +910,7 @@ static void device_resume_early(struct device *dev, pm_message_t state, bool asy
910910
complete_all(&dev->power.completion);
911911

912912
if (error) {
913-
async_error = error;
913+
WRITE_ONCE(async_error, error);
914914
dpm_save_failed_dev(dev_name(dev));
915915
pm_dev_err(dev, state, async ? " async early" : " early", error);
916916
}
@@ -971,7 +971,7 @@ void dpm_resume_early(pm_message_t state)
971971
mutex_unlock(&dpm_list_mtx);
972972
async_synchronize_full();
973973
dpm_show_time(starttime, state, 0, "early");
974-
if (async_error)
974+
if (READ_ONCE(async_error))
975975
dpm_save_failed_step(SUSPEND_RESUME_EARLY);
976976

977977
trace_suspend_resume(TPS("dpm_resume_early"), state.event, false);
@@ -1086,7 +1086,7 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
10861086
TRACE_RESUME(error);
10871087

10881088
if (error) {
1089-
async_error = error;
1089+
WRITE_ONCE(async_error, error);
10901090
dpm_save_failed_dev(dev_name(dev));
10911091
pm_dev_err(dev, state, async ? " async" : "", error);
10921092
}
@@ -1150,7 +1150,7 @@ void dpm_resume(pm_message_t state)
11501150
mutex_unlock(&dpm_list_mtx);
11511151
async_synchronize_full();
11521152
dpm_show_time(starttime, state, 0, NULL);
1153-
if (async_error)
1153+
if (READ_ONCE(async_error))
11541154
dpm_save_failed_step(SUSPEND_RESUME);
11551155

11561156
cpufreq_resume();
@@ -1387,7 +1387,7 @@ static void async_suspend_noirq(void *data, async_cookie_t cookie);
13871387
* The driver of @dev will not receive interrupts while this function is being
13881388
* executed.
13891389
*/
1390-
static int device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
1390+
static void device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
13911391
{
13921392
pm_callback_t callback = NULL;
13931393
const char *info = NULL;
@@ -1398,7 +1398,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
13981398

13991399
dpm_wait_for_subordinate(dev, async);
14001400

1401-
if (async_error)
1401+
if (READ_ONCE(async_error))
14021402
goto Complete;
14031403

14041404
if (dev->power.syscore || dev->power.direct_complete)
@@ -1431,7 +1431,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
14311431
Run:
14321432
error = dpm_run_callback(callback, dev, state, info);
14331433
if (error) {
1434-
async_error = error;
1434+
WRITE_ONCE(async_error, error);
14351435
dpm_save_failed_dev(dev_name(dev));
14361436
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
14371437
goto Complete;
@@ -1457,12 +1457,10 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
14571457
complete_all(&dev->power.completion);
14581458
TRACE_SUSPEND(error);
14591459

1460-
if (error || async_error)
1461-
return error;
1460+
if (error || READ_ONCE(async_error))
1461+
return;
14621462

14631463
dpm_async_suspend_superior(dev, async_suspend_noirq);
1464-
1465-
return 0;
14661464
}
14671465

14681466
static void async_suspend_noirq(void *data, async_cookie_t cookie)
@@ -1477,7 +1475,7 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
14771475
{
14781476
ktime_t starttime = ktime_get();
14791477
struct device *dev;
1480-
int error = 0;
1478+
int error;
14811479

14821480
trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);
14831481

@@ -1508,13 +1506,13 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
15081506

15091507
mutex_unlock(&dpm_list_mtx);
15101508

1511-
error = device_suspend_noirq(dev, state, false);
1509+
device_suspend_noirq(dev, state, false);
15121510

15131511
put_device(dev);
15141512

15151513
mutex_lock(&dpm_list_mtx);
15161514

1517-
if (error || async_error) {
1515+
if (READ_ONCE(async_error)) {
15181516
dpm_async_suspend_complete_all(&dpm_late_early_list);
15191517
/*
15201518
* Move all devices to the target list to resume them
@@ -1528,9 +1526,8 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
15281526
mutex_unlock(&dpm_list_mtx);
15291527

15301528
async_synchronize_full();
1531-
if (!error)
1532-
error = async_error;
15331529

1530+
error = READ_ONCE(async_error);
15341531
if (error)
15351532
dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
15361533

@@ -1585,7 +1582,7 @@ static void async_suspend_late(void *data, async_cookie_t cookie);
15851582
*
15861583
* Runtime PM is disabled for @dev while this function is being executed.
15871584
*/
1588-
static int device_suspend_late(struct device *dev, pm_message_t state, bool async)
1585+
static void device_suspend_late(struct device *dev, pm_message_t state, bool async)
15891586
{
15901587
pm_callback_t callback = NULL;
15911588
const char *info = NULL;
@@ -1602,11 +1599,11 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16021599

16031600
dpm_wait_for_subordinate(dev, async);
16041601

1605-
if (async_error)
1602+
if (READ_ONCE(async_error))
16061603
goto Complete;
16071604

16081605
if (pm_wakeup_pending()) {
1609-
async_error = -EBUSY;
1606+
WRITE_ONCE(async_error, -EBUSY);
16101607
goto Complete;
16111608
}
16121609

@@ -1640,7 +1637,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16401637
Run:
16411638
error = dpm_run_callback(callback, dev, state, info);
16421639
if (error) {
1643-
async_error = error;
1640+
WRITE_ONCE(async_error, error);
16441641
dpm_save_failed_dev(dev_name(dev));
16451642
pm_dev_err(dev, state, async ? " async late" : " late", error);
16461643
goto Complete;
@@ -1654,12 +1651,10 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16541651
TRACE_SUSPEND(error);
16551652
complete_all(&dev->power.completion);
16561653

1657-
if (error || async_error)
1658-
return error;
1654+
if (error || READ_ONCE(async_error))
1655+
return;
16591656

16601657
dpm_async_suspend_superior(dev, async_suspend_late);
1661-
1662-
return 0;
16631658
}
16641659

16651660
static void async_suspend_late(void *data, async_cookie_t cookie)
@@ -1678,7 +1673,7 @@ int dpm_suspend_late(pm_message_t state)
16781673
{
16791674
ktime_t starttime = ktime_get();
16801675
struct device *dev;
1681-
int error = 0;
1676+
int error;
16821677

16831678
trace_suspend_resume(TPS("dpm_suspend_late"), state.event, true);
16841679

@@ -1711,13 +1706,13 @@ int dpm_suspend_late(pm_message_t state)
17111706

17121707
mutex_unlock(&dpm_list_mtx);
17131708

1714-
error = device_suspend_late(dev, state, false);
1709+
device_suspend_late(dev, state, false);
17151710

17161711
put_device(dev);
17171712

17181713
mutex_lock(&dpm_list_mtx);
17191714

1720-
if (error || async_error) {
1715+
if (READ_ONCE(async_error)) {
17211716
dpm_async_suspend_complete_all(&dpm_suspended_list);
17221717
/*
17231718
* Move all devices to the target list to resume them
@@ -1731,9 +1726,8 @@ int dpm_suspend_late(pm_message_t state)
17311726
mutex_unlock(&dpm_list_mtx);
17321727

17331728
async_synchronize_full();
1734-
if (!error)
1735-
error = async_error;
17361729

1730+
error = READ_ONCE(async_error);
17371731
if (error) {
17381732
dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
17391733
dpm_resume_early(resume_event(state));
@@ -1822,7 +1816,7 @@ static void async_suspend(void *data, async_cookie_t cookie);
18221816
* @state: PM transition of the system being carried out.
18231817
* @async: If true, the device is being suspended asynchronously.
18241818
*/
1825-
static int device_suspend(struct device *dev, pm_message_t state, bool async)
1819+
static void device_suspend(struct device *dev, pm_message_t state, bool async)
18261820
{
18271821
pm_callback_t callback = NULL;
18281822
const char *info = NULL;
@@ -1834,7 +1828,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
18341828

18351829
dpm_wait_for_subordinate(dev, async);
18361830

1837-
if (async_error) {
1831+
if (READ_ONCE(async_error)) {
18381832
dev->power.direct_complete = false;
18391833
goto Complete;
18401834
}
@@ -1854,7 +1848,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
18541848

18551849
if (pm_wakeup_pending()) {
18561850
dev->power.direct_complete = false;
1857-
async_error = -EBUSY;
1851+
WRITE_ONCE(async_error, -EBUSY);
18581852
goto Complete;
18591853
}
18601854

@@ -1938,20 +1932,18 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
19381932

19391933
Complete:
19401934
if (error) {
1941-
async_error = error;
1935+
WRITE_ONCE(async_error, error);
19421936
dpm_save_failed_dev(dev_name(dev));
19431937
pm_dev_err(dev, state, async ? " async" : "", error);
19441938
}
19451939

19461940
complete_all(&dev->power.completion);
19471941
TRACE_SUSPEND(error);
19481942

1949-
if (error || async_error)
1950-
return error;
1943+
if (error || READ_ONCE(async_error))
1944+
return;
19511945

19521946
dpm_async_suspend_superior(dev, async_suspend);
1953-
1954-
return 0;
19551947
}
19561948

19571949
static void async_suspend(void *data, async_cookie_t cookie)
@@ -1970,7 +1962,7 @@ int dpm_suspend(pm_message_t state)
19701962
{
19711963
ktime_t starttime = ktime_get();
19721964
struct device *dev;
1973-
int error = 0;
1965+
int error;
19741966

19751967
trace_suspend_resume(TPS("dpm_suspend"), state.event, true);
19761968
might_sleep();
@@ -2005,13 +1997,13 @@ int dpm_suspend(pm_message_t state)
20051997

20061998
mutex_unlock(&dpm_list_mtx);
20071999

2008-
error = device_suspend(dev, state, false);
2000+
device_suspend(dev, state, false);
20092001

20102002
put_device(dev);
20112003

20122004
mutex_lock(&dpm_list_mtx);
20132005

2014-
if (error || async_error) {
2006+
if (READ_ONCE(async_error)) {
20152007
dpm_async_suspend_complete_all(&dpm_prepared_list);
20162008
/*
20172009
* Move all devices to the target list to resume them
@@ -2025,9 +2017,8 @@ int dpm_suspend(pm_message_t state)
20252017
mutex_unlock(&dpm_list_mtx);
20262018

20272019
async_synchronize_full();
2028-
if (!error)
2029-
error = async_error;
20302020

2021+
error = READ_ONCE(async_error);
20312022
if (error)
20322023
dpm_save_failed_step(SUSPEND_SUSPEND);
20332024

0 commit comments

Comments
 (0)