From: "Maciej W. Rozycki" <macro@ds2.pg.gda.pl>

Fix up the 8259 ack handling for buggy SMM firmware.

See http://www.ussg.iu.edu/hypermail/linux/kernel/0203.2/0956.html

Apparently the embedded 8259A-compatible core is not fully functional. 
This patch lets the I/O APIC-driven NMI watchdog to function correctly. 
Credit to Ross Dickson for discovering this.




---

 arch/i386/kernel/io_apic.c |   20 ++++++++++++++++----
 1 files changed, 16 insertions(+), 4 deletions(-)

diff -puN arch/i386/kernel/io_apic.c~8259-timer-ack-fix arch/i386/kernel/io_apic.c
--- 25/arch/i386/kernel/io_apic.c~8259-timer-ack-fix	2004-02-06 18:03:45.000000000 -0800
+++ 25-akpm/arch/i386/kernel/io_apic.c	2004-02-06 18:06:00.000000000 -0800
@@ -2155,6 +2155,10 @@ static inline void check_timer(void)
 {
 	int pin1, pin2;
 	int vector;
+	unsigned int ver;
+
+	ver = apic_read(APIC_LVR);
+	ver = GET_APIC_VERSION(ver);
 
 	/*
 	 * get/set the timer IRQ vector:
@@ -2168,11 +2172,17 @@ static inline void check_timer(void)
 	 * mode for the 8259A whenever interrupts are routed
 	 * through I/O APICs.  Also IRQ0 has to be enabled in
 	 * the 8259A which implies the virtual wire has to be
-	 * disabled in the local APIC.
+	 * disabled in the local APIC.  Finally timer interrupts
+	 * need to be acknowledged manually in the 8259A for
+	 * do_slow_timeoffset() and for the i82489DX when using
+	 * the NMI watchdog.
 	 */
 	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
 	init_8259A(1);
-	timer_ack = 1;
+	if (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver))
+		timer_ack = 1;
+	else
+		timer_ack = !cpu_has_tsc;
 	enable_8259A_irq(0);
 
 	pin1 = find_isa_irq_pin(0, mp_INT);
@@ -2190,7 +2200,8 @@ static inline void check_timer(void)
 				disable_8259A_irq(0);
 				setup_nmi();
 				enable_8259A_irq(0);
-				check_nmi_watchdog();
+				if (check_nmi_watchdog() < 0);
+					timer_ack = !cpu_has_tsc;
 			}
 			return;
 		}
@@ -2213,7 +2224,8 @@ static inline void check_timer(void)
 				add_pin_to_irq(0, 0, pin2);
 			if (nmi_watchdog == NMI_IO_APIC) {
 				setup_nmi();
-				check_nmi_watchdog();
+				if (check_nmi_watchdog() < 0);
+					timer_ack = !cpu_has_tsc;
 			}
 			return;
 		}

_