|  | From 7900596ec1aeb58ee6e66b7fef6bfb23dfed5c65 Mon Sep 17 00:00:00 2001 | 
|  | From: Steven Rostedt <rostedt@goodmis.org> | 
|  | Date: Wed, 13 Feb 2013 09:26:05 -0500 | 
|  | Subject: [PATCH 214/351] acpi/rt: Convert acpi_gbl_hardware lock back to a | 
|  | raw_spinlock_t | 
|  | X-NVConfidentiality: public | 
|  |  | 
|  | We hit the following bug with 3.6-rt: | 
|  |  | 
|  | [    5.898990] BUG: scheduling while atomic: swapper/3/0/0x00000002 | 
|  | [    5.898991] no locks held by swapper/3/0. | 
|  | [    5.898993] Modules linked in: | 
|  | [    5.898996] Pid: 0, comm: swapper/3 Not tainted 3.6.11-rt28.19.el6rt.x86_64.debug #1 | 
|  | [    5.898997] Call Trace: | 
|  | [    5.899011]  [<ffffffff810804e7>] __schedule_bug+0x67/0x90 | 
|  | [    5.899028]  [<ffffffff81577923>] __schedule+0x793/0x7a0 | 
|  | [    5.899032]  [<ffffffff810b4e40>] ? debug_rt_mutex_print_deadlock+0x50/0x200 | 
|  | [    5.899034]  [<ffffffff81577b89>] schedule+0x29/0x70 | 
|  | [    5.899036] BUG: scheduling while atomic: swapper/7/0/0x00000002 | 
|  | [    5.899037] no locks held by swapper/7/0. | 
|  | [    5.899039]  [<ffffffff81578525>] rt_spin_lock_slowlock+0xe5/0x2f0 | 
|  | [    5.899040] Modules linked in: | 
|  | [    5.899041] | 
|  | [    5.899045]  [<ffffffff81579a58>] ? _raw_spin_unlock_irqrestore+0x38/0x90 | 
|  | [    5.899046] Pid: 0, comm: swapper/7 Not tainted 3.6.11-rt28.19.el6rt.x86_64.debug #1 | 
|  | [    5.899047] Call Trace: | 
|  | [    5.899049]  [<ffffffff81578bc6>] rt_spin_lock+0x16/0x40 | 
|  | [    5.899052]  [<ffffffff810804e7>] __schedule_bug+0x67/0x90 | 
|  | [    5.899054]  [<ffffffff8157d3f0>] ? notifier_call_chain+0x80/0x80 | 
|  | [    5.899056]  [<ffffffff81577923>] __schedule+0x793/0x7a0 | 
|  | [    5.899059]  [<ffffffff812f2034>] acpi_os_acquire_lock+0x1f/0x23 | 
|  | [    5.899062]  [<ffffffff810b4e40>] ? debug_rt_mutex_print_deadlock+0x50/0x200 | 
|  | [    5.899068]  [<ffffffff8130be64>] acpi_write_bit_register+0x33/0xb0 | 
|  | [    5.899071]  [<ffffffff81577b89>] schedule+0x29/0x70 | 
|  | [    5.899072]  [<ffffffff8130be13>] ? acpi_read_bit_register+0x33/0x51 | 
|  | [    5.899074]  [<ffffffff81578525>] rt_spin_lock_slowlock+0xe5/0x2f0 | 
|  | [    5.899077]  [<ffffffff8131d1fc>] acpi_idle_enter_bm+0x8a/0x28e | 
|  | [    5.899079]  [<ffffffff81579a58>] ? _raw_spin_unlock_irqrestore+0x38/0x90 | 
|  | [    5.899081]  [<ffffffff8107e5da>] ? this_cpu_load+0x1a/0x30 | 
|  | [    5.899083]  [<ffffffff81578bc6>] rt_spin_lock+0x16/0x40 | 
|  | [    5.899087]  [<ffffffff8144c759>] cpuidle_enter+0x19/0x20 | 
|  | [    5.899088]  [<ffffffff8157d3f0>] ? notifier_call_chain+0x80/0x80 | 
|  | [    5.899090]  [<ffffffff8144c777>] cpuidle_enter_state+0x17/0x50 | 
|  | [    5.899092]  [<ffffffff812f2034>] acpi_os_acquire_lock+0x1f/0x23 | 
|  | [    5.899094]  [<ffffffff8144d1a1>] cpuidle899101]  [<ffffffff8130be13>] ? | 
|  |  | 
|  | As the acpi code disables interrupts in acpi_idle_enter_bm, and calls | 
|  | code that grabs the acpi lock, it causes issues as the lock is currently | 
|  | in RT a sleeping lock. | 
|  |  | 
|  | The lock was converted from a raw to a sleeping lock due to some | 
|  | previous issues, and tests that showed it didn't seem to matter. | 
|  | Unfortunately, it did matter for one of our boxes. | 
|  |  | 
|  | This patch converts the lock back to a raw lock. I've run this code on a | 
|  | few of my own machines, one being my laptop that uses the acpi quite | 
|  | extensively. I've been able to suspend and resume without issues. | 
|  |  | 
|  | [ tglx: Made the change exclusive for acpi_gbl_hardware_lock ] | 
|  |  | 
|  | Signed-off-by: Steven Rostedt <rostedt@goodmis.org> | 
|  | Cc: John Kacur <jkacur@gmail.com> | 
|  | Cc: Clark Williams <clark@redhat.com> | 
|  | Link: http://lkml.kernel.org/r/1360765565.23152.5.camel@gandalf.local.home | 
|  |  | 
|  | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | 
|  | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 
|  | --- | 
|  | drivers/acpi/acpica/acglobal.h  |  2 +- | 
|  | drivers/acpi/acpica/hwregs.c    |  4 ++-- | 
|  | drivers/acpi/acpica/hwxface.c   |  4 ++-- | 
|  | drivers/acpi/acpica/utmutex.c   |  4 ++-- | 
|  | include/acpi/platform/aclinux.h | 15 +++++++++++++++ | 
|  | 5 files changed, 22 insertions(+), 7 deletions(-) | 
|  |  | 
|  | diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h | 
|  | index faa97604d878..941497f31cf0 100644 | 
|  | --- a/drivers/acpi/acpica/acglobal.h | 
|  | +++ b/drivers/acpi/acpica/acglobal.h | 
|  | @@ -116,7 +116,7 @@ ACPI_GLOBAL(u8, acpi_gbl_global_lock_pending); | 
|  | * interrupt level | 
|  | */ | 
|  | ACPI_GLOBAL(acpi_spinlock, acpi_gbl_gpe_lock);	/* For GPE data structs and registers */ | 
|  | -ACPI_GLOBAL(acpi_spinlock, acpi_gbl_hardware_lock);	/* For ACPI H/W except GPE registers */ | 
|  | +ACPI_GLOBAL(acpi_raw_spinlock, acpi_gbl_hardware_lock);	/* For ACPI H/W except GPE registers */ | 
|  | ACPI_GLOBAL(acpi_spinlock, acpi_gbl_reference_count_lock); | 
|  |  | 
|  | /* Mutex for _OSI support */ | 
|  | diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c | 
|  | index 3cf77afd142c..dc32e72132f1 100644 | 
|  | --- a/drivers/acpi/acpica/hwregs.c | 
|  | +++ b/drivers/acpi/acpica/hwregs.c | 
|  | @@ -269,14 +269,14 @@ acpi_status acpi_hw_clear_acpi_status(void) | 
|  | ACPI_BITMASK_ALL_FIXED_STATUS, | 
|  | ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); | 
|  |  | 
|  | -	lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); | 
|  | +	raw_spin_lock_irqsave(acpi_gbl_hardware_lock, lock_flags); | 
|  |  | 
|  | /* Clear the fixed events in PM1 A/B */ | 
|  |  | 
|  | status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, | 
|  | ACPI_BITMASK_ALL_FIXED_STATUS); | 
|  |  | 
|  | -	acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); | 
|  | +	raw_spin_unlock_irqrestore(acpi_gbl_hardware_lock, lock_flags); | 
|  |  | 
|  | if (ACPI_FAILURE(status)) { | 
|  | goto exit; | 
|  | diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c | 
|  | index 5f97468df8ff..8c017f15da7d 100644 | 
|  | --- a/drivers/acpi/acpica/hwxface.c | 
|  | +++ b/drivers/acpi/acpica/hwxface.c | 
|  | @@ -374,7 +374,7 @@ acpi_status acpi_write_bit_register(u32 register_id, u32 value) | 
|  | return_ACPI_STATUS(AE_BAD_PARAMETER); | 
|  | } | 
|  |  | 
|  | -	lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); | 
|  | +	raw_spin_lock_irqsave(acpi_gbl_hardware_lock, lock_flags); | 
|  |  | 
|  | /* | 
|  | * At this point, we know that the parent register is one of the | 
|  | @@ -435,7 +435,7 @@ acpi_status acpi_write_bit_register(u32 register_id, u32 value) | 
|  |  | 
|  | unlock_and_exit: | 
|  |  | 
|  | -	acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); | 
|  | +	raw_spin_unlock_irqrestore(acpi_gbl_hardware_lock, lock_flags); | 
|  | return_ACPI_STATUS(status); | 
|  | } | 
|  |  | 
|  | diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c | 
|  | index ce406e39b669..41a75eb3ae9d 100644 | 
|  | --- a/drivers/acpi/acpica/utmutex.c | 
|  | +++ b/drivers/acpi/acpica/utmutex.c | 
|  | @@ -88,7 +88,7 @@ acpi_status acpi_ut_mutex_initialize(void) | 
|  | return_ACPI_STATUS (status); | 
|  | } | 
|  |  | 
|  | -	status = acpi_os_create_lock (&acpi_gbl_hardware_lock); | 
|  | +	status = acpi_os_create_raw_lock (&acpi_gbl_hardware_lock); | 
|  | if (ACPI_FAILURE (status)) { | 
|  | return_ACPI_STATUS (status); | 
|  | } | 
|  | @@ -156,7 +156,7 @@ void acpi_ut_mutex_terminate(void) | 
|  | /* Delete the spinlocks */ | 
|  |  | 
|  | acpi_os_delete_lock(acpi_gbl_gpe_lock); | 
|  | -	acpi_os_delete_lock(acpi_gbl_hardware_lock); | 
|  | +	acpi_os_delete_raw_lock(acpi_gbl_hardware_lock); | 
|  | acpi_os_delete_lock(acpi_gbl_reference_count_lock); | 
|  |  | 
|  | /* Delete the reader/writer lock */ | 
|  | diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h | 
|  | index 323e5daece54..cc5fbd534fd4 100644 | 
|  | --- a/include/acpi/platform/aclinux.h | 
|  | +++ b/include/acpi/platform/aclinux.h | 
|  | @@ -127,6 +127,7 @@ | 
|  |  | 
|  | #define acpi_cache_t                        struct kmem_cache | 
|  | #define acpi_spinlock                       spinlock_t * | 
|  | +#define acpi_raw_spinlock		raw_spinlock_t * | 
|  | #define acpi_cpu_flags                      unsigned long | 
|  |  | 
|  | /* Use native linux version of acpi_os_allocate_zeroed */ | 
|  | @@ -145,6 +146,20 @@ | 
|  | #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_thread_id | 
|  | #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_lock | 
|  |  | 
|  | +#define acpi_os_create_raw_lock(__handle)			\ | 
|  | +({								\ | 
|  | +	 raw_spinlock_t *lock = ACPI_ALLOCATE(sizeof(*lock));	\ | 
|  | +								\ | 
|  | +	 if (lock) {						\ | 
|  | +		*(__handle) = lock;				\ | 
|  | +		raw_spin_lock_init(*(__handle));		\ | 
|  | +	 }							\ | 
|  | +	 lock ? AE_OK : AE_NO_MEMORY;				\ | 
|  | + }) | 
|  | + | 
|  | +#define acpi_os_delete_raw_lock(__handle)	kfree(__handle) | 
|  | + | 
|  | + | 
|  | /* | 
|  | * OSL interfaces used by debugger/disassembler | 
|  | */ | 
|  | -- | 
|  | 2.10.1 | 
|  |  |