mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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
This commit is contained in:
@@ -767,7 +767,7 @@ Out:
|
||||
TRACE_RESUME(error);
|
||||
|
||||
if (error) {
|
||||
async_error = error;
|
||||
WRITE_ONCE(async_error, error);
|
||||
dpm_save_failed_dev(dev_name(dev));
|
||||
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
|
||||
}
|
||||
@@ -824,7 +824,7 @@ static void dpm_noirq_resume_devices(pm_message_t state)
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
async_synchronize_full();
|
||||
dpm_show_time(starttime, state, 0, "noirq");
|
||||
if (async_error)
|
||||
if (READ_ONCE(async_error))
|
||||
dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
|
||||
|
||||
trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false);
|
||||
@@ -910,7 +910,7 @@ Out:
|
||||
complete_all(&dev->power.completion);
|
||||
|
||||
if (error) {
|
||||
async_error = error;
|
||||
WRITE_ONCE(async_error, error);
|
||||
dpm_save_failed_dev(dev_name(dev));
|
||||
pm_dev_err(dev, state, async ? " async early" : " early", error);
|
||||
}
|
||||
@@ -971,7 +971,7 @@ void dpm_resume_early(pm_message_t state)
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
async_synchronize_full();
|
||||
dpm_show_time(starttime, state, 0, "early");
|
||||
if (async_error)
|
||||
if (READ_ONCE(async_error))
|
||||
dpm_save_failed_step(SUSPEND_RESUME_EARLY);
|
||||
|
||||
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)
|
||||
TRACE_RESUME(error);
|
||||
|
||||
if (error) {
|
||||
async_error = error;
|
||||
WRITE_ONCE(async_error, error);
|
||||
dpm_save_failed_dev(dev_name(dev));
|
||||
pm_dev_err(dev, state, async ? " async" : "", error);
|
||||
}
|
||||
@@ -1150,7 +1150,7 @@ void dpm_resume(pm_message_t state)
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
async_synchronize_full();
|
||||
dpm_show_time(starttime, state, 0, NULL);
|
||||
if (async_error)
|
||||
if (READ_ONCE(async_error))
|
||||
dpm_save_failed_step(SUSPEND_RESUME);
|
||||
|
||||
cpufreq_resume();
|
||||
@@ -1387,7 +1387,7 @@ static void async_suspend_noirq(void *data, async_cookie_t cookie);
|
||||
* The driver of @dev will not receive interrupts while this function is being
|
||||
* executed.
|
||||
*/
|
||||
static int device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
|
||||
static void device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
|
||||
{
|
||||
pm_callback_t callback = NULL;
|
||||
const char *info = NULL;
|
||||
@@ -1398,7 +1398,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
|
||||
|
||||
dpm_wait_for_subordinate(dev, async);
|
||||
|
||||
if (async_error)
|
||||
if (READ_ONCE(async_error))
|
||||
goto Complete;
|
||||
|
||||
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
|
||||
Run:
|
||||
error = dpm_run_callback(callback, dev, state, info);
|
||||
if (error) {
|
||||
async_error = error;
|
||||
WRITE_ONCE(async_error, error);
|
||||
dpm_save_failed_dev(dev_name(dev));
|
||||
pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
|
||||
goto Complete;
|
||||
@@ -1457,12 +1457,10 @@ Complete:
|
||||
complete_all(&dev->power.completion);
|
||||
TRACE_SUSPEND(error);
|
||||
|
||||
if (error || async_error)
|
||||
return error;
|
||||
if (error || READ_ONCE(async_error))
|
||||
return;
|
||||
|
||||
dpm_async_suspend_superior(dev, async_suspend_noirq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ktime_t starttime = ktime_get();
|
||||
struct device *dev;
|
||||
int error = 0;
|
||||
int error;
|
||||
|
||||
trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);
|
||||
|
||||
@@ -1508,13 +1506,13 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
|
||||
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
error = device_suspend_noirq(dev, state, false);
|
||||
device_suspend_noirq(dev, state, false);
|
||||
|
||||
put_device(dev);
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
|
||||
if (error || async_error) {
|
||||
if (READ_ONCE(async_error)) {
|
||||
dpm_async_suspend_complete_all(&dpm_late_early_list);
|
||||
/*
|
||||
* Move all devices to the target list to resume them
|
||||
@@ -1528,9 +1526,8 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
async_synchronize_full();
|
||||
if (!error)
|
||||
error = async_error;
|
||||
|
||||
error = READ_ONCE(async_error);
|
||||
if (error)
|
||||
dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
|
||||
|
||||
@@ -1585,7 +1582,7 @@ static void async_suspend_late(void *data, async_cookie_t cookie);
|
||||
*
|
||||
* Runtime PM is disabled for @dev while this function is being executed.
|
||||
*/
|
||||
static int device_suspend_late(struct device *dev, pm_message_t state, bool async)
|
||||
static void device_suspend_late(struct device *dev, pm_message_t state, bool async)
|
||||
{
|
||||
pm_callback_t callback = NULL;
|
||||
const char *info = NULL;
|
||||
@@ -1602,11 +1599,11 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
|
||||
|
||||
dpm_wait_for_subordinate(dev, async);
|
||||
|
||||
if (async_error)
|
||||
if (READ_ONCE(async_error))
|
||||
goto Complete;
|
||||
|
||||
if (pm_wakeup_pending()) {
|
||||
async_error = -EBUSY;
|
||||
WRITE_ONCE(async_error, -EBUSY);
|
||||
goto Complete;
|
||||
}
|
||||
|
||||
@@ -1640,7 +1637,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
|
||||
Run:
|
||||
error = dpm_run_callback(callback, dev, state, info);
|
||||
if (error) {
|
||||
async_error = error;
|
||||
WRITE_ONCE(async_error, error);
|
||||
dpm_save_failed_dev(dev_name(dev));
|
||||
pm_dev_err(dev, state, async ? " async late" : " late", error);
|
||||
goto Complete;
|
||||
@@ -1654,12 +1651,10 @@ Complete:
|
||||
TRACE_SUSPEND(error);
|
||||
complete_all(&dev->power.completion);
|
||||
|
||||
if (error || async_error)
|
||||
return error;
|
||||
if (error || READ_ONCE(async_error))
|
||||
return;
|
||||
|
||||
dpm_async_suspend_superior(dev, async_suspend_late);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void async_suspend_late(void *data, async_cookie_t cookie)
|
||||
@@ -1678,7 +1673,7 @@ int dpm_suspend_late(pm_message_t state)
|
||||
{
|
||||
ktime_t starttime = ktime_get();
|
||||
struct device *dev;
|
||||
int error = 0;
|
||||
int error;
|
||||
|
||||
trace_suspend_resume(TPS("dpm_suspend_late"), state.event, true);
|
||||
|
||||
@@ -1711,13 +1706,13 @@ int dpm_suspend_late(pm_message_t state)
|
||||
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
error = device_suspend_late(dev, state, false);
|
||||
device_suspend_late(dev, state, false);
|
||||
|
||||
put_device(dev);
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
|
||||
if (error || async_error) {
|
||||
if (READ_ONCE(async_error)) {
|
||||
dpm_async_suspend_complete_all(&dpm_suspended_list);
|
||||
/*
|
||||
* Move all devices to the target list to resume them
|
||||
@@ -1731,9 +1726,8 @@ int dpm_suspend_late(pm_message_t state)
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
async_synchronize_full();
|
||||
if (!error)
|
||||
error = async_error;
|
||||
|
||||
error = READ_ONCE(async_error);
|
||||
if (error) {
|
||||
dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
|
||||
dpm_resume_early(resume_event(state));
|
||||
@@ -1822,7 +1816,7 @@ static void async_suspend(void *data, async_cookie_t cookie);
|
||||
* @state: PM transition of the system being carried out.
|
||||
* @async: If true, the device is being suspended asynchronously.
|
||||
*/
|
||||
static int device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
static void device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
{
|
||||
pm_callback_t callback = NULL;
|
||||
const char *info = NULL;
|
||||
@@ -1834,7 +1828,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
|
||||
dpm_wait_for_subordinate(dev, async);
|
||||
|
||||
if (async_error) {
|
||||
if (READ_ONCE(async_error)) {
|
||||
dev->power.direct_complete = false;
|
||||
goto Complete;
|
||||
}
|
||||
@@ -1854,7 +1848,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
|
||||
if (pm_wakeup_pending()) {
|
||||
dev->power.direct_complete = false;
|
||||
async_error = -EBUSY;
|
||||
WRITE_ONCE(async_error, -EBUSY);
|
||||
goto Complete;
|
||||
}
|
||||
|
||||
@@ -1938,7 +1932,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
|
||||
Complete:
|
||||
if (error) {
|
||||
async_error = error;
|
||||
WRITE_ONCE(async_error, error);
|
||||
dpm_save_failed_dev(dev_name(dev));
|
||||
pm_dev_err(dev, state, async ? " async" : "", error);
|
||||
}
|
||||
@@ -1946,12 +1940,10 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
complete_all(&dev->power.completion);
|
||||
TRACE_SUSPEND(error);
|
||||
|
||||
if (error || async_error)
|
||||
return error;
|
||||
if (error || READ_ONCE(async_error))
|
||||
return;
|
||||
|
||||
dpm_async_suspend_superior(dev, async_suspend);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void async_suspend(void *data, async_cookie_t cookie)
|
||||
@@ -1970,7 +1962,7 @@ int dpm_suspend(pm_message_t state)
|
||||
{
|
||||
ktime_t starttime = ktime_get();
|
||||
struct device *dev;
|
||||
int error = 0;
|
||||
int error;
|
||||
|
||||
trace_suspend_resume(TPS("dpm_suspend"), state.event, true);
|
||||
might_sleep();
|
||||
@@ -2005,13 +1997,13 @@ int dpm_suspend(pm_message_t state)
|
||||
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
error = device_suspend(dev, state, false);
|
||||
device_suspend(dev, state, false);
|
||||
|
||||
put_device(dev);
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
|
||||
if (error || async_error) {
|
||||
if (READ_ONCE(async_error)) {
|
||||
dpm_async_suspend_complete_all(&dpm_prepared_list);
|
||||
/*
|
||||
* Move all devices to the target list to resume them
|
||||
@@ -2025,9 +2017,8 @@ int dpm_suspend(pm_message_t state)
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
|
||||
async_synchronize_full();
|
||||
if (!error)
|
||||
error = async_error;
|
||||
|
||||
error = READ_ONCE(async_error);
|
||||
if (error)
|
||||
dpm_save_failed_step(SUSPEND_SUSPEND);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user