aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/sleep.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/sleep.c')
-rw-r--r--drivers/acpi/sleep.c63
1 files changed, 33 insertions, 30 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 3fb4bdea7e06..2862c781b372 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -82,6 +82,20 @@ static int acpi_sleep_prepare(u32 acpi_state)
82static u32 acpi_target_sleep_state = ACPI_STATE_S0; 82static u32 acpi_target_sleep_state = ACPI_STATE_S0;
83 83
84/* 84/*
85 * The ACPI specification wants us to save NVS memory regions during hibernation
86 * and to restore them during the subsequent resume. Windows does that also for
87 * suspend to RAM. However, it is known that this mechanism does not work on
88 * all machines, so we allow the user to disable it with the help of the
89 * 'acpi_sleep=nonvs' kernel command line option.
90 */
91static bool nvs_nosave;
92
93void __init acpi_nvs_nosave(void)
94{
95 nvs_nosave = true;
96}
97
98/*
85 * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the 99 * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
86 * user to request that behavior by using the 'acpi_old_suspend_ordering' 100 * user to request that behavior by using the 'acpi_old_suspend_ordering'
87 * kernel command line option that causes the following variable to be set. 101 * kernel command line option that causes the following variable to be set.
@@ -114,6 +128,8 @@ static int __acpi_pm_prepare(void)
114{ 128{
115 int error = acpi_sleep_prepare(acpi_target_sleep_state); 129 int error = acpi_sleep_prepare(acpi_target_sleep_state);
116 130
131 suspend_nvs_save();
132
117 if (error) 133 if (error)
118 acpi_target_sleep_state = ACPI_STATE_S0; 134 acpi_target_sleep_state = ACPI_STATE_S0;
119 return error; 135 return error;
@@ -143,6 +159,9 @@ static void acpi_pm_finish(void)
143{ 159{
144 u32 acpi_state = acpi_target_sleep_state; 160 u32 acpi_state = acpi_target_sleep_state;
145 161
162 suspend_nvs_free();
163 acpi_ec_unblock_transactions();
164
146 if (acpi_state == ACPI_STATE_S0) 165 if (acpi_state == ACPI_STATE_S0)
147 return; 166 return;
148 167
@@ -192,6 +211,10 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
192 u32 acpi_state = acpi_suspend_states[pm_state]; 211 u32 acpi_state = acpi_suspend_states[pm_state];
193 int error = 0; 212 int error = 0;
194 213
214 error = nvs_nosave ? 0 : suspend_nvs_alloc();
215 if (error)
216 return error;
217
195 if (sleep_states[acpi_state]) { 218 if (sleep_states[acpi_state]) {
196 acpi_target_sleep_state = acpi_state; 219 acpi_target_sleep_state = acpi_state;
197 acpi_sleep_tts_switch(acpi_target_sleep_state); 220 acpi_sleep_tts_switch(acpi_target_sleep_state);
@@ -269,12 +292,13 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
269 if (acpi_state == ACPI_STATE_S3) 292 if (acpi_state == ACPI_STATE_S3)
270 acpi_restore_state_mem(); 293 acpi_restore_state_mem();
271 294
295 suspend_nvs_restore();
296
272 return ACPI_SUCCESS(status) ? 0 : -EFAULT; 297 return ACPI_SUCCESS(status) ? 0 : -EFAULT;
273} 298}
274 299
275static void acpi_suspend_finish(void) 300static void acpi_suspend_finish(void)
276{ 301{
277 acpi_ec_unblock_transactions();
278 acpi_pm_finish(); 302 acpi_pm_finish();
279} 303}
280 304
@@ -377,20 +401,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
377#endif /* CONFIG_SUSPEND */ 401#endif /* CONFIG_SUSPEND */
378 402
379#ifdef CONFIG_HIBERNATION 403#ifdef CONFIG_HIBERNATION
380/*
381 * The ACPI specification wants us to save NVS memory regions during hibernation
382 * and to restore them during the subsequent resume. However, it is not certain
383 * if this mechanism is going to work on all machines, so we allow the user to
384 * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
385 * option.
386 */
387static bool s4_no_nvs;
388
389void __init acpi_s4_no_nvs(void)
390{
391 s4_no_nvs = true;
392}
393
394static unsigned long s4_hardware_signature; 404static unsigned long s4_hardware_signature;
395static struct acpi_table_facs *facs; 405static struct acpi_table_facs *facs;
396static bool nosigcheck; 406static bool nosigcheck;
@@ -404,7 +414,7 @@ static int acpi_hibernation_begin(void)
404{ 414{
405 int error; 415 int error;
406 416
407 error = s4_no_nvs ? 0 : hibernate_nvs_alloc(); 417 error = nvs_nosave ? 0 : suspend_nvs_alloc();
408 if (!error) { 418 if (!error) {
409 acpi_target_sleep_state = ACPI_STATE_S4; 419 acpi_target_sleep_state = ACPI_STATE_S4;
410 acpi_sleep_tts_switch(acpi_target_sleep_state); 420 acpi_sleep_tts_switch(acpi_target_sleep_state);
@@ -418,7 +428,7 @@ static int acpi_hibernation_pre_snapshot(void)
418 int error = acpi_pm_prepare(); 428 int error = acpi_pm_prepare();
419 429
420 if (!error) 430 if (!error)
421 hibernate_nvs_save(); 431 suspend_nvs_save();
422 432
423 return error; 433 return error;
424} 434}
@@ -441,13 +451,6 @@ static int acpi_hibernation_enter(void)
441 return ACPI_SUCCESS(status) ? 0 : -EFAULT; 451 return ACPI_SUCCESS(status) ? 0 : -EFAULT;
442} 452}
443 453
444static void acpi_hibernation_finish(void)
445{
446 hibernate_nvs_free();
447 acpi_ec_unblock_transactions();
448 acpi_pm_finish();
449}
450
451static void acpi_hibernation_leave(void) 454static void acpi_hibernation_leave(void)
452{ 455{
453 /* 456 /*
@@ -464,7 +467,7 @@ static void acpi_hibernation_leave(void)
464 panic("ACPI S4 hardware signature mismatch"); 467 panic("ACPI S4 hardware signature mismatch");
465 } 468 }
466 /* Restore the NVS memory area */ 469 /* Restore the NVS memory area */
467 hibernate_nvs_restore(); 470 suspend_nvs_restore();
468 /* Allow EC transactions to happen. */ 471 /* Allow EC transactions to happen. */
469 acpi_ec_unblock_transactions_early(); 472 acpi_ec_unblock_transactions_early();
470} 473}
@@ -479,7 +482,7 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
479 .begin = acpi_hibernation_begin, 482 .begin = acpi_hibernation_begin,
480 .end = acpi_pm_end, 483 .end = acpi_pm_end,
481 .pre_snapshot = acpi_hibernation_pre_snapshot, 484 .pre_snapshot = acpi_hibernation_pre_snapshot,
482 .finish = acpi_hibernation_finish, 485 .finish = acpi_pm_finish,
483 .prepare = acpi_pm_prepare, 486 .prepare = acpi_pm_prepare,
484 .enter = acpi_hibernation_enter, 487 .enter = acpi_hibernation_enter,
485 .leave = acpi_hibernation_leave, 488 .leave = acpi_hibernation_leave,
@@ -506,8 +509,8 @@ static int acpi_hibernation_begin_old(void)
506 error = acpi_sleep_prepare(ACPI_STATE_S4); 509 error = acpi_sleep_prepare(ACPI_STATE_S4);
507 510
508 if (!error) { 511 if (!error) {
509 if (!s4_no_nvs) 512 if (!nvs_nosave)
510 error = hibernate_nvs_alloc(); 513 error = suspend_nvs_alloc();
511 if (!error) 514 if (!error)
512 acpi_target_sleep_state = ACPI_STATE_S4; 515 acpi_target_sleep_state = ACPI_STATE_S4;
513 } 516 }
@@ -517,7 +520,7 @@ static int acpi_hibernation_begin_old(void)
517static int acpi_hibernation_pre_snapshot_old(void) 520static int acpi_hibernation_pre_snapshot_old(void)
518{ 521{
519 acpi_pm_freeze(); 522 acpi_pm_freeze();
520 hibernate_nvs_save(); 523 suspend_nvs_save();
521 return 0; 524 return 0;
522} 525}
523 526
@@ -529,8 +532,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = {
529 .begin = acpi_hibernation_begin_old, 532 .begin = acpi_hibernation_begin_old,
530 .end = acpi_pm_end, 533 .end = acpi_pm_end,
531 .pre_snapshot = acpi_hibernation_pre_snapshot_old, 534 .pre_snapshot = acpi_hibernation_pre_snapshot_old,
532 .finish = acpi_hibernation_finish,
533 .prepare = acpi_pm_freeze, 535 .prepare = acpi_pm_freeze,
536 .finish = acpi_pm_finish,
534 .enter = acpi_hibernation_enter, 537 .enter = acpi_hibernation_enter,
535 .leave = acpi_hibernation_leave, 538 .leave = acpi_hibernation_leave,
536 .pre_restore = acpi_pm_freeze, 539 .pre_restore = acpi_pm_freeze,