aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/sleep.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-03-03 19:52:58 -0500
committerLen Brown <len.brown@intel.com>2010-03-08 14:15:51 -0500
commitf6bb13aa1ea3bb26a4c783822347873f085b9000 (patch)
treee0350530685e0719d4318f052982aa4340a00650 /drivers/acpi/sleep.c
parent60b341b778cc2929df16c0a504c91621b3c6a4ad (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.c19
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
555static void acpi_pm_enable_gpes(void) 555static 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
563static 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 */