diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2010-04-09 01:39:40 +0200 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-05-28 23:35:55 -0400 |
commit | d5a64513c6a171262082c250592c062e97a2c693 (patch) | |
tree | ebcbe81e8ea4fd4ba773fe4d35698b71a88f77ee /drivers/acpi/ec.c | |
parent | e40152ee1e1c7a63f4777791863215e3faa37a86 (diff) |
ACPI / EC / PM: Fix race between EC transactions and system suspend
There still is a race that may result in suspending the system in
the middle of an EC transaction in progress, which leads to problems
(like the kernel thinking that the ACPI global lock is held during
resume while in fact it's not).
To remove the race condition, modify the ACPI platform suspend and
hibernate callbacks so that EC transactions are blocked right after
executing the _PTS global control method and are allowed to happen
again right after the low-level wakeup.
Introduce acpi_pm_freeze() that will disable GPEs, wait until the
event queues are empty and block EC transactions. Use it wherever
GPEs are disabled in preparation for switching local interrupts off.
Introduce acpi_pm_thaw() that will allow EC transactions to happen
again and enable runtime GPEs. Use it to balance acpi_pm_freeze()
wherever necessary.
In addition to that use acpi_ec_resume_transactions_early() to
unblock EC transactions as early as reasonably possible during
resume. Also unblock EC transactions in acpi_hibernation_finish()
and in the analogous suspend routine to make sure that the EC
transactions are enabled in all error paths.
Fixes https://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/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index f2234db85da0..2c2b73a2a7c2 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -485,6 +485,16 @@ void acpi_ec_resume_transactions(void) mutex_unlock(&ec->lock); } +void acpi_ec_resume_transactions_early(void) +{ + /* + * Allow transactions to happen again (this function is called from + * atomic context during wakeup, so we don't need to acquire the mutex). + */ + if (first_ec) + clear_bit(EC_FLAGS_FROZEN, &first_ec->flags); +} + static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) { int result; |