diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2010-03-03 19:52:58 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-03-08 14:15:51 -0500 |
commit | f6bb13aa1ea3bb26a4c783822347873f085b9000 (patch) | |
tree | e0350530685e0719d4318f052982aa4340a00650 /drivers/acpi/sleep.c | |
parent | 60b341b778cc2929df16c0a504c91621b3c6a4ad (diff) |
ACPI / EC / PM: Close race between EC and resume from hibernation
There is a race between resume from hibernation and the EC driver
that may result in restoring the hibernation image in the middle of
an EC transaction in progress, which in turn may lead to
unpredictable behavior of the platform.
To remove that race condition, add a helpers for suspending and
resuming EC transactions in a safe way to be executed by the ACPI
platform hibernate pre-restore and restore cleanup callbacks.
http://bugzilla.kernel.org/show_bug.cgi?id=14668
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Reported-and-tested-by: Maxim Levitsky <maximlevitsky@gmail.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/sleep.c')
-rw-r--r-- | drivers/acpi/sleep.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 79d33d908b5a..f01f8e84fd3d 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -552,8 +552,17 @@ static void acpi_hibernation_leave(void) | |||
552 | hibernate_nvs_restore(); | 552 | hibernate_nvs_restore(); |
553 | } | 553 | } |
554 | 554 | ||
555 | static void acpi_pm_enable_gpes(void) | 555 | static int acpi_pm_pre_restore(void) |
556 | { | 556 | { |
557 | acpi_disable_all_gpes(); | ||
558 | acpi_os_wait_events_complete(NULL); | ||
559 | acpi_ec_suspend_transactions(); | ||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static void acpi_pm_restore_cleanup(void) | ||
564 | { | ||
565 | acpi_ec_resume_transactions(); | ||
557 | acpi_enable_all_runtime_gpes(); | 566 | acpi_enable_all_runtime_gpes(); |
558 | } | 567 | } |
559 | 568 | ||
@@ -565,8 +574,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = { | |||
565 | .prepare = acpi_pm_prepare, | 574 | .prepare = acpi_pm_prepare, |
566 | .enter = acpi_hibernation_enter, | 575 | .enter = acpi_hibernation_enter, |
567 | .leave = acpi_hibernation_leave, | 576 | .leave = acpi_hibernation_leave, |
568 | .pre_restore = acpi_pm_disable_gpes, | 577 | .pre_restore = acpi_pm_pre_restore, |
569 | .restore_cleanup = acpi_pm_enable_gpes, | 578 | .restore_cleanup = acpi_pm_restore_cleanup, |
570 | }; | 579 | }; |
571 | 580 | ||
572 | /** | 581 | /** |
@@ -618,8 +627,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = { | |||
618 | .prepare = acpi_pm_disable_gpes, | 627 | .prepare = acpi_pm_disable_gpes, |
619 | .enter = acpi_hibernation_enter, | 628 | .enter = acpi_hibernation_enter, |
620 | .leave = acpi_hibernation_leave, | 629 | .leave = acpi_hibernation_leave, |
621 | .pre_restore = acpi_pm_disable_gpes, | 630 | .pre_restore = acpi_pm_pre_restore, |
622 | .restore_cleanup = acpi_pm_enable_gpes, | 631 | .restore_cleanup = acpi_pm_restore_cleanup, |
623 | .recover = acpi_pm_finish, | 632 | .recover = acpi_pm_finish, |
624 | }; | 633 | }; |
625 | #endif /* CONFIG_HIBERNATION */ | 634 | #endif /* CONFIG_HIBERNATION */ |