diff options
author | Liu, Chuansheng <chuansheng.liu@intel.com> | 2014-02-17 21:28:48 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-19 19:30:09 -0500 |
commit | de377b3972729f00ee236ae4a97393e282ffe391 (patch) | |
tree | feeb6d2e86bc3d90e69d1c5f1ce924b6e72cb4de | |
parent | 28b6fd6e37792b16a56d324841bdb20ab78e4522 (diff) |
PM / sleep: Asynchronous threads for suspend_late
In analogy with commits 5af84b82701a and 97df8c12995, using
asynchronous threads can improve the overall suspend_late
time significantly.
This patch is for suspend_late 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.c | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9335b326d1f5..42355e442a5d 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -1127,16 +1127,26 @@ static int dpm_suspend_noirq(pm_message_t state) | |||
1127 | * | 1127 | * |
1128 | * Runtime PM is disabled for @dev while this function is being executed. | 1128 | * Runtime PM is disabled for @dev while this function is being executed. |
1129 | */ | 1129 | */ |
1130 | static int device_suspend_late(struct device *dev, pm_message_t state) | 1130 | static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) |
1131 | { | 1131 | { |
1132 | pm_callback_t callback = NULL; | 1132 | pm_callback_t callback = NULL; |
1133 | char *info = NULL; | 1133 | char *info = NULL; |
1134 | int error; | 1134 | int error = 0; |
1135 | 1135 | ||
1136 | __pm_runtime_disable(dev, false); | 1136 | __pm_runtime_disable(dev, false); |
1137 | 1137 | ||
1138 | if (async_error) | ||
1139 | goto Complete; | ||
1140 | |||
1141 | if (pm_wakeup_pending()) { | ||
1142 | async_error = -EBUSY; | ||
1143 | goto Complete; | ||
1144 | } | ||
1145 | |||
1138 | if (dev->power.syscore) | 1146 | if (dev->power.syscore) |
1139 | return 0; | 1147 | goto Complete; |
1148 | |||
1149 | dpm_wait_for_children(dev, async); | ||
1140 | 1150 | ||
1141 | if (dev->pm_domain) { | 1151 | if (dev->pm_domain) { |
1142 | info = "late power domain "; | 1152 | info = "late power domain "; |
@@ -1160,10 +1170,40 @@ static int device_suspend_late(struct device *dev, pm_message_t state) | |||
1160 | error = dpm_run_callback(callback, dev, state, info); | 1170 | error = dpm_run_callback(callback, dev, state, info); |
1161 | if (!error) | 1171 | if (!error) |
1162 | dev->power.is_late_suspended = true; | 1172 | dev->power.is_late_suspended = true; |
1173 | else | ||
1174 | async_error = error; | ||
1163 | 1175 | ||
1176 | Complete: | ||
1177 | complete_all(&dev->power.completion); | ||
1164 | return error; | 1178 | return error; |
1165 | } | 1179 | } |
1166 | 1180 | ||
1181 | static void async_suspend_late(void *data, async_cookie_t cookie) | ||
1182 | { | ||
1183 | struct device *dev = (struct device *)data; | ||
1184 | int error; | ||
1185 | |||
1186 | error = __device_suspend_late(dev, pm_transition, true); | ||
1187 | if (error) { | ||
1188 | dpm_save_failed_dev(dev_name(dev)); | ||
1189 | pm_dev_err(dev, pm_transition, " async", error); | ||
1190 | } | ||
1191 | put_device(dev); | ||
1192 | } | ||
1193 | |||
1194 | static int device_suspend_late(struct device *dev) | ||
1195 | { | ||
1196 | reinit_completion(&dev->power.completion); | ||
1197 | |||
1198 | if (pm_async_enabled && dev->power.async_suspend) { | ||
1199 | get_device(dev); | ||
1200 | async_schedule(async_suspend_late, dev); | ||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | return __device_suspend_late(dev, pm_transition, false); | ||
1205 | } | ||
1206 | |||
1167 | /** | 1207 | /** |
1168 | * dpm_suspend_late - Execute "late suspend" callbacks for all devices. | 1208 | * dpm_suspend_late - Execute "late suspend" callbacks for all devices. |
1169 | * @state: PM transition of the system being carried out. | 1209 | * @state: PM transition of the system being carried out. |
@@ -1174,19 +1214,20 @@ static int dpm_suspend_late(pm_message_t state) | |||
1174 | int error = 0; | 1214 | int error = 0; |
1175 | 1215 | ||
1176 | mutex_lock(&dpm_list_mtx); | 1216 | mutex_lock(&dpm_list_mtx); |
1217 | pm_transition = state; | ||
1218 | async_error = 0; | ||
1219 | |||
1177 | while (!list_empty(&dpm_suspended_list)) { | 1220 | while (!list_empty(&dpm_suspended_list)) { |
1178 | struct device *dev = to_device(dpm_suspended_list.prev); | 1221 | struct device *dev = to_device(dpm_suspended_list.prev); |
1179 | 1222 | ||
1180 | get_device(dev); | 1223 | get_device(dev); |
1181 | mutex_unlock(&dpm_list_mtx); | 1224 | mutex_unlock(&dpm_list_mtx); |
1182 | 1225 | ||
1183 | error = device_suspend_late(dev, state); | 1226 | error = device_suspend_late(dev); |
1184 | 1227 | ||
1185 | mutex_lock(&dpm_list_mtx); | 1228 | mutex_lock(&dpm_list_mtx); |
1186 | if (error) { | 1229 | if (error) { |
1187 | pm_dev_err(dev, state, " late", error); | 1230 | pm_dev_err(dev, state, " late", error); |
1188 | suspend_stats.failed_suspend_late++; | ||
1189 | dpm_save_failed_step(SUSPEND_SUSPEND_LATE); | ||
1190 | dpm_save_failed_dev(dev_name(dev)); | 1231 | dpm_save_failed_dev(dev_name(dev)); |
1191 | put_device(dev); | 1232 | put_device(dev); |
1192 | break; | 1233 | break; |
@@ -1195,17 +1236,18 @@ static int dpm_suspend_late(pm_message_t state) | |||
1195 | list_move(&dev->power.entry, &dpm_late_early_list); | 1236 | list_move(&dev->power.entry, &dpm_late_early_list); |
1196 | put_device(dev); | 1237 | put_device(dev); |
1197 | 1238 | ||
1198 | if (pm_wakeup_pending()) { | 1239 | if (async_error) |
1199 | error = -EBUSY; | ||
1200 | break; | 1240 | break; |
1201 | } | ||
1202 | } | 1241 | } |
1203 | mutex_unlock(&dpm_list_mtx); | 1242 | mutex_unlock(&dpm_list_mtx); |
1204 | if (error) | 1243 | async_synchronize_full(); |
1244 | if (error) { | ||
1245 | suspend_stats.failed_suspend_late++; | ||
1246 | dpm_save_failed_step(SUSPEND_SUSPEND_LATE); | ||
1205 | dpm_resume_early(resume_event(state)); | 1247 | dpm_resume_early(resume_event(state)); |
1206 | else | 1248 | } else { |
1207 | dpm_show_time(starttime, state, "late"); | 1249 | dpm_show_time(starttime, state, "late"); |
1208 | 1250 | } | |
1209 | return error; | 1251 | return error; |
1210 | } | 1252 | } |
1211 | 1253 | ||