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(); |
