[kernel/f13/master] acpi-ec-pm-fix-race-between-ec-transactions-and-system-suspend.patch

Chuck Ebbert cebbert at fedoraproject.org
Sat Sep 4 03:34:57 UTC 2010


commit e00d73683c8da6ce617075c4613a690c14c82d6b
Author: Chuck Ebbert <cebbert at redhat.com>
Date:   Fri Sep 3 23:35:20 2010 -0400

    acpi-ec-pm-fix-race-between-ec-transactions-and-system-suspend.patch
    
    another possible fix for suspend/resume problems.

 ...etween-ec-transactions-and-system-suspend.patch |  215 ++++++++++++++++++++
 kernel.spec                                        |   16 ++-
 2 files changed, 228 insertions(+), 3 deletions(-)
---
diff --git a/acpi-ec-pm-fix-race-between-ec-transactions-and-system-suspend.patch b/acpi-ec-pm-fix-race-between-ec-transactions-and-system-suspend.patch
new file mode 100644
index 0000000..85d6756
--- /dev/null
+++ b/acpi-ec-pm-fix-race-between-ec-transactions-and-system-suspend.patch
@@ -0,0 +1,215 @@
+From: Rafael J. Wysocki <rjw at sisk.pl>
+Date: Thu, 8 Apr 2010 23:39:40 +0000 (+0200)
+Subject: ACPI / EC / PM: Fix race between EC transactions and system suspend
+X-Git-Tag: v2.6.35-rc2~39^2~3
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=d5a64513c6a171262082c250592c062e97a2c693
+
+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 at sisk.pl>
+Reported-and-tested-by: Maxim Levitsky <maximlevitsky at gmail.com>
+Signed-off-by: Len Brown <len.brown at intel.com>
+---
+
+diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
+index f2234db..2c2b73a 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;
+diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
+index e284113..0ec48c7 100644
+--- a/drivers/acpi/internal.h
++++ b/drivers/acpi/internal.h
+@@ -51,6 +51,7 @@ int acpi_ec_ecdt_probe(void);
+ int acpi_boot_ec_enable(void);
+ void acpi_ec_suspend_transactions(void);
+ void acpi_ec_resume_transactions(void);
++void acpi_ec_resume_transactions_early(void);
+ 
+ /*--------------------------------------------------------------------------
+                                   Suspend/Resume
+diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
+index baa76bb..24741ac 100644
+--- a/drivers/acpi/sleep.c
++++ b/drivers/acpi/sleep.c
+@@ -110,11 +110,13 @@ void __init acpi_old_suspend_ordering(void)
+ }
+ 
+ /**
+- *	acpi_pm_disable_gpes - Disable the GPEs.
++ * acpi_pm_freeze - Disable the GPEs and suspend EC transactions.
+  */
+-static int acpi_pm_disable_gpes(void)
++static int acpi_pm_freeze(void)
+ {
+ 	acpi_disable_all_gpes();
++	acpi_os_wait_events_complete(NULL);
++	acpi_ec_suspend_transactions();
+ 	return 0;
+ }
+ 
+@@ -142,7 +144,8 @@ static int acpi_pm_prepare(void)
+ 	int error = __acpi_pm_prepare();
+ 
+ 	if (!error)
+-		acpi_disable_all_gpes();
++		acpi_pm_freeze();
++
+ 	return error;
+ }
+ 
+@@ -275,6 +278,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
+ 	 * acpi_leave_sleep_state will reenable specific GPEs later
+ 	 */
+ 	acpi_disable_all_gpes();
++	/* Allow EC transactions to happen. */
++	acpi_ec_resume_transactions_early();
+ 
+ 	local_irq_restore(flags);
+ 	printk(KERN_DEBUG "Back to C!\n");
+@@ -286,6 +291,12 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
+ 	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+ }
+ 
++static void acpi_suspend_finish(void)
++{
++	acpi_ec_resume_transactions();
++	acpi_pm_finish();
++}
++
+ static int acpi_suspend_state_valid(suspend_state_t pm_state)
+ {
+ 	u32 acpi_state;
+@@ -307,7 +318,7 @@ static struct platform_suspend_ops acpi_suspend_ops = {
+ 	.begin = acpi_suspend_begin,
+ 	.prepare_late = acpi_pm_prepare,
+ 	.enter = acpi_suspend_enter,
+-	.wake = acpi_pm_finish,
++	.wake = acpi_suspend_finish,
+ 	.end = acpi_pm_end,
+ };
+ 
+@@ -333,9 +344,9 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state)
+ static struct platform_suspend_ops acpi_suspend_ops_old = {
+ 	.valid = acpi_suspend_state_valid,
+ 	.begin = acpi_suspend_begin_old,
+-	.prepare_late = acpi_pm_disable_gpes,
++	.prepare_late = acpi_pm_freeze,
+ 	.enter = acpi_suspend_enter,
+-	.wake = acpi_pm_finish,
++	.wake = acpi_suspend_finish,
+ 	.end = acpi_pm_end,
+ 	.recover = acpi_pm_finish,
+ };
+@@ -586,6 +597,7 @@ static int acpi_hibernation_enter(void)
+ static void acpi_hibernation_finish(void)
+ {
+ 	hibernate_nvs_free();
++	acpi_ec_resume_transactions();
+ 	acpi_pm_finish();
+ }
+ 
+@@ -606,17 +618,11 @@ static void acpi_hibernation_leave(void)
+ 	}
+ 	/* Restore the NVS memory area */
+ 	hibernate_nvs_restore();
++	/* Allow EC transactions to happen. */
++	acpi_ec_resume_transactions_early();
+ }
+ 
+-static int acpi_pm_pre_restore(void)
+-{
+-	acpi_disable_all_gpes();
+-	acpi_os_wait_events_complete(NULL);
+-	acpi_ec_suspend_transactions();
+-	return 0;
+-}
+-
+-static void acpi_pm_restore_cleanup(void)
++static void acpi_pm_thaw(void)
+ {
+ 	acpi_ec_resume_transactions();
+ 	acpi_enable_all_runtime_gpes();
+@@ -630,8 +636,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
+ 	.prepare = acpi_pm_prepare,
+ 	.enter = acpi_hibernation_enter,
+ 	.leave = acpi_hibernation_leave,
+-	.pre_restore = acpi_pm_pre_restore,
+-	.restore_cleanup = acpi_pm_restore_cleanup,
++	.pre_restore = acpi_pm_freeze,
++	.restore_cleanup = acpi_pm_thaw,
+ };
+ 
+ /**
+@@ -663,12 +669,9 @@ static int acpi_hibernation_begin_old(void)
+ 
+ static int acpi_hibernation_pre_snapshot_old(void)
+ {
+-	int error = acpi_pm_disable_gpes();
+-
+-	if (!error)
+-		hibernate_nvs_save();
+-
+-	return error;
++	acpi_pm_freeze();
++	hibernate_nvs_save();
++	return 0;
+ }
+ 
+ /*
+@@ -680,11 +683,11 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = {
+ 	.end = acpi_pm_end,
+ 	.pre_snapshot = acpi_hibernation_pre_snapshot_old,
+ 	.finish = acpi_hibernation_finish,
+-	.prepare = acpi_pm_disable_gpes,
++	.prepare = acpi_pm_freeze,
+ 	.enter = acpi_hibernation_enter,
+ 	.leave = acpi_hibernation_leave,
+-	.pre_restore = acpi_pm_pre_restore,
+-	.restore_cleanup = acpi_pm_restore_cleanup,
++	.pre_restore = acpi_pm_freeze,
++	.restore_cleanup = acpi_pm_thaw,
+ 	.recover = acpi_pm_finish,
+ };
+ #endif /* CONFIG_HIBERNATION */
diff --git a/kernel.spec b/kernel.spec
index af501ab..275872d 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -48,7 +48,7 @@ Summary: The Linux kernel
 # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec).
 # scripts/rebase.sh should be made to do that for you, actually.
 #
