diff options
Diffstat (limited to 'kernel/power/disk.c')
-rw-r--r-- | kernel/power/disk.c | 138 |
1 files changed, 85 insertions, 53 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 4a4a206b1979..e886d1332a10 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -214,7 +214,7 @@ static int create_image(int platform_mode) | |||
214 | return error; | 214 | return error; |
215 | 215 | ||
216 | device_pm_lock(); | 216 | device_pm_lock(); |
217 | local_irq_disable(); | 217 | |
218 | /* At this point, device_suspend() has been called, but *not* | 218 | /* At this point, device_suspend() has been called, but *not* |
219 | * device_power_down(). We *must* call device_power_down() now. | 219 | * device_power_down(). We *must* call device_power_down() now. |
220 | * Otherwise, drivers for some devices (e.g. interrupt controllers) | 220 | * Otherwise, drivers for some devices (e.g. interrupt controllers) |
@@ -225,13 +225,25 @@ static int create_image(int platform_mode) | |||
225 | if (error) { | 225 | if (error) { |
226 | printk(KERN_ERR "PM: Some devices failed to power down, " | 226 | printk(KERN_ERR "PM: Some devices failed to power down, " |
227 | "aborting hibernation\n"); | 227 | "aborting hibernation\n"); |
228 | goto Enable_irqs; | 228 | goto Unlock; |
229 | } | 229 | } |
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 | |||
240 | local_irq_disable(); | ||
241 | |||
230 | sysdev_suspend(PMSG_FREEZE); | 242 | sysdev_suspend(PMSG_FREEZE); |
231 | if (error) { | 243 | if (error) { |
232 | printk(KERN_ERR "PM: Some devices failed to power down, " | 244 | printk(KERN_ERR "PM: Some devices failed to power down, " |
233 | "aborting hibernation\n"); | 245 | "aborting hibernation\n"); |
234 | goto Power_up_devices; | 246 | goto Enable_irqs; |
235 | } | 247 | } |
236 | 248 | ||
237 | if (hibernation_test(TEST_CORE)) | 249 | if (hibernation_test(TEST_CORE)) |
@@ -247,17 +259,28 @@ static int create_image(int platform_mode) | |||
247 | restore_processor_state(); | 259 | restore_processor_state(); |
248 | if (!in_suspend) | 260 | if (!in_suspend) |
249 | platform_leave(platform_mode); | 261 | platform_leave(platform_mode); |
262 | |||
250 | Power_up: | 263 | Power_up: |
251 | sysdev_resume(); | 264 | sysdev_resume(); |
252 | /* NOTE: device_power_up() is just a resume() for devices | 265 | /* NOTE: device_power_up() is just a resume() for devices |
253 | * that suspended with irqs off ... no overall powerup. | 266 | * that suspended with irqs off ... no overall powerup. |
254 | */ | 267 | */ |
255 | Power_up_devices: | 268 | |
256 | device_power_up(in_suspend ? | ||
257 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
258 | Enable_irqs: | 269 | Enable_irqs: |
259 | local_irq_enable(); | 270 | local_irq_enable(); |
271 | |||
272 | Enable_cpus: | ||
273 | enable_nonboot_cpus(); | ||
274 | |||
275 | Platform_finish: | ||
276 | platform_finish(platform_mode); | ||
277 | |||
278 | device_power_up(in_suspend ? | ||
279 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
280 | |||
281 | Unlock: | ||
260 | device_pm_unlock(); | 282 | device_pm_unlock(); |
283 | |||
261 | return error; | 284 | return error; |
262 | } | 285 | } |
263 | 286 | ||
@@ -291,25 +314,9 @@ int hibernation_snapshot(int platform_mode) | |||
291 | if (hibernation_test(TEST_DEVICES)) | 314 | if (hibernation_test(TEST_DEVICES)) |
292 | goto Recover_platform; | 315 | goto Recover_platform; |
293 | 316 | ||
294 | error = platform_pre_snapshot(platform_mode); | 317 | error = create_image(platform_mode); |
295 | if (error || hibernation_test(TEST_PLATFORM)) | 318 | /* Control returns here after successful restore */ |
296 | goto Finish; | ||
297 | |||
298 | error = disable_nonboot_cpus(); | ||
299 | if (!error) { | ||
300 | if (hibernation_test(TEST_CPUS)) | ||
301 | goto Enable_cpus; | ||
302 | |||
303 | if (hibernation_testmode(HIBERNATION_TEST)) | ||
304 | goto Enable_cpus; | ||
305 | 319 | ||
306 | error = create_image(platform_mode); | ||
307 | /* Control returns here after successful restore */ | ||
308 | } | ||
309 | Enable_cpus: | ||
310 | enable_nonboot_cpus(); | ||
311 | Finish: | ||
312 | platform_finish(platform_mode); | ||
313 | Resume_devices: | 320 | Resume_devices: |
314 | device_resume(in_suspend ? | 321 | device_resume(in_suspend ? |
315 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 322 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
@@ -331,19 +338,33 @@ int hibernation_snapshot(int platform_mode) | |||
331 | * kernel. | 338 | * kernel. |
332 | */ | 339 | */ |
333 | 340 | ||
334 | static int resume_target_kernel(void) | 341 | static int resume_target_kernel(bool platform_mode) |
335 | { | 342 | { |
336 | int error; | 343 | int error; |
337 | 344 | ||
338 | device_pm_lock(); | 345 | device_pm_lock(); |
339 | local_irq_disable(); | 346 | |
340 | error = device_power_down(PMSG_QUIESCE); | 347 | error = device_power_down(PMSG_QUIESCE); |
341 | if (error) { | 348 | if (error) { |
342 | printk(KERN_ERR "PM: Some devices failed to power down, " | 349 | printk(KERN_ERR "PM: Some devices failed to power down, " |
343 | "aborting resume\n"); | 350 | "aborting resume\n"); |
344 | goto Enable_irqs; | 351 | goto Unlock; |
345 | } | 352 | } |
346 | sysdev_suspend(PMSG_QUIESCE); | 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 | |||
362 | local_irq_disable(); | ||
363 | |||
364 | error = sysdev_suspend(PMSG_QUIESCE); | ||
365 | if (error) | ||
366 | goto Enable_irqs; | ||
367 | |||
347 | /* 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 */ |
348 | save_processor_state(); | 369 | save_processor_state(); |
349 | error = restore_highmem(); | 370 | error = restore_highmem(); |
@@ -366,11 +387,23 @@ static int resume_target_kernel(void) | |||
366 | swsusp_free(); | 387 | swsusp_free(); |
367 | restore_processor_state(); | 388 | restore_processor_state(); |
368 | touch_softlockup_watchdog(); | 389 | touch_softlockup_watchdog(); |
390 | |||
369 | sysdev_resume(); | 391 | sysdev_resume(); |
370 | device_power_up(PMSG_RECOVER); | 392 | |
371 | Enable_irqs: | 393 | Enable_irqs: |
372 | local_irq_enable(); | 394 | local_irq_enable(); |
395 | |||
396 | Enable_cpus: | ||
397 | enable_nonboot_cpus(); | ||
398 | |||
399 | Cleanup: | ||
400 | platform_restore_cleanup(platform_mode); | ||
401 | |||
402 | device_power_up(PMSG_RECOVER); | ||
403 | |||
404 | Unlock: | ||
373 | device_pm_unlock(); | 405 | device_pm_unlock(); |
406 | |||
374 | return error; | 407 | return error; |
375 | } | 408 | } |
376 | 409 | ||
@@ -390,19 +423,10 @@ int hibernation_restore(int platform_mode) | |||
390 | pm_prepare_console(); | 423 | pm_prepare_console(); |
391 | suspend_console(); | 424 | suspend_console(); |
392 | error = device_suspend(PMSG_QUIESCE); | 425 | error = device_suspend(PMSG_QUIESCE); |
393 | if (error) | ||
394 | goto Finish; | ||
395 | |||
396 | error = platform_pre_restore(platform_mode); | ||
397 | if (!error) { | 426 | if (!error) { |
398 | error = disable_nonboot_cpus(); | 427 | error = resume_target_kernel(platform_mode); |
399 | if (!error) | 428 | device_resume(PMSG_RECOVER); |
400 | error = resume_target_kernel(); | ||
401 | enable_nonboot_cpus(); | ||
402 | } | 429 | } |
403 | platform_restore_cleanup(platform_mode); | ||
404 | device_resume(PMSG_RECOVER); | ||
405 | Finish: | ||
406 | resume_console(); | 430 | resume_console(); |
407 | pm_restore_console(); | 431 | pm_restore_console(); |
408 | return error; | 432 | return error; |
@@ -438,38 +462,46 @@ int hibernation_platform_enter(void) | |||
438 | goto Resume_devices; | 462 | goto Resume_devices; |
439 | } | 463 | } |
440 | 464 | ||
465 | device_pm_lock(); | ||
466 | |||
467 | error = device_power_down(PMSG_HIBERNATE); | ||
468 | if (error) | ||
469 | goto Unlock; | ||
470 | |||
441 | error = hibernation_ops->prepare(); | 471 | error = hibernation_ops->prepare(); |
442 | if (error) | 472 | if (error) |
443 | goto Resume_devices; | 473 | goto Platofrm_finish; |
444 | 474 | ||
445 | error = disable_nonboot_cpus(); | 475 | error = disable_nonboot_cpus(); |
446 | if (error) | 476 | if (error) |
447 | goto Finish; | 477 | goto Platofrm_finish; |
448 | 478 | ||
449 | device_pm_lock(); | ||
450 | local_irq_disable(); | 479 | local_irq_disable(); |
451 | error = device_power_down(PMSG_HIBERNATE); | 480 | sysdev_suspend(PMSG_HIBERNATE); |
452 | if (!error) { | 481 | hibernation_ops->enter(); |
453 | sysdev_suspend(PMSG_HIBERNATE); | 482 | /* We should never get here */ |
454 | hibernation_ops->enter(); | 483 | while (1); |
455 | /* We should never get here */ | ||
456 | while (1); | ||
457 | } | ||
458 | local_irq_enable(); | ||
459 | device_pm_unlock(); | ||
460 | 484 | ||
461 | /* | 485 | /* |
462 | * 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 |
463 | * the system is going to be halted anyway. | 487 | * the system is going to be halted anyway. |
464 | */ | 488 | */ |
465 | Finish: | 489 | Platofrm_finish: |
466 | hibernation_ops->finish(); | 490 | hibernation_ops->finish(); |
491 | |||
492 | device_power_up(PMSG_RESTORE); | ||
493 | |||
494 | Unlock: | ||
495 | device_pm_unlock(); | ||
496 | |||
467 | Resume_devices: | 497 | Resume_devices: |
468 | entering_platform_hibernation = false; | 498 | entering_platform_hibernation = false; |
469 | device_resume(PMSG_RESTORE); | 499 | device_resume(PMSG_RESTORE); |
470 | resume_console(); | 500 | resume_console(); |
501 | |||
471 | Close: | 502 | Close: |
472 | hibernation_ops->end(); | 503 | hibernation_ops->end(); |
504 | |||
473 | return error; | 505 | return error; |
474 | } | 506 | } |
475 | 507 | ||