diff options
-rw-r--r-- | kernel/power/disk.c | 109 |
1 files changed, 61 insertions, 48 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 320bb0949bdf..e886d1332a10 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -228,13 +228,22 @@ static int create_image(int platform_mode) | |||
228 | goto Unlock; | 228 | goto Unlock; |
229 | } | 229 | } |
230 | 230 | ||
231 | error = platform_pre_snapshot(platform_mode); | ||
232 | if (error || hibernation_test(TEST_PLATFORM)) | ||
233 | goto Platform_finish; | ||
234 | |||
235 | error = disable_nonboot_cpus(); | ||
236 | if (error || hibernation_test(TEST_CPUS) | ||
237 | || hibernation_testmode(HIBERNATION_TEST)) | ||
238 | goto Enable_cpus; | ||
239 | |||
231 | local_irq_disable(); | 240 | local_irq_disable(); |
232 | 241 | ||
233 | sysdev_suspend(PMSG_FREEZE); | 242 | sysdev_suspend(PMSG_FREEZE); |
234 | if (error) { | 243 | if (error) { |
235 | printk(KERN_ERR "PM: Some devices failed to power down, " | 244 | printk(KERN_ERR "PM: Some devices failed to power down, " |
236 | "aborting hibernation\n"); | 245 | "aborting hibernation\n"); |
237 | goto Power_up_devices; | 246 | goto Enable_irqs; |
238 | } | 247 | } |
239 | 248 | ||
240 | if (hibernation_test(TEST_CORE)) | 249 | if (hibernation_test(TEST_CORE)) |
@@ -250,15 +259,22 @@ static int create_image(int platform_mode) | |||
250 | restore_processor_state(); | 259 | restore_processor_state(); |
251 | if (!in_suspend) | 260 | if (!in_suspend) |
252 | platform_leave(platform_mode); | 261 | platform_leave(platform_mode); |
262 | |||
253 | Power_up: | 263 | Power_up: |
254 | sysdev_resume(); | 264 | sysdev_resume(); |
255 | /* NOTE: device_power_up() is just a resume() for devices | 265 | /* NOTE: device_power_up() is just a resume() for devices |
256 | * that suspended with irqs off ... no overall powerup. | 266 | * that suspended with irqs off ... no overall powerup. |
257 | */ | 267 | */ |
258 | 268 | ||
259 | Power_up_devices: | 269 | Enable_irqs: |
260 | local_irq_enable(); | 270 | local_irq_enable(); |
261 | 271 | ||
272 | Enable_cpus: | ||
273 | enable_nonboot_cpus(); | ||
274 | |||
275 | Platform_finish: | ||
276 | platform_finish(platform_mode); | ||
277 | |||
262 | device_power_up(in_suspend ? | 278 | device_power_up(in_suspend ? |
263 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 279 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
264 | 280 | ||
@@ -298,25 +314,9 @@ int hibernation_snapshot(int platform_mode) | |||
298 | if (hibernation_test(TEST_DEVICES)) | 314 | if (hibernation_test(TEST_DEVICES)) |
299 | goto Recover_platform; | 315 | goto Recover_platform; |
300 | 316 | ||
301 | error = platform_pre_snapshot(platform_mode); | 317 | error = create_image(platform_mode); |
302 | if (error || hibernation_test(TEST_PLATFORM)) | 318 | /* Control returns here after successful restore */ |
303 | goto Finish; | ||
304 | |||
305 | error = disable_nonboot_cpus(); | ||
306 | if (!error) { | ||
307 | if (hibernation_test(TEST_CPUS)) | ||
308 | goto Enable_cpus; | ||
309 | |||
310 | if (hibernation_testmode(HIBERNATION_TEST)) | ||
311 | goto Enable_cpus; | ||
312 | 319 | ||
313 | error = create_image(platform_mode); | ||
314 | /* Control returns here after successful restore */ | ||
315 | } | ||
316 | Enable_cpus: | ||
317 | enable_nonboot_cpus(); | ||
318 | Finish: | ||
319 | platform_finish(platform_mode); | ||
320 | Resume_devices: | 320 | Resume_devices: |
321 | device_resume(in_suspend ? | 321 | device_resume(in_suspend ? |
322 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 322 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
@@ -338,7 +338,7 @@ int hibernation_snapshot(int platform_mode) | |||
338 | * kernel. | 338 | * kernel. |
339 | */ | 339 | */ |
340 | 340 | ||
341 | static int resume_target_kernel(void) | 341 | static int resume_target_kernel(bool platform_mode) |
342 | { | 342 | { |
343 | int error; | 343 | int error; |
344 | 344 | ||
@@ -351,9 +351,20 @@ static int resume_target_kernel(void) | |||
351 | goto Unlock; | 351 | goto Unlock; |
352 | } | 352 | } |
353 | 353 | ||
354 | error = platform_pre_restore(platform_mode); | ||
355 | if (error) | ||
356 | goto Cleanup; | ||
357 | |||
358 | error = disable_nonboot_cpus(); | ||
359 | if (error) | ||
360 | goto Enable_cpus; | ||
361 | |||
354 | local_irq_disable(); | 362 | local_irq_disable(); |
355 | 363 | ||
356 | sysdev_suspend(PMSG_QUIESCE); | 364 | error = sysdev_suspend(PMSG_QUIESCE); |
365 | if (error) | ||
366 | goto Enable_irqs; | ||
367 | |||
357 | /* We'll ignore saved state, but this gets preempt count (etc) right */ | 368 | /* We'll ignore saved state, but this gets preempt count (etc) right */ |
358 | save_processor_state(); | 369 | save_processor_state(); |
359 | error = restore_highmem(); | 370 | error = restore_highmem(); |
@@ -379,8 +390,15 @@ static int resume_target_kernel(void) | |||
379 | 390 | ||
380 | sysdev_resume(); | 391 | sysdev_resume(); |
381 | 392 | ||
393 | Enable_irqs: | ||
382 | local_irq_enable(); | 394 | local_irq_enable(); |
383 | 395 | ||
396 | Enable_cpus: | ||
397 | enable_nonboot_cpus(); | ||
398 | |||
399 | Cleanup: | ||
400 | platform_restore_cleanup(platform_mode); | ||
401 | |||
384 | device_power_up(PMSG_RECOVER); | 402 | device_power_up(PMSG_RECOVER); |
385 | 403 | ||
386 | Unlock: | 404 | Unlock: |
@@ -405,19 +423,10 @@ int hibernation_restore(int platform_mode) | |||
405 | pm_prepare_console(); | 423 | pm_prepare_console(); |
406 | suspend_console(); | 424 | suspend_console(); |
407 | error = device_suspend(PMSG_QUIESCE); | 425 | error = device_suspend(PMSG_QUIESCE); |
408 | if (error) | ||
409 | goto Finish; | ||
410 | |||
411 | error = platform_pre_restore(platform_mode); | ||
412 | if (!error) { | 426 | if (!error) { |
413 | error = disable_nonboot_cpus(); | 427 | error = resume_target_kernel(platform_mode); |
414 | if (!error) | 428 | device_resume(PMSG_RECOVER); |
415 | error = resume_target_kernel(); | ||
416 | enable_nonboot_cpus(); | ||
417 | } | 429 | } |
418 | platform_restore_cleanup(platform_mode); | ||
419 | device_resume(PMSG_RECOVER); | ||
420 | Finish: | ||
421 | resume_console(); | 430 | resume_console(); |
422 | pm_restore_console(); | 431 | pm_restore_console(); |
423 | return error; | 432 | return error; |
@@ -453,34 +462,38 @@ int hibernation_platform_enter(void) | |||
453 | goto Resume_devices; | 462 | goto Resume_devices; |
454 | } | 463 | } |
455 | 464 | ||
465 | device_pm_lock(); | ||
466 | |||
467 | error = device_power_down(PMSG_HIBERNATE); | ||
468 | if (error) | ||
469 | goto Unlock; | ||
470 | |||
456 | error = hibernation_ops->prepare(); | 471 | error = hibernation_ops->prepare(); |
457 | if (error) | 472 | if (error) |
458 | goto Resume_devices; | 473 | goto Platofrm_finish; |
459 | 474 | ||
460 | error = disable_nonboot_cpus(); | 475 | error = disable_nonboot_cpus(); |
461 | if (error) | 476 | if (error) |
462 | goto Finish; | 477 | goto Platofrm_finish; |
463 | |||
464 | device_pm_lock(); | ||
465 | |||
466 | error = device_power_down(PMSG_HIBERNATE); | ||
467 | if (!error) { | ||
468 | local_irq_disable(); | ||
469 | sysdev_suspend(PMSG_HIBERNATE); | ||
470 | hibernation_ops->enter(); | ||
471 | /* We should never get here */ | ||
472 | while (1); | ||
473 | } | ||
474 | 478 | ||
475 | device_pm_unlock(); | 479 | local_irq_disable(); |
480 | sysdev_suspend(PMSG_HIBERNATE); | ||
481 | hibernation_ops->enter(); | ||
482 | /* We should never get here */ | ||
483 | while (1); | ||
476 | 484 | ||
477 | /* | 485 | /* |
478 | * We don't need to reenable the nonboot CPUs or resume consoles, since | 486 | * We don't need to reenable the nonboot CPUs or resume consoles, since |
479 | * the system is going to be halted anyway. | 487 | * the system is going to be halted anyway. |
480 | */ | 488 | */ |
481 | Finish: | 489 | Platofrm_finish: |
482 | hibernation_ops->finish(); | 490 | hibernation_ops->finish(); |
483 | 491 | ||
492 | device_power_up(PMSG_RESTORE); | ||
493 | |||
494 | Unlock: | ||
495 | device_pm_unlock(); | ||
496 | |||
484 | Resume_devices: | 497 | Resume_devices: |
485 | entering_platform_hibernation = false; | 498 | entering_platform_hibernation = false; |
486 | device_resume(PMSG_RESTORE); | 499 | device_resume(PMSG_RESTORE); |