aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu, Chuansheng <chuansheng.liu@intel.com>2014-02-17 21:28:47 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-19 19:30:09 -0500
commit28b6fd6e37792b16a56d324841bdb20ab78e4522 (patch)
tree7672d173bf71b4907ea882f9842496ccd6531ff3
parent9e5e7910df824ba02aedd2b5d2ca556426ea6d0b (diff)
PM / sleep: Asynchronous threads for suspend_noirq
In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_noirq time significantly. This patch is for suspend_noirq phase. Signed-off-by: Chuansheng Liu <chuansheng.liu@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/power/main.c68
1 files changed, 57 insertions, 11 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 6d41165701c4..9335b326d1f5 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -990,14 +990,24 @@ static pm_message_t resume_event(pm_message_t sleep_state)
990 * The driver of @dev will not receive interrupts while this function is being 990 * The driver of @dev will not receive interrupts while this function is being
991 * executed. 991 * executed.
992 */ 992 */
993static int device_suspend_noirq(struct device *dev, pm_message_t state) 993static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
994{ 994{
995 pm_callback_t callback = NULL; 995 pm_callback_t callback = NULL;
996 char *info = NULL; 996 char *info = NULL;
997 int error; 997 int error = 0;
998
999 if (async_error)
1000 goto Complete;
1001
1002 if (pm_wakeup_pending()) {
1003 async_error = -EBUSY;
1004 goto Complete;
1005 }
998 1006
999 if (dev->power.syscore) 1007 if (dev->power.syscore)
1000 return 0; 1008 goto Complete;
1009
1010 dpm_wait_for_children(dev, async);
1001 1011
1002 if (dev->pm_domain) { 1012 if (dev->pm_domain) {
1003 info = "noirq power domain "; 1013 info = "noirq power domain ";
@@ -1021,10 +1031,40 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
1021 error = dpm_run_callback(callback, dev, state, info); 1031 error = dpm_run_callback(callback, dev, state, info);
1022 if (!error) 1032 if (!error)
1023 dev->power.is_noirq_suspended = true; 1033 dev->power.is_noirq_suspended = true;
1034 else
1035 async_error = error;
1024 1036
1037Complete:
1038 complete_all(&dev->power.completion);
1025 return error; 1039 return error;
1026} 1040}
1027 1041
1042static void async_suspend_noirq(void *data, async_cookie_t cookie)
1043{
1044 struct device *dev = (struct device *)data;
1045 int error;
1046
1047 error = __device_suspend_noirq(dev, pm_transition, true);
1048 if (error) {
1049 dpm_save_failed_dev(dev_name(dev));
1050 pm_dev_err(dev, pm_transition, " async", error);
1051 }
1052
1053 put_device(dev);
1054}
1055
1056static int device_suspend_noirq(struct device *dev)
1057{
1058 reinit_completion(&dev->power.completion);
1059
1060 if (pm_async_enabled && dev->power.async_suspend) {
1061 get_device(dev);
1062 async_schedule(async_suspend_noirq, dev);
1063 return 0;
1064 }
1065 return __device_suspend_noirq(dev, pm_transition, false);
1066}
1067
1028/** 1068/**
1029 * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. 1069 * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices.
1030 * @state: PM transition of the system being carried out. 1070 * @state: PM transition of the system being carried out.
@@ -1040,19 +1080,20 @@ static int dpm_suspend_noirq(pm_message_t state)
1040 cpuidle_pause(); 1080 cpuidle_pause();
1041 suspend_device_irqs(); 1081 suspend_device_irqs();
1042 mutex_lock(&dpm_list_mtx); 1082 mutex_lock(&dpm_list_mtx);
1083 pm_transition = state;
1084 async_error = 0;
1085
1043 while (!list_empty(&dpm_late_early_list)) { 1086 while (!list_empty(&dpm_late_early_list)) {
1044 struct device *dev = to_device(dpm_late_early_list.prev); 1087 struct device *dev = to_device(dpm_late_early_list.prev);
1045 1088
1046 get_device(dev); 1089 get_device(dev);
1047 mutex_unlock(&dpm_list_mtx); 1090 mutex_unlock(&dpm_list_mtx);
1048 1091
1049 error = device_suspend_noirq(dev, state); 1092 error = device_suspend_noirq(dev);
1050 1093
1051 mutex_lock(&dpm_list_mtx); 1094 mutex_lock(&dpm_list_mtx);
1052 if (error) { 1095 if (error) {
1053 pm_dev_err(dev, state, " noirq", error); 1096 pm_dev_err(dev, state, " noirq", error);
1054 suspend_stats.failed_suspend_noirq++;
1055 dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
1056 dpm_save_failed_dev(dev_name(dev)); 1097 dpm_save_failed_dev(dev_name(dev));
1057 put_device(dev); 1098 put_device(dev);
1058 break; 1099 break;
@@ -1061,16 +1102,21 @@ static int dpm_suspend_noirq(pm_message_t state)
1061 list_move(&dev->power.entry, &dpm_noirq_list); 1102 list_move(&dev->power.entry, &dpm_noirq_list);
1062 put_device(dev); 1103 put_device(dev);
1063 1104
1064 if (pm_wakeup_pending()) { 1105 if (async_error)
1065 error = -EBUSY;
1066 break; 1106 break;
1067 }
1068 } 1107 }
1069 mutex_unlock(&dpm_list_mtx); 1108 mutex_unlock(&dpm_list_mtx);
1070 if (error) 1109 async_synchronize_full();
1110 if (!error)
1111 error = async_error;
1112
1113 if (error) {
1114 suspend_stats.failed_suspend_noirq++;
1115 dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
1071 dpm_resume_noirq(resume_event(state)); 1116 dpm_resume_noirq(resume_event(state));
1072 else 1117 } else {
1073 dpm_show_time(starttime, state, "noirq"); 1118 dpm_show_time(starttime, state, "noirq");
1119 }
1074 return error; 1120 return error;
1075} 1121}
1076 1122