summaryrefslogtreecommitdiff
path: root/drivers/base/power/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r--drivers/base/power/main.c41
1 files changed, 26 insertions, 15 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 4192e46eda37..63100949e50d 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1058,11 +1058,13 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
}
error = dpm_run_callback(callback, dev, state, info);
- if (!error)
+ if (!error) {
dev->power.is_noirq_suspended = true;
- else
+ } else {
+ log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+ dev_name(dev), callback, error);
async_error = error;
-
+ }
Complete:
complete_all(&dev->power.completion);
TRACE_SUSPEND(error);
@@ -1205,10 +1207,13 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
}
error = dpm_run_callback(callback, dev, state, info);
- if (!error)
+ if (!error) {
dev->power.is_late_suspended = true;
- else
+ } else {
+ log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+ dev_name(dev), callback, error);
async_error = error;
+ }
Complete:
TRACE_SUSPEND(error);
@@ -1351,7 +1356,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
pm_callback_t callback = NULL;
char *info = NULL;
int error = 0;
- char suspend_abort[MAX_SUSPEND_ABORT_LEN];
DECLARE_DPM_WATCHDOG_ON_STACK(wd);
TRACE_DEVICE(dev);
@@ -1365,18 +1369,19 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
}
/*
- * If a device configured to wake up the system from sleep states
- * has been suspended at run time and there's a resume request pending
- * for it, this is equivalent to the device signaling wakeup, so the
- * system suspend operation should be aborted.
+ * Wait for possible runtime PM transitions of the device in progress
+ * to complete and if there's a runtime resume request pending for it,
+ * resume it before proceeding with invoking the system-wide suspend
+ * callbacks for it.
+ *
+ * If the system-wide suspend callbacks below change the configuration
+ * of the device, they must disable runtime PM for it or otherwise
+ * ensure that its runtime-resume callbacks will not be confused by that
+ * change in case they are invoked going forward.
*/
- if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
- pm_wakeup_event(dev, 0);
+ pm_runtime_barrier(dev);
if (pm_wakeup_pending()) {
- pm_get_active_wakeup_sources(suspend_abort,
- MAX_SUSPEND_ABORT_LEN);
- log_suspend_abort_reason(suspend_abort);
dev->power.direct_complete = false;
async_error = -EBUSY;
goto Complete;
@@ -1463,6 +1468,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
spin_unlock_irq(&parent->power.lock);
}
+ } else {
+ log_suspend_abort_reason("Callback failed on %s in %pF returned %d",
+ dev_name(dev), callback, error);
}
device_unlock(dev);
@@ -1666,6 +1674,9 @@ int dpm_prepare(pm_message_t state)
printk(KERN_INFO "PM: Device %s not prepared "
"for power transition: code %d\n",
dev_name(dev), error);
+ log_suspend_abort_reason("Device %s not prepared "
+ "for power transition: code %d",
+ dev_name(dev), error);
put_device(dev);
break;
}