-%global baserelease 51
+%global baserelease 52
 %global fedora_build %{baserelease}
 
 # base_sublevel is the kernel version we're starting with and patching
@@ -771,10 +771,13 @@ Patch12480: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch
 Patch12490: dell-wmi-add-support-for-eject-key.patch
 Patch12500: irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch
 Patch12510: wireless-extensions-fix-kernel-heap-content-leak.patch
+
 Patch12515: sanity-check-bond-proc_entry.patch
 Patch12516: asix-use-eth_mac_addr.patch
 Patch12517: flexcop-fix-xlate_proc_name-warning.patch
 
+Patch12520: acpi-ec-pm-fix-race-between-ec-transactions-and-system-suspend.patch
+
 %endif
 
 BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root
@@ -1454,6 +1457,9 @@ ApplyPatch asix-use-eth_mac_addr.patch
 # bz #575873
 ApplyPatch flexcop-fix-xlate_proc_name-warning.patch
 
+# another fix for suspend/resume bugs
+ApplyPatch acpi-ec-pm-fix-race-between-ec-transactions-and-system-suspend.patch
+
 # END OF PATCH APPLICATIONS
 
 %endif
@@ -2075,9 +2081,13 @@ fi
 
 
 %changelog
-* Fri Sep 03 2010 Kyle McMartin <kmcmartin at redhat.com> 2.6.34.6-52
+* Fri Sep 03 2010 Chuck Ebbert <cebbert at redhat.com> 2.6.34.6-52
+- acpi-ec-pm-fix-race-between-ec-transactions-and-system-suspend.patch:
+  another possible fix for suspend/resume problems.
+
+* Fri Sep 03 2010 Kyle McMartin <kmcmartin at redhat.com>
 - sanity-check-bond-proc_entry.patch (rhbz#604630)
-- asix.c: stub out set_mac_address in case it's breaking things (rhbz#629871)
+- asix.c: stub out set_mac_address in case it's breaking things (rhbz#625479)
 - default to pci=nocrs
 - flexcop: fix registering braindead stupid names (#575873)
 


More information about the scm-commits mailing list