Skip to content

Commit d4d25de

Browse files
Maciej W. RozyckiIngo Molnar
authored andcommitted
x86: fix NMI watchdog & 'stopped time' problem
More than 3 years ago Niclas Gustafsson reported a 'stopped time' problem: > Watching the /proc/interrupts with 10s apart after the "stop". > > [root@s151 root]# more /proc/interrupts > CPU0 > 0: 66413955 local-APIC-edge timer [...] > LOC: 67355837 > ERR: 0 > MIS: 0 > [root@s151 root]# more /proc/interrupts > CPU0 > 0: 66413955 local-APIC-edge timer [...] > LOC: 67379568 > ERR: 0 > MIS: 0 This may be because buggy SMM firmware messes with the 8259A (configured for a transparent mode -- yes that rare "local-APIC-edge" mode is tricky ;-) ) insanely. this should resolve: http://bugzilla.kernel.org/show_bug.cgi?id=2544 http://bugzilla.kernel.org/show_bug.cgi?id=6296 Patch-dusted-off-by: Ingo Molnar <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 2ffbb83 commit d4d25de

File tree

2 files changed

+17
-4
lines changed

2 files changed

+17
-4
lines changed

arch/x86/kernel/io_apic_32.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,10 @@ static inline void __init check_timer(void)
21662166
{
21672167
int apic1, pin1, apic2, pin2;
21682168
int vector;
2169+
unsigned int ver;
2170+
2171+
ver = apic_read(APIC_LVR);
2172+
ver = GET_APIC_VERSION(ver);
21692173

21702174
/*
21712175
* get/set the timer IRQ vector:
@@ -2179,11 +2183,15 @@ static inline void __init check_timer(void)
21792183
* mode for the 8259A whenever interrupts are routed
21802184
* through I/O APICs. Also IRQ0 has to be enabled in
21812185
* the 8259A which implies the virtual wire has to be
2182-
* disabled in the local APIC.
2186+
* disabled in the local APIC. Finally timer interrupts
2187+
* need to be acknowledged manually in the 8259A for
2188+
* timer_interrupt() and for the i82489DX when using
2189+
* the NMI watchdog.
21832190
*/
21842191
apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
21852192
init_8259A(1);
2186-
timer_ack = 1;
2193+
timer_ack = !cpu_has_tsc;
2194+
timer_ack |= (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver));
21872195
if (timer_over_8254 > 0)
21882196
enable_8259A_irq(0);
21892197

arch/x86/kernel/nmi_32.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <asm/smp.h>
2727
#include <asm/nmi.h>
28+
#include <asm/timer.h>
2829

2930
#include "mach_traps.h"
3031

@@ -83,7 +84,7 @@ static int __init check_nmi_watchdog(void)
8384

8485
prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
8586
if (!prev_nmi_count)
86-
return -1;
87+
goto error;
8788

8889
printk(KERN_INFO "Testing NMI watchdog ... ");
8990

@@ -117,7 +118,7 @@ static int __init check_nmi_watchdog(void)
117118
if (!atomic_read(&nmi_active)) {
118119
kfree(prev_nmi_count);
119120
atomic_set(&nmi_active, -1);
120-
return -1;
121+
goto error;
121122
}
122123
printk("OK.\n");
123124

@@ -128,6 +129,10 @@ static int __init check_nmi_watchdog(void)
128129

129130
kfree(prev_nmi_count);
130131
return 0;
132+
error:
133+
timer_ack = !cpu_has_tsc;
134+
135+
return -1;
131136
}
132137
/* This needs to happen later in boot so counters are working */
133138
late_initcall(check_nmi_watchdog);

0 commit comments

Comments
 (0)