diff options
| author | Len Brown <len.brown@intel.com> | 2009-04-05 02:14:15 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2009-04-05 02:14:15 -0400 |
| commit | 478c6a43fcbc6c11609f8cee7c7b57223907754f (patch) | |
| tree | a7f7952099da60d33032aed6de9c0c56c9f8779e /kernel/power/disk.c | |
| parent | 8a3f257c704e02aee9869decd069a806b45be3f1 (diff) | |
| parent | 6bb597507f9839b13498781e481f5458aea33620 (diff) | |
Merge branch 'linus' into release
Conflicts:
arch/x86/kernel/cpu/cpufreq/longhaul.c
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'kernel/power/disk.c')
| -rw-r--r-- | kernel/power/disk.c | 143 |
1 files changed, 88 insertions, 55 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 4a4a206b1979..5f21ab2bbcdf 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/console.h> | 22 | #include <linux/console.h> |
| 23 | #include <linux/cpu.h> | 23 | #include <linux/cpu.h> |
| 24 | #include <linux/freezer.h> | 24 | #include <linux/freezer.h> |
| 25 | #include <asm/suspend.h> | ||
| 25 | 26 | ||
| 26 | #include "power.h" | 27 | #include "power.h" |
| 27 | 28 | ||
| @@ -214,7 +215,7 @@ static int create_image(int platform_mode) | |||
| 214 | return error; | 215 | return error; |
| 215 | 216 | ||
| 216 | device_pm_lock(); | 217 | device_pm_lock(); |
| 217 | local_irq_disable(); | 218 | |
| 218 | /* At this point, device_suspend() has been called, but *not* | 219 | /* At this point, device_suspend() has been called, but *not* |
| 219 | * device_power_down(). We *must* call device_power_down() now. | 220 | * device_power_down(). We *must* call device_power_down() now. |
| 220 | * Otherwise, drivers for some devices (e.g. interrupt controllers) | 221 | * Otherwise, drivers for some devices (e.g. interrupt controllers) |
| @@ -225,13 +226,25 @@ static int create_image(int platform_mode) | |||
| 225 | if (error) { | 226 | if (error) { |
| 226 | printk(KERN_ERR "PM: Some devices failed to power down, " | 227 | printk(KERN_ERR "PM: Some devices failed to power down, " |
| 227 | "aborting hibernation\n"); | 228 | "aborting hibernation\n"); |
| 228 | goto Enable_irqs; | 229 | goto Unlock; |
| 229 | } | 230 | } |
| 231 | |||
| 232 | error = platform_pre_snapshot(platform_mode); | ||
| 233 | if (error || hibernation_test(TEST_PLATFORM)) | ||
| 234 | goto Platform_finish; | ||
| 235 | |||
| 236 | error = disable_nonboot_cpus(); | ||
| 237 | if (error || hibernation_test(TEST_CPUS) | ||
| 238 | || hibernation_testmode(HIBERNATION_TEST)) | ||
| 239 | goto Enable_cpus; | ||
| 240 | |||
| 241 | local_irq_disable(); | ||
| 242 | |||
| 230 | sysdev_suspend(PMSG_FREEZE); | 243 | sysdev_suspend(PMSG_FREEZE); |
| 231 | if (error) { | 244 | if (error) { |
| 232 | printk(KERN_ERR "PM: Some devices failed to power down, " | 245 | printk(KERN_ERR "PM: Some devices failed to power down, " |
| 233 | "aborting hibernation\n"); | 246 | "aborting hibernation\n"); |
| 234 | goto Power_up_devices; | 247 | goto Enable_irqs; |
| 235 | } | 248 | } |
| 236 | 249 | ||
| 237 | if (hibernation_test(TEST_CORE)) | 250 | if (hibernation_test(TEST_CORE)) |
| @@ -247,17 +260,28 @@ static int create_image(int platform_mode) | |||
| 247 | restore_processor_state(); | 260 | restore_processor_state(); |
| 248 | if (!in_suspend) | 261 | if (!in_suspend) |
| 249 | platform_leave(platform_mode); | 262 | platform_leave(platform_mode); |
| 263 | |||
| 250 | Power_up: | 264 | Power_up: |
| 251 | sysdev_resume(); | 265 | sysdev_resume(); |
| 252 | /* NOTE: device_power_up() is just a resume() for devices | 266 | /* NOTE: device_power_up() is just a resume() for devices |
| 253 | * that suspended with irqs off ... no overall powerup. | 267 | * that suspended with irqs off ... no overall powerup. |
| 254 | */ | 268 | */ |
| 255 | Power_up_devices: | 269 | |
| 256 | device_power_up(in_suspend ? | ||
| 257 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
| 258 | Enable_irqs: | 270 | Enable_irqs: |
| 259 | local_irq_enable(); | 271 | local_irq_enable(); |
| 272 | |||
| 273 | Enable_cpus: | ||
| 274 | enable_nonboot_cpus(); | ||
| 275 | |||
| 276 | Platform_finish: | ||
| 277 | platform_finish(platform_mode); | ||
| 278 | |||
| 279 | device_power_up(in_suspend ? | ||
| 280 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
| 281 | |||
| 282 | Unlock: | ||
| 260 | device_pm_unlock(); | 283 | device_pm_unlock(); |
| 284 | |||
| 261 | return error; | 285 | return error; |
| 262 | } | 286 | } |
| 263 | 287 | ||
| @@ -265,7 +289,7 @@ static int create_image(int platform_mode) | |||
| 265 | * hibernation_snapshot - quiesce devices and create the hibernation | 289 | * hibernation_snapshot - quiesce devices and create the hibernation |
| 266 | * snapshot image. | 290 | * snapshot image. |
| 267 | * @platform_mode - if set, use the platform driver, if available, to | 291 | * @platform_mode - if set, use the platform driver, if available, to |
| 268 | * prepare the platform frimware for the power transition. | 292 | * prepare the platform firmware for the power transition. |
| 269 | * | 293 | * |
| 270 | * Must be called with pm_mutex held | 294 | * Must be called with pm_mutex held |
| 271 | */ | 295 | */ |
| @@ -291,25 +315,9 @@ int hibernation_snapshot(int platform_mode) | |||
| 291 | if (hibernation_test(TEST_DEVICES)) | 315 | if (hibernation_test(TEST_DEVICES)) |
| 292 | goto Recover_platform; | 316 | goto Recover_platform; |
| 293 | 317 | ||
| 294 | error = platform_pre_snapshot(platform_mode); | 318 | error = create_image(platform_mode); |
| 295 | if (error || hibernation_test(TEST_PLATFORM)) | 319 | /* 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 | 320 | ||
| 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: | 321 | Resume_devices: |
| 314 | device_resume(in_suspend ? | 322 | device_resume(in_suspend ? |
| 315 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 323 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
| @@ -331,19 +339,33 @@ int hibernation_snapshot(int platform_mode) | |||
| 331 | * kernel. | 339 | * kernel. |
| 332 | */ | 340 | */ |
| 333 | 341 | ||
| 334 | static int resume_target_kernel(void) | 342 | static int resume_target_kernel(bool platform_mode) |
| 335 | { | 343 | { |
| 336 | int error; | 344 | int error; |
| 337 | 345 | ||
| 338 | device_pm_lock(); | 346 | device_pm_lock(); |
| 339 | local_irq_disable(); | 347 | |
| 340 | error = device_power_down(PMSG_QUIESCE); | 348 | error = device_power_down(PMSG_QUIESCE); |
| 341 | if (error) { | 349 | if (error) { |
| 342 | printk(KERN_ERR "PM: Some devices failed to power down, " | 350 | printk(KERN_ERR "PM: Some devices failed to power down, " |
| 343 | "aborting resume\n"); | 351 | "aborting resume\n"); |
| 344 | goto Enable_irqs; | 352 | goto Unlock; |
| 345 | } | 353 | } |
| 346 | sysdev_suspend(PMSG_QUIESCE); | 354 | |
| 355 | error = platform_pre_restore(platform_mode); | ||
| 356 | if (error) | ||
| 357 | goto Cleanup; | ||
| 358 | |||
| 359 | error = disable_nonboot_cpus(); | ||
| 360 | if (error) | ||
| 361 | goto Enable_cpus; | ||
| 362 | |||
| 363 | local_irq_disable(); | ||
| 364 | |||
| 365 | error = sysdev_suspend(PMSG_QUIESCE); | ||
| 366 | if (error) | ||
| 367 | goto Enable_irqs; | ||
| 368 | |||
| 347 | /* We'll ignore saved state, but this gets preempt count (etc) right */ | 369 | /* We'll ignore saved state, but this gets preempt count (etc) right */ |
| 348 | save_processor_state(); | 370 | save_processor_state(); |
| 349 | error = restore_highmem(); | 371 | error = restore_highmem(); |
| @@ -366,11 +388,23 @@ static int resume_target_kernel(void) | |||
| 366 | swsusp_free(); | 388 | swsusp_free(); |
| 367 | restore_processor_state(); | 389 | restore_processor_state(); |
| 368 | touch_softlockup_watchdog(); | 390 | touch_softlockup_watchdog(); |
| 391 | |||
| 369 | sysdev_resume(); | 392 | sysdev_resume(); |
| 370 | device_power_up(PMSG_RECOVER); | 393 | |
| 371 | Enable_irqs: | 394 | Enable_irqs: |
| 372 | local_irq_enable(); | 395 | local_irq_enable(); |
| 396 | |||
| 397 | Enable_cpus: | ||
| 398 | enable_nonboot_cpus(); | ||
| 399 | |||
| 400 | Cleanup: | ||
| 401 | platform_restore_cleanup(platform_mode); | ||
| 402 | |||
| 403 | device_power_up(PMSG_RECOVER); | ||
| 404 | |||
| 405 | Unlock: | ||
| 373 | device_pm_unlock(); | 406 | device_pm_unlock(); |
| 407 | |||
| 374 | return error; | 408 | return error; |
| 375 | } | 409 | } |
| 376 | 410 | ||
| @@ -378,7 +412,7 @@ static int resume_target_kernel(void) | |||
| 378 | * hibernation_restore - quiesce devices and restore the hibernation | 412 | * hibernation_restore - quiesce devices and restore the hibernation |
| 379 | * snapshot image. If successful, control returns in hibernation_snaphot() | 413 | * snapshot image. If successful, control returns in hibernation_snaphot() |
| 380 | * @platform_mode - if set, use the platform driver, if available, to | 414 | * @platform_mode - if set, use the platform driver, if available, to |
| 381 | * prepare the platform frimware for the transition. | 415 | * prepare the platform firmware for the transition. |
| 382 | * | 416 | * |
| 383 | * Must be called with pm_mutex held | 417 | * Must be called with pm_mutex held |
| 384 | */ | 418 | */ |
| @@ -390,19 +424,10 @@ int hibernation_restore(int platform_mode) | |||
| 390 | pm_prepare_console(); | 424 | pm_prepare_console(); |
| 391 | suspend_console(); | 425 | suspend_console(); |
| 392 | error = device_suspend(PMSG_QUIESCE); | 426 | error = device_suspend(PMSG_QUIESCE); |
| 393 | if (error) | ||
| 394 | goto Finish; | ||
| 395 | |||
| 396 | error = platform_pre_restore(platform_mode); | ||
| 397 | if (!error) { | 427 | if (!error) { |
| 398 | error = disable_nonboot_cpus(); | 428 | error = resume_target_kernel(platform_mode); |
| 399 | if (!error) | 429 | device_resume(PMSG_RECOVER); |
| 400 | error = resume_target_kernel(); | ||
| 401 | enable_nonboot_cpus(); | ||
| 402 | } | 430 | } |
| 403 | platform_restore_cleanup(platform_mode); | ||
| 404 | device_resume(PMSG_RECOVER); | ||
| 405 | Finish: | ||
| 406 | resume_console(); | 431 | resume_console(); |
| 407 | pm_restore_console(); | 432 | pm_restore_console(); |
| 408 | return error; | 433 | return error; |
| @@ -438,38 +463,46 @@ int hibernation_platform_enter(void) | |||
| 438 | goto Resume_devices; | 463 | goto Resume_devices; |
| 439 | } | 464 | } |
| 440 | 465 | ||
| 466 | device_pm_lock(); | ||
| 467 | |||
| 468 | error = device_power_down(PMSG_HIBERNATE); | ||
| 469 | if (error) | ||
| 470 | goto Unlock; | ||
| 471 | |||
| 441 | error = hibernation_ops->prepare(); | 472 | error = hibernation_ops->prepare(); |
| 442 | if (error) | 473 | if (error) |
| 443 | goto Resume_devices; | 474 | goto Platofrm_finish; |
| 444 | 475 | ||
| 445 | error = disable_nonboot_cpus(); | 476 | error = disable_nonboot_cpus(); |
| 446 | if (error) | 477 | if (error) |
| 447 | goto Finish; | 478 | goto Platofrm_finish; |
| 448 | 479 | ||
| 449 | device_pm_lock(); | ||
| 450 | local_irq_disable(); | 480 | local_irq_disable(); |
| 451 | error = device_power_down(PMSG_HIBERNATE); | 481 | sysdev_suspend(PMSG_HIBERNATE); |
| 452 | if (!error) { | 482 | hibernation_ops->enter(); |
| 453 | sysdev_suspend(PMSG_HIBERNATE); | 483 | /* We should never get here */ |
| 454 | hibernation_ops->enter(); | 484 | while (1); |
| 455 | /* We should never get here */ | ||
| 456 | while (1); | ||
| 457 | } | ||
| 458 | local_irq_enable(); | ||
| 459 | device_pm_unlock(); | ||
| 460 | 485 | ||
| 461 | /* | 486 | /* |
| 462 | * We don't need to reenable the nonboot CPUs or resume consoles, since | 487 | * We don't need to reenable the nonboot CPUs or resume consoles, since |
| 463 | * the system is going to be halted anyway. | 488 | * the system is going to be halted anyway. |
| 464 | */ | 489 | */ |
| 465 | Finish: | 490 | Platofrm_finish: |
| 466 | hibernation_ops->finish(); | 491 | hibernation_ops->finish(); |
| 492 | |||
| 493 | device_power_up(PMSG_RESTORE); | ||
| 494 | |||
| 495 | Unlock: | ||
| 496 | device_pm_unlock(); | ||
| 497 | |||
| 467 | Resume_devices: | 498 | Resume_devices: |
| 468 | entering_platform_hibernation = false; | 499 | entering_platform_hibernation = false; |
| 469 | device_resume(PMSG_RESTORE); | 500 | device_resume(PMSG_RESTORE); |
| 470 | resume_console(); | 501 | resume_console(); |
| 502 | |||
| 471 | Close: | 503 | Close: |
| 472 | hibernation_ops->end(); | 504 | hibernation_ops->end(); |
| 505 | |||
| 473 | return error; | 506 | return error; |
| 474 | } | 507 | } |
| 475 | 508 | ||
