|
@@ -570,7 +570,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
|
|
pm_callback_t callback = NULL;
|
|
pm_callback_t callback = NULL;
|
|
char *info = NULL;
|
|
char *info = NULL;
|
|
int error = 0;
|
|
int error = 0;
|
|
- bool put = false;
|
|
|
|
|
|
|
|
TRACE_DEVICE(dev);
|
|
TRACE_DEVICE(dev);
|
|
TRACE_RESUME(0);
|
|
TRACE_RESUME(0);
|
|
@@ -591,7 +590,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
|
|
goto Unlock;
|
|
goto Unlock;
|
|
|
|
|
|
pm_runtime_enable(dev);
|
|
pm_runtime_enable(dev);
|
|
- put = true;
|
|
|
|
|
|
|
|
if (dev->pm_domain) {
|
|
if (dev->pm_domain) {
|
|
info = "power domain ";
|
|
info = "power domain ";
|
|
@@ -646,9 +644,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
|
|
|
|
|
|
TRACE_RESUME(error);
|
|
TRACE_RESUME(error);
|
|
|
|
|
|
- if (put)
|
|
|
|
- pm_runtime_put_sync(dev);
|
|
|
|
-
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -762,6 +757,8 @@ static void device_complete(struct device *dev, pm_message_t state)
|
|
}
|
|
}
|
|
|
|
|
|
device_unlock(dev);
|
|
device_unlock(dev);
|
|
|
|
+
|
|
|
|
+ pm_runtime_put_sync(dev);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1015,7 +1012,7 @@ int dpm_suspend_end(pm_message_t state)
|
|
|
|
|
|
error = dpm_suspend_noirq(state);
|
|
error = dpm_suspend_noirq(state);
|
|
if (error) {
|
|
if (error) {
|
|
- dpm_resume_early(state);
|
|
|
|
|
|
+ dpm_resume_early(resume_event(state));
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1062,12 +1059,16 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
|
if (async_error)
|
|
if (async_error)
|
|
goto Complete;
|
|
goto Complete;
|
|
|
|
|
|
- pm_runtime_get_noresume(dev);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * 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.
|
|
|
|
+ */
|
|
if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
|
|
if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
|
|
pm_wakeup_event(dev, 0);
|
|
pm_wakeup_event(dev, 0);
|
|
|
|
|
|
if (pm_wakeup_pending()) {
|
|
if (pm_wakeup_pending()) {
|
|
- pm_runtime_put_sync(dev);
|
|
|
|
async_error = -EBUSY;
|
|
async_error = -EBUSY;
|
|
goto Complete;
|
|
goto Complete;
|
|
}
|
|
}
|
|
@@ -1133,12 +1134,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
|
Complete:
|
|
Complete:
|
|
complete_all(&dev->power.completion);
|
|
complete_all(&dev->power.completion);
|
|
|
|
|
|
- if (error) {
|
|
|
|
- pm_runtime_put_sync(dev);
|
|
|
|
|
|
+ if (error)
|
|
async_error = error;
|
|
async_error = error;
|
|
- } else if (dev->power.is_suspended) {
|
|
|
|
|
|
+ else if (dev->power.is_suspended)
|
|
__pm_runtime_disable(dev, false);
|
|
__pm_runtime_disable(dev, false);
|
|
- }
|
|
|
|
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
@@ -1234,6 +1233,14 @@ static int device_prepare(struct device *dev, pm_message_t state)
|
|
if (dev->power.syscore)
|
|
if (dev->power.syscore)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If a device's parent goes into runtime suspend at the wrong time,
|
|
|
|
+ * it won't be possible to resume the device. To prevent this we
|
|
|
|
+ * block runtime suspend here, during the prepare phase, and allow
|
|
|
|
+ * it again during the complete phase.
|
|
|
|
+ */
|
|
|
|
+ pm_runtime_get_noresume(dev);
|
|
|
|
+
|
|
device_lock(dev);
|
|
device_lock(dev);
|
|
|
|
|
|
dev->power.wakeup_path = device_may_wakeup(dev);
|
|
dev->power.wakeup_path = device_may_wakeup(dev);
|