Updated Lockup Patches, 2.4.22 - 23 Nforce2, apic timer ack delay, ioapic edge for NMI debug

From: Ross Dickson
Date: Sun Dec 21 2003 - 23:39:00 EST


Here are my patches reworked for 2.4.22.
They should patch on 2.4.23 but differ in line numbers.

I use them on my patched 2.4.23 kern.

Details are in following lkml thread, please refer to it prior to usage.

Updated Lockup Patches, 2.6.0 Nforce2, apic timer ack delay, ioapic edge for NMI debug

If not subscribed it can be found in many archives
such as
http://linux.derkeiler.com/Mailing-Lists/Kernel/2003-12/4525.html
or here
http://lkml.org/lkml/2003/12/21/7

Regards,
Ross Dickson

local apic timer ack delay:
--- CUT HERE ---
--- linux-2.4.22/arch/i386/kernel/apic.c 2003-06-14 00:51:29.000000000 +1000
+++ linux-2.4.22-rd/arch/i386/kernel/apic.c 2003-12-22 13:18:08.000000000 +1000
@@ -1058,10 +1058,17 @@ inline void smp_local_timer_interrupt(st
* we can take more than 100K local irqs per second on a 100 MHz P5.
*/
}

/*
+ * Athlon nforce2 R.D.
+ * preset timer ack mode if desired
+ * e.g. static int apic_timerack = 2;
+*/
+static int apic_timerack;
+
+/*
* Local APIC timer interrupt. This is the most natural way for doing
* local interrupts, but local timer interrupts can be emulated by
* broadcast interrupts too. [in case the hw doesn't support APIC timers]
*
* [ if a single-CPU system runs an SMP kernel then we call the local
@@ -1077,10 +1084,54 @@ void smp_apic_timer_interrupt(struct pt_
* the NMI deadlock-detector uses this.
*/
apic_timer_irqs[cpu]++;

/*
+ * Athlon nforce2 timer ack delay. Ross Dickson.
+ * works around issue of hard lockups in code location
+ * where linux exposes underlying system timing fault?
+ * hopefully manufacturers will fix it soon.
+ * We leave C1 disconnect bit alone as bios/SMM wants?
+ */
+ if(apic_timerack) {
+ if(apic_timerack==1) {
+ /* v1 timer ack delay, inline delay version
+ * on AMDXP & nforce2 chipset we use at least 500ns
+ * try to scale delay time with cpu speed.
+ * safe all cpu cores?
+ */
+ ndelay((cpu_khz >> 12)+200); /* don't ack too soon or hard lockup */
+ } else {
+ static unsigned int passno, safecnt;
+ /* v2 timer ack delay, timeout version, more efficient
+ * on AMDXP & nforce2 chipset we need 800ns?
+ * from timer irq start to apic irq ack, read apic timer,
+ * may be unsafe for thoroughbred cores?
+ */
+ if(!passno) { /* calculate timing */
+ safecnt = apic_read(APIC_TMICT) -
+ ( (800UL * apic_read(APIC_TMICT) ) /
+ (1000000000UL/HZ) );
+ printk("..APIC TIMER ack delay, reload:%lu, safe:%u\n",
+ apic_read(APIC_TMICT), safecnt);
+ passno++;
+ }
+#if APIC_DEBUG
+ if(passno<12) {
+ unsigned int at1 = apic_read(APIC_TMCCT);
+ if( passno > 1 )
+ Dprintk("..APIC TIMER ack delay, predelay count:%u \n", at1 );
+ passno++;
+ }
+# endif
+ /* delay only if required */
+ while( apic_read(APIC_TMCCT) > safecnt )
+ ndelay(100);
+ }
+ }
+
+ /*
* NOTE! We'd better ACK the irq immediately,
* because timer handling can be slow.
*/
ack_APIC_irq();
/*
@@ -1145,10 +1196,28 @@ asmlinkage void smp_error_interrupt(void
printk (KERN_ERR "APIC error on CPU%d: %02lx(%02lx)\n",
smp_processor_id(), v , v1);
}

/*
+* Athlon nforce2 timer ack delay. R.D.
+* kernel arg apic_tack=[012]
+* 0 off, 1 always delay, 2 timeout
+*/
+static int __init setup_apic_timerack(char *str)
+{
+ int tack;
+
+ get_option(&str, &tack);
+
+ if ( tack < 0 || tack > 2 )
+ return 0;
+ apic_timerack = tack;
+ return 1;
+}
+__setup("apic_tack=", setup_apic_timerack);
+
+/*
* This initializes the IO-APIC and APIC hardware if this is
* a UP kernel.
*/
int __init APIC_init_uniprocessor (void)
{
--- CUT HERE ---

io-apic edge:
--- CUT HERE ---
--- linux-2.4.22/arch/i386/kernel/io_apic.c 2003-08-25 21:44:39.000000000 +1000
+++ linux-2.4.22-rd/arch/i386/kernel/io_apic.c 2003-12-22 13:31:32.000000000 +1000
@@ -1612,12 +1612,56 @@ static inline void check_timer(void)
check_nmi_watchdog();
}
return;
}
clear_IO_APIC_pin(0, pin1);
- printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
+ printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC INTIN%d\n",pin1);
+ }
+
+#if defined(CONFIG_ACPI_BOOT) && defined(CONFIG_X86_UP_IOAPIC)
+ /* for nforce2 try vector 0 on pin0
+ * Note 8259a is already masked, also by default
+ * the io_apic_set_pci_routing call disables the 8259 irq 0
+ * so we must be connected directly to the 8254 timer if this works
+ * Note2: this violates the above comment re Subtle but works!
+ */
+ printk(KERN_INFO "..TIMER: Is timer irq0 connected to IO-APIC INTIN0? ...\n");
+ if (pin1 != -1) {
+ extern spinlock_t i8259A_lock;
+ unsigned long flags;
+ int tok, saved_timer_ack = timer_ack;
+ /*
+ * Ok, does IRQ0 through the IOAPIC work?
+ */
+ io_apic_set_pci_routing ( 0, 0, 0, 0, 0); /* connect pin */
+ unmask_IO_APIC_irq(0);
+ timer_ack = 0;
+
+ /*
+ * Ok, does IRQ0 through the IOAPIC work?
+ */
+ spin_lock_irqsave(&i8259A_lock, flags);
+ Dprintk("..TIMER 8259A ints disabled?, imr1:%02x, imr2:%02x\n", inb(0x21), inb(0xA1));
+ tok = timer_irq_works();
+ spin_unlock_irqrestore(&i8259A_lock, flags);
+ if (tok) {
+ if (nmi_watchdog == NMI_IO_APIC) {
+ disable_8259A_irq(0);
+ setup_nmi();
+ enable_8259A_irq(0);
+ check_nmi_watchdog();
+ }
+ printk(KERN_INFO "..TIMER: works OK on IO-APIC INTIN0 irq0\n" );
+ return;
+ }
+ /* failed */
+ timer_ack = saved_timer_ack;
+ clear_IO_APIC_pin(0, 0);
+ io_apic_set_pci_routing ( 0, pin1, 0, 0, 0);
+ printk(KERN_ERR "..MP-BIOS: 8254 timer not connected to IO-APIC INTIN0\n");
}
+#endif

printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
if (pin2 != -1) {
printk("\n..... (found pin %d) ...", pin2);
/*
--- CUT HERE ---

Attachment: nforce2-rd-v3-2.4.22-patches.tar.bz2
Description: application/tbz