diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2010-04-22 11:47:51 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-26 14:27:07 -0700 |
commit | 843447c62b771a9ad12f0e7f4a791804b4cc99f5 (patch) | |
tree | 46dff7ba661b3cb7a9abee96d29b7d6d1feac23a /drivers | |
parent | 0851f4563b9e0770d4b3c071e605cb5e150c6ed3 (diff) |
clockevent: Prevent dead lock on clockevents_lock
This is a merge of two mainline commits, intended
for stable@kernel.org submission for 2.6.27 kernel.
commit f833bab87fca5c3ce13778421b1365845843b976
and
commit 918aae42aa9b611a3663b16ae849fdedc67c2292
Changelog of both:
Currently clockevents_notify() is called with interrupts enabled at
some places and interrupts disabled at some other places.
This results in a deadlock in this scenario.
cpu A holds clockevents_lock in clockevents_notify() with irqs enabled
cpu B waits for clockevents_lock in clockevents_notify() with irqs disabled
cpu C doing set_mtrr() which will try to rendezvous of all the cpus.
This will result in C and A come to the rendezvous point and waiting
for B. B is stuck forever waiting for the spinlock and thus not
reaching the rendezvous point.
Fix the clockevents code so that clockevents_lock is taken with
interrupts disabled and thus avoid the above deadlock.
Also call lapic_timer_propagate_broadcast() on the destination cpu so
that we avoid calling smp_call_function() in the clockevents notifier
chain.
This issue left us wondering if we need to change the MTRR rendezvous
logic to use stop machine logic (instead of smp_call_function) or add
a check in spinlock debug code to see if there are other spinlocks
which gets taken under both interrupts enabled/disabled conditions.
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: "Brown Len" <len.brown@intel.com>
Cc: stable@kernel.org
LKML-Reference: <1250544899.2709.210.camel@sbs-t61.sc.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
I got following warning on ia64 box:
In function 'acpi_processor_power_verify':
642: warning: passing argument 2 of 'smp_call_function_single' from
incompatible pointer type
This smp_call_function_single() was introduced by a commit
f833bab87fca5c3ce13778421b1365845843b976:
The problem is that the lapic_timer_propagate_broadcast() has 2 versions:
One is real code that modified in the above commit, and the other is NOP
code that used when !ARCH_APICTIMER_STOPS_ON_C3:
static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) { }
So I got warning because of !ARCH_APICTIMER_STOPS_ON_C3.
We really want to do nothing here on !ARCH_APICTIMER_STOPS_ON_C3, so
modify lapic_timer_propagate_broadcast() of real version to use
smp_call_function_single() in it.
Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Acked-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/processor_idle.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 5639e27cb49..94483a2a61f 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -317,8 +317,9 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr, pr->power.timer_broadcast_on_state = state; } -static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) +static void __lapic_timer_propagate_broadcast(void *arg) { + struct acpi_processor *pr = (struct acpi_processor *) arg; unsigned long reason; reason = pr->power.timer_broadcast_on_state < INT_MAX ? @@ -327,6 +328,12 @@ static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) clockevents_notify(reason, &pr->id); } +static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) +{ + smp_call_function_single(pr->id, __lapic_timer_propagate_broadcast, + (void *)pr, 1); +} + /* Power(C) State timer broadcast control */ static void acpi_state_timer_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, @@ -347,7 +354,7 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, static void acpi_timer_check_state(int state, struct acpi_processor *pr, struct acpi_processor_cx *cstate) { } -static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { } +static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) { } static void acpi_state_timer_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, int broadcast) @@ -1177,7 +1184,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) working++; } - acpi_propagate_timer_broadcast(pr); + lapic_timer_propagate_broadcast(pr); return (working); } |