Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: Call idle notifier after irq_enter()

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 irq_enter() -> rcu_idle_exit() to be called before
doing so otherwise this results in a grumpy RCU:

[ 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

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
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>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>

authored by

Frederic Weisbecker and committed by
Paul E. McKenney
98ad1cc1 e37e112d

+9 -9
+3 -3
arch/x86/kernel/apic/apic.c
··· 876 876 * Besides, if we don't timer interrupts ignore the global 877 877 * interrupt lock, which is the WrongThing (tm) to do. 878 878 */ 879 - exit_idle(); 880 879 irq_enter(); 880 + exit_idle(); 881 881 local_apic_timer_interrupt(); 882 882 irq_exit(); 883 883 ··· 1809 1809 { 1810 1810 u32 v; 1811 1811 1812 - exit_idle(); 1813 1812 irq_enter(); 1813 + exit_idle(); 1814 1814 /* 1815 1815 * Check if this really is a spurious interrupt and ACK it 1816 1816 * if it is a vectored one. Just in case... ··· 1846 1846 "Illegal register address", /* APIC Error Bit 7 */ 1847 1847 }; 1848 1848 1849 - exit_idle(); 1850 1849 irq_enter(); 1850 + exit_idle(); 1851 1851 /* First tickle the hardware, only then report what went on. -- REW */ 1852 1852 v0 = apic_read(APIC_ESR); 1853 1853 apic_write(APIC_ESR, 0);
+1 -1
arch/x86/kernel/apic/io_apic.c
··· 2421 2421 unsigned vector, me; 2422 2422 2423 2423 ack_APIC_irq(); 2424 - exit_idle(); 2425 2424 irq_enter(); 2425 + exit_idle(); 2426 2426 2427 2427 me = smp_processor_id(); 2428 2428 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
+1 -1
arch/x86/kernel/cpu/mcheck/therm_throt.c
··· 397 397 398 398 asmlinkage void smp_thermal_interrupt(struct pt_regs *regs) 399 399 { 400 - exit_idle(); 401 400 irq_enter(); 401 + exit_idle(); 402 402 inc_irq_stat(irq_thermal_count); 403 403 smp_thermal_vector(); 404 404 irq_exit();
+1 -1
arch/x86/kernel/cpu/mcheck/threshold.c
··· 19 19 20 20 asmlinkage void smp_threshold_interrupt(void) 21 21 { 22 - exit_idle(); 23 22 irq_enter(); 23 + exit_idle(); 24 24 inc_irq_stat(irq_threshold_count); 25 25 mce_threshold_vector(); 26 26 irq_exit();
+3 -3
arch/x86/kernel/irq.c
··· 181 181 unsigned vector = ~regs->orig_ax; 182 182 unsigned irq; 183 183 184 - exit_idle(); 185 184 irq_enter(); 185 + exit_idle(); 186 186 187 187 irq = __this_cpu_read(vector_irq[vector]); 188 188 ··· 209 209 210 210 ack_APIC_irq(); 211 211 212 - exit_idle(); 213 - 214 212 irq_enter(); 213 + 214 + exit_idle(); 215 215 216 216 inc_irq_stat(x86_platform_ipis); 217 217