diff options
Diffstat (limited to 'kernel/power/disk.c')
-rw-r--r-- | kernel/power/disk.c | 50 |
1 files changed, 37 insertions, 13 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 14a656cdc652..f011e0870b52 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -180,6 +180,17 @@ static void platform_restore_cleanup(int platform_mode) | |||
180 | } | 180 | } |
181 | 181 | ||
182 | /** | 182 | /** |
183 | * platform_recover - recover the platform from a failure to suspend | ||
184 | * devices. | ||
185 | */ | ||
186 | |||
187 | static void platform_recover(int platform_mode) | ||
188 | { | ||
189 | if (platform_mode && hibernation_ops && hibernation_ops->recover) | ||
190 | hibernation_ops->recover(); | ||
191 | } | ||
192 | |||
193 | /** | ||
183 | * create_image - freeze devices that need to be frozen with interrupts | 194 | * create_image - freeze devices that need to be frozen with interrupts |
184 | * off, create the hibernation image and thaw those devices. Control | 195 | * off, create the hibernation image and thaw those devices. Control |
185 | * reappears in this routine after a restore. | 196 | * reappears in this routine after a restore. |
@@ -193,6 +204,7 @@ static int create_image(int platform_mode) | |||
193 | if (error) | 204 | if (error) |
194 | return error; | 205 | return error; |
195 | 206 | ||
207 | device_pm_lock(); | ||
196 | local_irq_disable(); | 208 | local_irq_disable(); |
197 | /* At this point, device_suspend() has been called, but *not* | 209 | /* At this point, device_suspend() has been called, but *not* |
198 | * device_power_down(). We *must* call device_power_down() now. | 210 | * device_power_down(). We *must* call device_power_down() now. |
@@ -224,9 +236,11 @@ static int create_image(int platform_mode) | |||
224 | /* NOTE: device_power_up() is just a resume() for devices | 236 | /* NOTE: device_power_up() is just a resume() for devices |
225 | * that suspended with irqs off ... no overall powerup. | 237 | * that suspended with irqs off ... no overall powerup. |
226 | */ | 238 | */ |
227 | device_power_up(); | 239 | device_power_up(in_suspend ? |
240 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
228 | Enable_irqs: | 241 | Enable_irqs: |
229 | local_irq_enable(); | 242 | local_irq_enable(); |
243 | device_pm_unlock(); | ||
230 | return error; | 244 | return error; |
231 | } | 245 | } |
232 | 246 | ||
@@ -255,10 +269,10 @@ int hibernation_snapshot(int platform_mode) | |||
255 | suspend_console(); | 269 | suspend_console(); |
256 | error = device_suspend(PMSG_FREEZE); | 270 | error = device_suspend(PMSG_FREEZE); |
257 | if (error) | 271 | if (error) |
258 | goto Resume_console; | 272 | goto Recover_platform; |
259 | 273 | ||
260 | if (hibernation_test(TEST_DEVICES)) | 274 | if (hibernation_test(TEST_DEVICES)) |
261 | goto Resume_devices; | 275 | goto Recover_platform; |
262 | 276 | ||
263 | error = platform_pre_snapshot(platform_mode); | 277 | error = platform_pre_snapshot(platform_mode); |
264 | if (error || hibernation_test(TEST_PLATFORM)) | 278 | if (error || hibernation_test(TEST_PLATFORM)) |
@@ -280,12 +294,16 @@ int hibernation_snapshot(int platform_mode) | |||
280 | Finish: | 294 | Finish: |
281 | platform_finish(platform_mode); | 295 | platform_finish(platform_mode); |
282 | Resume_devices: | 296 | Resume_devices: |
283 | device_resume(); | 297 | device_resume(in_suspend ? |
284 | Resume_console: | 298 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
285 | resume_console(); | 299 | resume_console(); |
286 | Close: | 300 | Close: |
287 | platform_end(platform_mode); | 301 | platform_end(platform_mode); |
288 | return error; | 302 | return error; |
303 | |||
304 | Recover_platform: | ||
305 | platform_recover(platform_mode); | ||
306 | goto Resume_devices; | ||
289 | } | 307 | } |
290 | 308 | ||
291 | /** | 309 | /** |
@@ -300,8 +318,9 @@ static int resume_target_kernel(void) | |||
300 | { | 318 | { |
301 | int error; | 319 | int error; |
302 | 320 | ||
321 | device_pm_lock(); | ||
303 | local_irq_disable(); | 322 | local_irq_disable(); |
304 | error = device_power_down(PMSG_PRETHAW); | 323 | error = device_power_down(PMSG_QUIESCE); |
305 | if (error) { | 324 | if (error) { |
306 | printk(KERN_ERR "PM: Some devices failed to power down, " | 325 | printk(KERN_ERR "PM: Some devices failed to power down, " |
307 | "aborting resume\n"); | 326 | "aborting resume\n"); |
@@ -329,9 +348,10 @@ static int resume_target_kernel(void) | |||
329 | swsusp_free(); | 348 | swsusp_free(); |
330 | restore_processor_state(); | 349 | restore_processor_state(); |
331 | touch_softlockup_watchdog(); | 350 | touch_softlockup_watchdog(); |
332 | device_power_up(); | 351 | device_power_up(PMSG_RECOVER); |
333 | Enable_irqs: | 352 | Enable_irqs: |
334 | local_irq_enable(); | 353 | local_irq_enable(); |
354 | device_pm_unlock(); | ||
335 | return error; | 355 | return error; |
336 | } | 356 | } |
337 | 357 | ||
@@ -350,7 +370,7 @@ int hibernation_restore(int platform_mode) | |||
350 | 370 | ||
351 | pm_prepare_console(); | 371 | pm_prepare_console(); |
352 | suspend_console(); | 372 | suspend_console(); |
353 | error = device_suspend(PMSG_PRETHAW); | 373 | error = device_suspend(PMSG_QUIESCE); |
354 | if (error) | 374 | if (error) |
355 | goto Finish; | 375 | goto Finish; |
356 | 376 | ||
@@ -362,7 +382,7 @@ int hibernation_restore(int platform_mode) | |||
362 | enable_nonboot_cpus(); | 382 | enable_nonboot_cpus(); |
363 | } | 383 | } |
364 | platform_restore_cleanup(platform_mode); | 384 | platform_restore_cleanup(platform_mode); |
365 | device_resume(); | 385 | device_resume(PMSG_RECOVER); |
366 | Finish: | 386 | Finish: |
367 | resume_console(); | 387 | resume_console(); |
368 | pm_restore_console(); | 388 | pm_restore_console(); |
@@ -392,8 +412,11 @@ int hibernation_platform_enter(void) | |||
392 | 412 | ||
393 | suspend_console(); | 413 | suspend_console(); |
394 | error = device_suspend(PMSG_HIBERNATE); | 414 | error = device_suspend(PMSG_HIBERNATE); |
395 | if (error) | 415 | if (error) { |
396 | goto Resume_console; | 416 | if (hibernation_ops->recover) |
417 | hibernation_ops->recover(); | ||
418 | goto Resume_devices; | ||
419 | } | ||
397 | 420 | ||
398 | error = hibernation_ops->prepare(); | 421 | error = hibernation_ops->prepare(); |
399 | if (error) | 422 | if (error) |
@@ -403,6 +426,7 @@ int hibernation_platform_enter(void) | |||
403 | if (error) | 426 | if (error) |
404 | goto Finish; | 427 | goto Finish; |
405 | 428 | ||
429 | device_pm_lock(); | ||
406 | local_irq_disable(); | 430 | local_irq_disable(); |
407 | error = device_power_down(PMSG_HIBERNATE); | 431 | error = device_power_down(PMSG_HIBERNATE); |
408 | if (!error) { | 432 | if (!error) { |
@@ -411,6 +435,7 @@ int hibernation_platform_enter(void) | |||
411 | while (1); | 435 | while (1); |
412 | } | 436 | } |
413 | local_irq_enable(); | 437 | local_irq_enable(); |
438 | device_pm_unlock(); | ||
414 | 439 | ||
415 | /* | 440 | /* |
416 | * We don't need to reenable the nonboot CPUs or resume consoles, since | 441 | * We don't need to reenable the nonboot CPUs or resume consoles, since |
@@ -419,8 +444,7 @@ int hibernation_platform_enter(void) | |||
419 | Finish: | 444 | Finish: |
420 | hibernation_ops->finish(); | 445 | hibernation_ops->finish(); |
421 | Resume_devices: | 446 | Resume_devices: |
422 | device_resume(); | 447 | device_resume(PMSG_RESTORE); |
423 | Resume_console: | ||
424 | resume_console(); | 448 | resume_console(); |
425 | Close: | 449 | Close: |
426 | hibernation_ops->end(); | 450 | hibernation_ops->end(); |