aboutsummaryrefslogtreecommitdiffstats
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.c103
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 421static void dpm_show_time(ktime_t starttime, pm_message_t state, int error,
422static 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
440static inline void dpm_show_time(ktime_t starttime, pm_message_t state,
441 const char *info) {}
442#endif /* CONFIG_PM_DEBUG */
443 440
444static int dpm_run_callback(pm_callback_t cb, struct device *dev, 441static 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/** 602void 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 */
612void 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
651void 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 */
665void 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/** 1173void 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
1168int dpm_suspend_noirq(pm_message_t state) 1180int 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 */
1233int 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}