diff options
Diffstat (limited to 'drivers')
-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 d8242772de92..7e3c609cbef2 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, |