2012-05-12 14:20:55 +00:00
|
|
|
From 76f41af7cc93591a2723d2c59918df003f90cb09 Mon Sep 17 00:00:00 2001
|
2011-11-20 00:01:55 +00:00
|
|
|
From: Frederic Weisbecker <fweisbec@gmail.com>
|
2012-05-12 14:20:55 +00:00
|
|
|
Date: Mon, 26 Sep 2011 12:19:11 +0200
|
|
|
|
Subject: [PATCH 001/267] x86: Call idle notifier after irq_enter()
|
|
|
|
|
2011-11-20 00:01:55 +00:00
|
|
|
Interrupts notify the idle exit state before calling irq_enter(). But
|
|
|
|
the notifier code calls rcu_read_lock() and this is not allowed while
|
|
|
|
rcu is in an extended quiescent state. We need to wait for
|
|
|
|
rcu_irq_enter() to be called before doing so otherwise this results in
|
|
|
|
a grumpy RCU:
|
2012-05-12 14:20:55 +00:00
|
|
|
|
2011-11-20 00:01:55 +00:00
|
|
|
[ 0.099991] WARNING: at include/linux/rcupdate.h:194 __atomic_notifier_call_chain+0xd2/0x110()
|
|
|
|
[ 0.099991] Hardware name: AMD690VM-FMH
|
|
|
|
[ 0.099991] Modules linked in:
|
|
|
|
[ 0.099991] Pid: 0, comm: swapper Not tainted 3.0.0-rc6+ #255
|
|
|
|
[ 0.099991] Call Trace:
|
|
|
|
[ 0.099991] <IRQ> [<ffffffff81051c8a>] warn_slowpath_common+0x7a/0xb0
|
|
|
|
[ 0.099991] [<ffffffff81051cd5>] warn_slowpath_null+0x15/0x20
|
|
|
|
[ 0.099991] [<ffffffff817d6fa2>] __atomic_notifier_call_chain+0xd2/0x110
|
|
|
|
[ 0.099991] [<ffffffff817d6ff1>] atomic_notifier_call_chain+0x11/0x20
|
|
|
|
[ 0.099991] [<ffffffff81001873>] exit_idle+0x43/0x50
|
|
|
|
[ 0.099991] [<ffffffff81020439>] smp_apic_timer_interrupt+0x39/0xa0
|
|
|
|
[ 0.099991] [<ffffffff817da253>] apic_timer_interrupt+0x13/0x20
|
|
|
|
[ 0.099991] <EOI> [<ffffffff8100ae67>] ? default_idle+0xa7/0x350
|
|
|
|
[ 0.099991] [<ffffffff8100ae65>] ? default_idle+0xa5/0x350
|
|
|
|
[ 0.099991] [<ffffffff8100b19b>] amd_e400_idle+0x8b/0x110
|
|
|
|
[ 0.099991] [<ffffffff810cb01f>] ? rcu_enter_nohz+0x8f/0x160
|
|
|
|
[ 0.099991] [<ffffffff810019a0>] cpu_idle+0xb0/0x110
|
|
|
|
[ 0.099991] [<ffffffff817a7505>] rest_init+0xe5/0x140
|
|
|
|
[ 0.099991] [<ffffffff817a7468>] ? rest_init+0x48/0x140
|
|
|
|
[ 0.099991] [<ffffffff81cc5ca3>] start_kernel+0x3d1/0x3dc
|
|
|
|
[ 0.099991] [<ffffffff81cc5321>] x86_64_start_reservations+0x131/0x135
|
|
|
|
[ 0.099991] [<ffffffff81cc5412>] x86_64_start_kernel+0xed/0xf4
|
2012-05-12 14:20:55 +00:00
|
|
|
|
2011-11-20 00:01:55 +00:00
|
|
|
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
|
|
|
|
Link: http://lkml.kernel.org/r/20110929194047.GA10247@linux.vnet.ibm.com
|
|
|
|
Cc: Ingo Molnar <mingo@redhat.com>
|
|
|
|
Cc: H. Peter Anvin <hpa@zytor.com>
|
|
|
|
Cc: Andy Henroid <andrew.d.henroid@intel.com>
|
|
|
|
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
|
|
---
|
|
|
|
arch/x86/kernel/apic/apic.c | 6 +++---
|
|
|
|
arch/x86/kernel/apic/io_apic.c | 2 +-
|
|
|
|
arch/x86/kernel/cpu/mcheck/therm_throt.c | 2 +-
|
|
|
|
arch/x86/kernel/cpu/mcheck/threshold.c | 2 +-
|
|
|
|
arch/x86/kernel/irq.c | 6 +++---
|
|
|
|
5 files changed, 9 insertions(+), 9 deletions(-)
|
|
|
|
|
2012-05-12 14:20:55 +00:00
|
|
|
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
|
|
|
|
index f98d84c..2cd2d93 100644
|
|
|
|
--- a/arch/x86/kernel/apic/apic.c
|
|
|
|
+++ b/arch/x86/kernel/apic/apic.c
|
|
|
|
@@ -876,8 +876,8 @@ void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
|
2011-11-20 00:01:55 +00:00
|
|
|
* Besides, if we don't timer interrupts ignore the global
|
|
|
|
* interrupt lock, which is the WrongThing (tm) to do.
|
|
|
|
*/
|
|
|
|
- exit_idle();
|
|
|
|
irq_enter();
|
|
|
|
+ exit_idle();
|
|
|
|
local_apic_timer_interrupt();
|
|
|
|
irq_exit();
|
|
|
|
|
2012-05-12 14:20:55 +00:00
|
|
|
@@ -1809,8 +1809,8 @@ void smp_spurious_interrupt(struct pt_regs *regs)
|
2011-11-20 00:01:55 +00:00
|
|
|
{
|
|
|
|
u32 v;
|
|
|
|
|
|
|
|
- exit_idle();
|
|
|
|
irq_enter();
|
|
|
|
+ exit_idle();
|
|
|
|
/*
|
|
|
|
* Check if this really is a spurious interrupt and ACK it
|
|
|
|
* if it is a vectored one. Just in case...
|
2012-05-12 14:20:55 +00:00
|
|
|
@@ -1846,8 +1846,8 @@ void smp_error_interrupt(struct pt_regs *regs)
|
2011-11-20 00:01:55 +00:00
|
|
|
"Illegal register address", /* APIC Error Bit 7 */
|
|
|
|
};
|
|
|
|
|
|
|
|
- exit_idle();
|
|
|
|
irq_enter();
|
|
|
|
+ exit_idle();
|
|
|
|
/* First tickle the hardware, only then report what went on. -- REW */
|
|
|
|
v0 = apic_read(APIC_ESR);
|
|
|
|
apic_write(APIC_ESR, 0);
|
2012-05-12 14:20:55 +00:00
|
|
|
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
|
|
|
|
index 6d939d7..8980555 100644
|
|
|
|
--- a/arch/x86/kernel/apic/io_apic.c
|
|
|
|
+++ b/arch/x86/kernel/apic/io_apic.c
|
|
|
|
@@ -2421,8 +2421,8 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
|
2011-11-20 00:01:55 +00:00
|
|
|
unsigned vector, me;
|
|
|
|
|
|
|
|
ack_APIC_irq();
|
|
|
|
- exit_idle();
|
|
|
|
irq_enter();
|
|
|
|
+ exit_idle();
|
|
|
|
|
|
|
|
me = smp_processor_id();
|
|
|
|
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
|
2012-05-12 14:20:55 +00:00
|
|
|
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
|
|
|
|
index 787e06c..ce21561 100644
|
|
|
|
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
|
|
|
|
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
|
|
|
|
@@ -397,8 +397,8 @@ static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt;
|
2011-11-20 00:01:55 +00:00
|
|
|
|
|
|
|
asmlinkage void smp_thermal_interrupt(struct pt_regs *regs)
|
|
|
|
{
|
|
|
|
- exit_idle();
|
|
|
|
irq_enter();
|
|
|
|
+ exit_idle();
|
|
|
|
inc_irq_stat(irq_thermal_count);
|
|
|
|
smp_thermal_vector();
|
|
|
|
irq_exit();
|
2012-05-12 14:20:55 +00:00
|
|
|
diff --git a/arch/x86/kernel/cpu/mcheck/threshold.c b/arch/x86/kernel/cpu/mcheck/threshold.c
|
|
|
|
index d746df2..aa578ca 100644
|
|
|
|
--- a/arch/x86/kernel/cpu/mcheck/threshold.c
|
|
|
|
+++ b/arch/x86/kernel/cpu/mcheck/threshold.c
|
|
|
|
@@ -19,8 +19,8 @@ void (*mce_threshold_vector)(void) = default_threshold_interrupt;
|
2011-11-20 00:01:55 +00:00
|
|
|
|
|
|
|
asmlinkage void smp_threshold_interrupt(void)
|
|
|
|
{
|
|
|
|
- exit_idle();
|
|
|
|
irq_enter();
|
|
|
|
+ exit_idle();
|
|
|
|
inc_irq_stat(irq_threshold_count);
|
|
|
|
mce_threshold_vector();
|
|
|
|
irq_exit();
|
2012-05-12 14:20:55 +00:00
|
|
|
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
|
|
|
|
index 429e0c9..5d31e5b 100644
|
|
|
|
--- a/arch/x86/kernel/irq.c
|
|
|
|
+++ b/arch/x86/kernel/irq.c
|
|
|
|
@@ -181,8 +181,8 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
|
2011-11-20 00:01:55 +00:00
|
|
|
unsigned vector = ~regs->orig_ax;
|
|
|
|
unsigned irq;
|
|
|
|
|
|
|
|
- exit_idle();
|
|
|
|
irq_enter();
|
|
|
|
+ exit_idle();
|
|
|
|
|
|
|
|
irq = __this_cpu_read(vector_irq[vector]);
|
|
|
|
|
2012-05-12 14:20:55 +00:00
|
|
|
@@ -209,10 +209,10 @@ void smp_x86_platform_ipi(struct pt_regs *regs)
|
2011-11-20 00:01:55 +00:00
|
|
|
|
|
|
|
ack_APIC_irq();
|
|
|
|
|
|
|
|
- exit_idle();
|
|
|
|
-
|
|
|
|
irq_enter();
|
|
|
|
|
|
|
|
+ exit_idle();
|
|
|
|
+
|
|
|
|
inc_irq_stat(x86_platform_ipis);
|
|
|
|
|
|
|
|
if (x86_platform_ipi_callback)
|
2012-05-12 14:20:55 +00:00
|
|
|
--
|
|
|
|
1.7.10
|
|
|
|
|