aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/sleep.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/acpi/sleep.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/acpi/sleep.c')
-rw-r--r--drivers/acpi/sleep.c119
1 files changed, 99 insertions, 20 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 5f2c379ab7bf..baa76bbf244a 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -81,6 +81,23 @@ static int acpi_sleep_prepare(u32 acpi_state)
81#ifdef CONFIG_ACPI_SLEEP 81#ifdef CONFIG_ACPI_SLEEP
82static u32 acpi_target_sleep_state = ACPI_STATE_S0; 82static u32 acpi_target_sleep_state = ACPI_STATE_S0;
83/* 83/*
84 * According to the ACPI specification the BIOS should make sure that ACPI is
85 * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still,
86 * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI
87 * on such systems during resume. Unfortunately that doesn't help in
88 * particularly pathological cases in which SCI_EN has to be set directly on
89 * resume, although the specification states very clearly that this flag is
90 * owned by the hardware. The set_sci_en_on_resume variable will be set in such
91 * cases.
92 */
93static bool set_sci_en_on_resume;
94
95void __init acpi_set_sci_en_on_resume(void)
96{
97 set_sci_en_on_resume = true;
98}
99
100/*
84 * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the 101 * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
85 * user to request that behavior by using the 'acpi_old_suspend_ordering' 102 * user to request that behavior by using the 'acpi_old_suspend_ordering'
86 * kernel command line option that causes the following variable to be set. 103 * kernel command line option that causes the following variable to be set.
@@ -170,18 +187,6 @@ static void acpi_pm_end(void)
170#endif /* CONFIG_ACPI_SLEEP */ 187#endif /* CONFIG_ACPI_SLEEP */
171 188
172#ifdef CONFIG_SUSPEND 189#ifdef CONFIG_SUSPEND
173/*
174 * According to the ACPI specification the BIOS should make sure that ACPI is
175 * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still,
176 * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI
177 * on such systems during resume. Unfortunately that doesn't help in
178 * particularly pathological cases in which SCI_EN has to be set directly on
179 * resume, although the specification states very clearly that this flag is
180 * owned by the hardware. The set_sci_en_on_resume variable will be set in such
181 * cases.
182 */
183static bool set_sci_en_on_resume;
184
185extern void do_suspend_lowlevel(void); 190extern void do_suspend_lowlevel(void);
186 191
187static u32 acpi_suspend_states[] = { 192static u32 acpi_suspend_states[] = {
@@ -445,6 +450,38 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
445 }, 450 },
446 }, 451 },
447 { 452 {
453 .callback = init_set_sci_en_on_resume,
454 .ident = "Lenovo ThinkPad T410",
455 .matches = {
456 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
457 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T410"),
458 },
459 },
460 {
461 .callback = init_set_sci_en_on_resume,
462 .ident = "Lenovo ThinkPad T510",
463 .matches = {
464 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
465 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T510"),
466 },
467 },
468 {
469 .callback = init_set_sci_en_on_resume,
470 .ident = "Lenovo ThinkPad W510",
471 .matches = {
472 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
473 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W510"),
474 },
475 },
476 {
477 .callback = init_set_sci_en_on_resume,
478 .ident = "Lenovo ThinkPad X201[s]",
479 .matches = {
480 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
481 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201"),
482 },
483 },
484 {
448 .callback = init_old_suspend_ordering, 485 .callback = init_old_suspend_ordering,
449 .ident = "Panasonic CF51-2L", 486 .ident = "Panasonic CF51-2L",
450 .matches = { 487 .matches = {
@@ -453,6 +490,30 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
453 DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), 490 DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
454 }, 491 },
455 }, 492 },
493 {
494 .callback = init_set_sci_en_on_resume,
495 .ident = "Dell Studio 1558",
496 .matches = {
497 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
498 DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1558"),
499 },
500 },
501 {
502 .callback = init_set_sci_en_on_resume,
503 .ident = "Dell Studio 1557",
504 .matches = {
505 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
506 DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"),
507 },
508 },
509 {
510 .callback = init_set_sci_en_on_resume,
511 .ident = "Dell Studio 1555",
512 .matches = {
513 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
514 DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1555"),
515 },
516 },
456 {}, 517 {},
457}; 518};
458#endif /* CONFIG_SUSPEND */ 519#endif /* CONFIG_SUSPEND */
@@ -547,8 +608,17 @@ static void acpi_hibernation_leave(void)
547 hibernate_nvs_restore(); 608 hibernate_nvs_restore();
548} 609}
549 610
550static void acpi_pm_enable_gpes(void) 611static int acpi_pm_pre_restore(void)
551{ 612{
613 acpi_disable_all_gpes();
614 acpi_os_wait_events_complete(NULL);
615 acpi_ec_suspend_transactions();
616 return 0;
617}
618
619static void acpi_pm_restore_cleanup(void)
620{
621 acpi_ec_resume_transactions();
552 acpi_enable_all_runtime_gpes(); 622 acpi_enable_all_runtime_gpes();
553} 623}
554 624
@@ -560,8 +630,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
560 .prepare = acpi_pm_prepare, 630 .prepare = acpi_pm_prepare,
561 .enter = acpi_hibernation_enter, 631 .enter = acpi_hibernation_enter,
562 .leave = acpi_hibernation_leave, 632 .leave = acpi_hibernation_leave,
563 .pre_restore = acpi_pm_disable_gpes, 633 .pre_restore = acpi_pm_pre_restore,
564 .restore_cleanup = acpi_pm_enable_gpes, 634 .restore_cleanup = acpi_pm_restore_cleanup,
565}; 635};
566 636
567/** 637/**
@@ -613,8 +683,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = {
613 .prepare = acpi_pm_disable_gpes, 683 .prepare = acpi_pm_disable_gpes,
614 .enter = acpi_hibernation_enter, 684 .enter = acpi_hibernation_enter,
615 .leave = acpi_hibernation_leave, 685 .leave = acpi_hibernation_leave,
616 .pre_restore = acpi_pm_disable_gpes, 686 .pre_restore = acpi_pm_pre_restore,
617 .restore_cleanup = acpi_pm_enable_gpes, 687 .restore_cleanup = acpi_pm_restore_cleanup,
618 .recover = acpi_pm_finish, 688 .recover = acpi_pm_finish,
619}; 689};
620#endif /* CONFIG_HIBERNATION */ 690#endif /* CONFIG_HIBERNATION */
@@ -740,9 +810,18 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
740 return -ENODEV; 810 return -ENODEV;
741 } 811 }
742 812
743 error = enable ? 813 if (enable) {
744 acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : 814 error = acpi_enable_wakeup_device_power(adev,
745 acpi_disable_wakeup_device_power(adev); 815 acpi_target_sleep_state);
816 if (!error)
817 acpi_enable_gpe(adev->wakeup.gpe_device,
818 adev->wakeup.gpe_number,
819 ACPI_GPE_TYPE_WAKE);
820 } else {
821 acpi_disable_gpe(adev->wakeup.gpe_device, adev->wakeup.gpe_number,
822 ACPI_GPE_TYPE_WAKE);
823 error = acpi_disable_wakeup_device_power(adev);
824 }
746 if (!error) 825 if (!error)
747 dev_info(dev, "wake-up capability %s by ACPI\n", 826 dev_info(dev, "wake-up capability %s by ACPI\n",
748 enable ? "enabled" : "disabled"); 827 enable ? "enabled" : "disabled");