diff options
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r-- | drivers/base/power/main.c | 103 |
1 files changed, 64 insertions, 39 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index c99f8730de82..ea1732ed7a9d 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -418,8 +418,7 @@ static void pm_dev_err(struct device *dev, pm_message_t state, const char *info, | |||
418 | dev_name(dev), pm_verb(state.event), info, error); | 418 | dev_name(dev), pm_verb(state.event), info, error); |
419 | } | 419 | } |
420 | 420 | ||
421 | #ifdef CONFIG_PM_DEBUG | 421 | static void dpm_show_time(ktime_t starttime, pm_message_t state, int error, |
422 | static void dpm_show_time(ktime_t starttime, pm_message_t state, | ||
423 | const char *info) | 422 | const char *info) |
424 | { | 423 | { |
425 | ktime_t calltime; | 424 | ktime_t calltime; |
@@ -432,14 +431,12 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, | |||
432 | usecs = usecs64; | 431 | usecs = usecs64; |
433 | if (usecs == 0) | 432 | if (usecs == 0) |
434 | usecs = 1; | 433 | usecs = 1; |
435 | pr_info("PM: %s%s%s of devices complete after %ld.%03ld msecs\n", | 434 | |
436 | info ?: "", info ? " " : "", pm_verb(state.event), | 435 | pm_pr_dbg("%s%s%s of devices %s after %ld.%03ld msecs\n", |
437 | usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); | 436 | info ?: "", info ? " " : "", pm_verb(state.event), |
437 | error ? "aborted" : "complete", | ||
438 | usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); | ||
438 | } | 439 | } |
439 | #else | ||
440 | static inline void dpm_show_time(ktime_t starttime, pm_message_t state, | ||
441 | const char *info) {} | ||
442 | #endif /* CONFIG_PM_DEBUG */ | ||
443 | 440 | ||
444 | static int dpm_run_callback(pm_callback_t cb, struct device *dev, | 441 | static int dpm_run_callback(pm_callback_t cb, struct device *dev, |
445 | pm_message_t state, const char *info) | 442 | pm_message_t state, const char *info) |
@@ -602,14 +599,7 @@ static void async_resume_noirq(void *data, async_cookie_t cookie) | |||
602 | put_device(dev); | 599 | put_device(dev); |
603 | } | 600 | } |
604 | 601 | ||
605 | /** | 602 | void dpm_noirq_resume_devices(pm_message_t state) |
606 | * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. | ||
607 | * @state: PM transition of the system being carried out. | ||
608 | * | ||
609 | * Call the "noirq" resume handlers for all devices in dpm_noirq_list and | ||
610 | * enable device drivers to receive interrupts. | ||
611 | */ | ||
612 | void dpm_resume_noirq(pm_message_t state) | ||
613 | { | 603 | { |
614 | struct device *dev; | 604 | struct device *dev; |
615 | ktime_t starttime = ktime_get(); | 605 | ktime_t starttime = ktime_get(); |
@@ -654,11 +644,28 @@ void dpm_resume_noirq(pm_message_t state) | |||
654 | } | 644 | } |
655 | mutex_unlock(&dpm_list_mtx); | 645 | mutex_unlock(&dpm_list_mtx); |
656 | async_synchronize_full(); | 646 | async_synchronize_full(); |
657 | dpm_show_time(starttime, state, "noirq"); | 647 | dpm_show_time(starttime, state, 0, "noirq"); |
648 | trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); | ||
649 | } | ||
650 | |||
651 | void dpm_noirq_end(void) | ||
652 | { | ||
658 | resume_device_irqs(); | 653 | resume_device_irqs(); |
659 | device_wakeup_disarm_wake_irqs(); | 654 | device_wakeup_disarm_wake_irqs(); |
660 | cpuidle_resume(); | 655 | cpuidle_resume(); |
661 | trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); | 656 | } |
657 | |||
658 | /** | ||
659 | * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. | ||
660 | * @state: PM transition of the system being carried out. | ||
661 | * | ||
662 | * Invoke the "noirq" resume callbacks for all devices in dpm_noirq_list and | ||
663 | * allow device drivers' interrupt handlers to be called. | ||
664 | */ | ||
665 | void dpm_resume_noirq(pm_message_t state) | ||
666 | { | ||
667 | dpm_noirq_resume_devices(state); | ||
668 | dpm_noirq_end(); | ||
662 | } | 669 | } |
663 | 670 | ||
664 | /** | 671 | /** |
@@ -776,7 +783,7 @@ void dpm_resume_early(pm_message_t state) | |||
776 | } | 783 | } |
777 | mutex_unlock(&dpm_list_mtx); | 784 | mutex_unlock(&dpm_list_mtx); |
778 | async_synchronize_full(); | 785 | async_synchronize_full(); |
779 | dpm_show_time(starttime, state, "early"); | 786 | dpm_show_time(starttime, state, 0, "early"); |
780 | trace_suspend_resume(TPS("dpm_resume_early"), state.event, false); | 787 | trace_suspend_resume(TPS("dpm_resume_early"), state.event, false); |
781 | } | 788 | } |
782 | 789 | ||
@@ -948,7 +955,7 @@ void dpm_resume(pm_message_t state) | |||
948 | } | 955 | } |
949 | mutex_unlock(&dpm_list_mtx); | 956 | mutex_unlock(&dpm_list_mtx); |
950 | async_synchronize_full(); | 957 | async_synchronize_full(); |
951 | dpm_show_time(starttime, state, NULL); | 958 | dpm_show_time(starttime, state, 0, NULL); |
952 | 959 | ||
953 | cpufreq_resume(); | 960 | cpufreq_resume(); |
954 | trace_suspend_resume(TPS("dpm_resume"), state.event, false); | 961 | trace_suspend_resume(TPS("dpm_resume"), state.event, false); |
@@ -1098,6 +1105,11 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a | |||
1098 | if (async_error) | 1105 | if (async_error) |
1099 | goto Complete; | 1106 | goto Complete; |
1100 | 1107 | ||
1108 | if (pm_wakeup_pending()) { | ||
1109 | async_error = -EBUSY; | ||
1110 | goto Complete; | ||
1111 | } | ||
1112 | |||
1101 | if (dev->power.syscore || dev->power.direct_complete) | 1113 | if (dev->power.syscore || dev->power.direct_complete) |
1102 | goto Complete; | 1114 | goto Complete; |
1103 | 1115 | ||
@@ -1158,22 +1170,19 @@ static int device_suspend_noirq(struct device *dev) | |||
1158 | return __device_suspend_noirq(dev, pm_transition, false); | 1170 | return __device_suspend_noirq(dev, pm_transition, false); |
1159 | } | 1171 | } |
1160 | 1172 | ||
1161 | /** | 1173 | void dpm_noirq_begin(void) |
1162 | * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. | 1174 | { |
1163 | * @state: PM transition of the system being carried out. | 1175 | cpuidle_pause(); |
1164 | * | 1176 | device_wakeup_arm_wake_irqs(); |
1165 | * Prevent device drivers from receiving interrupts and call the "noirq" suspend | 1177 | suspend_device_irqs(); |
1166 | * handlers for all non-sysdev devices. | 1178 | } |
1167 | */ | 1179 | |
1168 | int dpm_suspend_noirq(pm_message_t state) | 1180 | int dpm_noirq_suspend_devices(pm_message_t state) |
1169 | { | 1181 | { |
1170 | ktime_t starttime = ktime_get(); | 1182 | ktime_t starttime = ktime_get(); |
1171 | int error = 0; | 1183 | int error = 0; |
1172 | 1184 | ||
1173 | trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true); | 1185 | trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true); |
1174 | cpuidle_pause(); | ||
1175 | device_wakeup_arm_wake_irqs(); | ||
1176 | suspend_device_irqs(); | ||
1177 | mutex_lock(&dpm_list_mtx); | 1186 | mutex_lock(&dpm_list_mtx); |
1178 | pm_transition = state; | 1187 | pm_transition = state; |
1179 | async_error = 0; | 1188 | async_error = 0; |
@@ -1208,15 +1217,32 @@ int dpm_suspend_noirq(pm_message_t state) | |||
1208 | if (error) { | 1217 | if (error) { |
1209 | suspend_stats.failed_suspend_noirq++; | 1218 | suspend_stats.failed_suspend_noirq++; |
1210 | dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); | 1219 | dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); |
1211 | dpm_resume_noirq(resume_event(state)); | ||
1212 | } else { | ||
1213 | dpm_show_time(starttime, state, "noirq"); | ||
1214 | } | 1220 | } |
1221 | dpm_show_time(starttime, state, error, "noirq"); | ||
1215 | trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, false); | 1222 | trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, false); |
1216 | return error; | 1223 | return error; |
1217 | } | 1224 | } |
1218 | 1225 | ||
1219 | /** | 1226 | /** |
1227 | * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. | ||
1228 | * @state: PM transition of the system being carried out. | ||
1229 | * | ||
1230 | * Prevent device drivers' interrupt handlers from being called and invoke | ||
1231 | * "noirq" suspend callbacks for all non-sysdev devices. | ||
1232 | */ | ||
1233 | int dpm_suspend_noirq(pm_message_t state) | ||
1234 | { | ||
1235 | int ret; | ||
1236 | |||
1237 | dpm_noirq_begin(); | ||
1238 | ret = dpm_noirq_suspend_devices(state); | ||
1239 | if (ret) | ||
1240 | dpm_resume_noirq(resume_event(state)); | ||
1241 | |||
1242 | return ret; | ||
1243 | } | ||
1244 | |||
1245 | /** | ||
1220 | * device_suspend_late - Execute a "late suspend" callback for given device. | 1246 | * device_suspend_late - Execute a "late suspend" callback for given device. |
1221 | * @dev: Device to handle. | 1247 | * @dev: Device to handle. |
1222 | * @state: PM transition of the system being carried out. | 1248 | * @state: PM transition of the system being carried out. |
@@ -1350,9 +1376,8 @@ int dpm_suspend_late(pm_message_t state) | |||
1350 | suspend_stats.failed_suspend_late++; | 1376 | suspend_stats.failed_suspend_late++; |
1351 | dpm_save_failed_step(SUSPEND_SUSPEND_LATE); | 1377 | dpm_save_failed_step(SUSPEND_SUSPEND_LATE); |
1352 | dpm_resume_early(resume_event(state)); | 1378 | dpm_resume_early(resume_event(state)); |
1353 | } else { | ||
1354 | dpm_show_time(starttime, state, "late"); | ||
1355 | } | 1379 | } |
1380 | dpm_show_time(starttime, state, error, "late"); | ||
1356 | trace_suspend_resume(TPS("dpm_suspend_late"), state.event, false); | 1381 | trace_suspend_resume(TPS("dpm_suspend_late"), state.event, false); |
1357 | return error; | 1382 | return error; |
1358 | } | 1383 | } |
@@ -1618,8 +1643,8 @@ int dpm_suspend(pm_message_t state) | |||
1618 | if (error) { | 1643 | if (error) { |
1619 | suspend_stats.failed_suspend++; | 1644 | suspend_stats.failed_suspend++; |
1620 | dpm_save_failed_step(SUSPEND_SUSPEND); | 1645 | dpm_save_failed_step(SUSPEND_SUSPEND); |
1621 | } else | 1646 | } |
1622 | dpm_show_time(starttime, state, NULL); | 1647 | dpm_show_time(starttime, state, error, NULL); |
1623 | trace_suspend_resume(TPS("dpm_suspend"), state.event, false); | 1648 | trace_suspend_resume(TPS("dpm_suspend"), state.event, false); |
1624 | return error; | 1649 | return error; |
1625 | } | 1650 | } |