diff options
Diffstat (limited to 'drivers/acpi/main.c')
| -rw-r--r-- | drivers/acpi/main.c | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/drivers/acpi/main.c b/drivers/acpi/main.c index d8242772de9..7e3c609cbef 100644 --- a/drivers/acpi/main.c +++ b/drivers/acpi/main.c | |||
| @@ -101,6 +101,19 @@ void __init acpi_old_suspend_ordering(void) | |||
| 101 | * cases. | 101 | * cases. |
| 102 | */ | 102 | */ |
| 103 | static bool set_sci_en_on_resume; | 103 | static bool set_sci_en_on_resume; |
| 104 | /* | ||
| 105 | * The ACPI specification wants us to save NVS memory regions during hibernation | ||
| 106 | * and to restore them during the subsequent resume. However, it is not certain | ||
| 107 | * if this mechanism is going to work on all machines, so we allow the user to | ||
| 108 | * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line | ||
| 109 | * option. | ||
| 110 | */ | ||
| 111 | static bool s4_no_nvs; | ||
| 112 | |||
| 113 | void __init acpi_s4_no_nvs(void) | ||
| 114 | { | ||
| 115 | s4_no_nvs = true; | ||
| 116 | } | ||
| 104 | 117 | ||
| 105 | /** | 118 | /** |
| 106 | * acpi_pm_disable_gpes - Disable the GPEs. | 119 | * acpi_pm_disable_gpes - Disable the GPEs. |
| @@ -394,9 +407,25 @@ void __init acpi_no_s4_hw_signature(void) | |||
| 394 | 407 | ||
| 395 | static int acpi_hibernation_begin(void) | 408 | static int acpi_hibernation_begin(void) |
| 396 | { | 409 | { |
| 397 | acpi_target_sleep_state = ACPI_STATE_S4; | 410 | int error; |
| 398 | acpi_sleep_tts_switch(acpi_target_sleep_state); | 411 | |
| 399 | return 0; | 412 | error = s4_no_nvs ? 0 : hibernate_nvs_alloc(); |
| 413 | if (!error) { | ||
| 414 | acpi_target_sleep_state = ACPI_STATE_S4; | ||
| 415 | acpi_sleep_tts_switch(acpi_target_sleep_state); | ||
| 416 | } | ||
| 417 | |||
| 418 | return error; | ||
| 419 | } | ||
| 420 | |||
| 421 | static int acpi_hibernation_pre_snapshot(void) | ||
| 422 | { | ||
| 423 | int error = acpi_pm_prepare(); | ||
| 424 | |||
| 425 | if (!error) | ||
| 426 | hibernate_nvs_save(); | ||
| 427 | |||
| 428 | return error; | ||
| 400 | } | 429 | } |
| 401 | 430 | ||
| 402 | static int acpi_hibernation_enter(void) | 431 | static int acpi_hibernation_enter(void) |
| @@ -417,6 +446,12 @@ static int acpi_hibernation_enter(void) | |||
| 417 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | 446 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; |
| 418 | } | 447 | } |
| 419 | 448 | ||
| 449 | static void acpi_hibernation_finish(void) | ||
| 450 | { | ||
| 451 | hibernate_nvs_free(); | ||
| 452 | acpi_pm_finish(); | ||
| 453 | } | ||
| 454 | |||
| 420 | static void acpi_hibernation_leave(void) | 455 | static void acpi_hibernation_leave(void) |
| 421 | { | 456 | { |
| 422 | /* | 457 | /* |
| @@ -432,6 +467,8 @@ static void acpi_hibernation_leave(void) | |||
| 432 | "cannot resume!\n"); | 467 | "cannot resume!\n"); |
| 433 | panic("ACPI S4 hardware signature mismatch"); | 468 | panic("ACPI S4 hardware signature mismatch"); |
| 434 | } | 469 | } |
| 470 | /* Restore the NVS memory area */ | ||
| 471 | hibernate_nvs_restore(); | ||
| 435 | } | 472 | } |
| 436 | 473 | ||
| 437 | static void acpi_pm_enable_gpes(void) | 474 | static void acpi_pm_enable_gpes(void) |
| @@ -442,8 +479,8 @@ static void acpi_pm_enable_gpes(void) | |||
| 442 | static struct platform_hibernation_ops acpi_hibernation_ops = { | 479 | static struct platform_hibernation_ops acpi_hibernation_ops = { |
| 443 | .begin = acpi_hibernation_begin, | 480 | .begin = acpi_hibernation_begin, |
| 444 | .end = acpi_pm_end, | 481 | .end = acpi_pm_end, |
| 445 | .pre_snapshot = acpi_pm_prepare, | 482 | .pre_snapshot = acpi_hibernation_pre_snapshot, |
| 446 | .finish = acpi_pm_finish, | 483 | .finish = acpi_hibernation_finish, |
| 447 | .prepare = acpi_pm_prepare, | 484 | .prepare = acpi_pm_prepare, |
| 448 | .enter = acpi_hibernation_enter, | 485 | .enter = acpi_hibernation_enter, |
| 449 | .leave = acpi_hibernation_leave, | 486 | .leave = acpi_hibernation_leave, |
| @@ -469,8 +506,22 @@ static int acpi_hibernation_begin_old(void) | |||
| 469 | 506 | ||
| 470 | error = acpi_sleep_prepare(ACPI_STATE_S4); | 507 | error = acpi_sleep_prepare(ACPI_STATE_S4); |
| 471 | 508 | ||
| 509 | if (!error) { | ||
| 510 | if (!s4_no_nvs) | ||
| 511 | error = hibernate_nvs_alloc(); | ||
| 512 | if (!error) | ||
| 513 | acpi_target_sleep_state = ACPI_STATE_S4; | ||
| 514 | } | ||
| 515 | return error; | ||
| 516 | } | ||
| 517 | |||
| 518 | static int acpi_hibernation_pre_snapshot_old(void) | ||
| 519 | { | ||
| 520 | int error = acpi_pm_disable_gpes(); | ||
| 521 | |||
| 472 | if (!error) | 522 | if (!error) |
| 473 | acpi_target_sleep_state = ACPI_STATE_S4; | 523 | hibernate_nvs_save(); |
| 524 | |||
| 474 | return error; | 525 | return error; |
| 475 | } | 526 | } |
| 476 | 527 | ||
| @@ -481,8 +532,8 @@ static int acpi_hibernation_begin_old(void) | |||
| 481 | static struct platform_hibernation_ops acpi_hibernation_ops_old = { | 532 | static struct platform_hibernation_ops acpi_hibernation_ops_old = { |
| 482 | .begin = acpi_hibernation_begin_old, | 533 | .begin = acpi_hibernation_begin_old, |
| 483 | .end = acpi_pm_end, | 534 | .end = acpi_pm_end, |
| 484 | .pre_snapshot = acpi_pm_disable_gpes, | 535 | .pre_snapshot = acpi_hibernation_pre_snapshot_old, |
| 485 | .finish = acpi_pm_finish, | 536 | .finish = acpi_hibernation_finish, |
| 486 | .prepare = acpi_pm_disable_gpes, | 537 | .prepare = acpi_pm_disable_gpes, |
| 487 | .enter = acpi_hibernation_enter, | 538 | .enter = acpi_hibernation_enter, |
| 488 | .leave = acpi_hibernation_leave, | 539 | .leave = acpi_hibernation_leave, |
