On Wednesday 14 April 2004 11:02, Len Brown wrote: > Re: IRQ0 XT-PIC timer issue > > Since the hardware is connected to APIC pin0, it is a BIOS bug > that an ACPI interrupt source override from pin2 to IRQ0 exists. > > With this simple 2.6.5 patch you can specify "acpi_skip_timer_override" > to ignore that bogus BIOS directive. The result is with your > ACPI-enabled APIC-enabled kernel, you'll get IRQ0 IO-APIC-edge timer. > > Probably there is a more clever way to trigger this workaround > automatcially instead of via boot parameter. > > cheers, > -Len > > ===== Documentation/kernel-parameters.txt 1.44 vs edited ===== > --- 1.44/Documentation/kernel-parameters.txt Mon Mar 22 16:03:22 2004 > +++ edited/Documentation/kernel-parameters.txt Tue Apr 13 17:47:11 2004 > @@ -122,6 +122,10 @@ > > acpi_serialize [HW,ACPI] force serialization of AML methods > > + acpi_skip_timer_override [HW,ACPI]] > + Recognize IRQ0/pin2 Interrupt Source Override > + and ignore it -- for broken nForce2 BIOS. > + > ad1816= [HW,OSS] > Format: ,,, > See also Documentation/sound/oss/AD1816. > ===== arch/i386/kernel/setup.c 1.115 vs edited ===== > --- 1.115/arch/i386/kernel/setup.c Fri Apr 2 07:21:43 2004 > +++ edited/arch/i386/kernel/setup.c Tue Apr 13 17:41:31 2004 > @@ -614,6 +614,12 @@ > else if (!memcmp(from, "acpi_sci=low", 12)) > acpi_sci_flags.polarity = 3; > > + else if (!memcmp(from, "acpi_skip_timer_override", 24)) { > + extern int acpi_skip_timer_override; > + > + acpi_skip_timer_override = 1; > + } > + > #ifdef CONFIG_X86_LOCAL_APIC > /* disable IO-APIC */ > else if (!memcmp(from, "noapic", 6)) > ===== arch/i386/kernel/acpi/boot.c 1.57 vs edited ===== > --- 1.57/arch/i386/kernel/acpi/boot.c Tue Mar 30 17:05:19 2004 > +++ edited/arch/i386/kernel/acpi/boot.c Tue Apr 13 17:50:14 2004 > @@ -62,6 +62,7 @@ > > acpi_interrupt_flags acpi_sci_flags __initdata; > int acpi_sci_override_gsi __initdata; > +int acpi_skip_timer_override __initdata; > > #ifdef CONFIG_X86_LOCAL_APIC > static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; > @@ -327,6 +328,12 @@ > acpi_sci_ioapic_setup(intsrc->global_irq, > intsrc->flags.polarity, intsrc->flags.trigger); > return 0; > + } > + > + if (acpi_skip_timer_override && > + intsrc->bus_irq == 0 && intsrc->global_irq == 2) { > + printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n"); > + return 0; > } > > mp_override_legacy_irq ( > > > Hi Len, I have updated my nforce2 patches for 2.6.5 to work with your patch. I have tested them only on one nforce2 board Epox 8Rga+ but as little has changed in core functionality from past releases I think all will be OK.... Hopefully no clock skew. I saw none on my system but thats no guarantee. I tried your above patch with the timer_ack on as is default in 2.6.5 and nmi_watchdog=1 failed as expected. I still think Maciej's 8259 ack patch is more complete solution to the ack issue but this one gets watchdog going for nforce2. I cannot see anyone using your above patch without an integrated apic and tsc so I cannot see a problem triggering it off your kern arg. The second patch is the C1halt update I suggested in another posting. http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-04/1707.html Both patches in attached tarball. Regards Ross. Here is my revised patch for use with "acpi_skip_timer_override" to get nmi_debug=1 working with the above patch from Len Brown. --- linux-2.6.5/arch/i386/kernel/io_apic.c.orig 2004-04-16 00:20:54.000000000 +1000 +++ linux-2.6.5/arch/i386/kernel/io_apic.c 2004-04-15 20:24:18.000000000 +1000 @@ -2179,10 +2179,13 @@ static inline void check_timer(void) if (pin1 != -1) { /* * Ok, does IRQ0 through the IOAPIC work? */ + extern int acpi_skip_timer_override; + if(acpi_skip_timer_override) + timer_ack=0; unmask_IO_APIC_irq(0); if (timer_irq_works()) { if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); setup_nmi(); Here is my revised patch for "idle=C1halt" to prevent nforce2 hard lockups. Now more robust, better tested with apm config, and without x86 apic config, and nolapic, noapic, acpi=off. All gave my usual 38C CPU temp when idle and no hard lockups. Temp measured by leaving machine idle on run level 3 for several minutes and then reading bios temp on reboot. --- linux-2.6.5/arch/i386/kernel/process.c.orig 2004-04-04 13:36:10.000000000 +1000 +++ linux-2.6.5/arch/i386/kernel/process.c 2004-04-15 20:41:13.000000000 +1000 @@ -47,10 +47,13 @@ #include #include #ifdef CONFIG_MATH_EMULATION #include #endif +#if defined(CONFIG_X86_UP_APIC) +#include +#endif #include #include asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); @@ -98,10 +101,34 @@ void default_idle(void) local_irq_enable(); } } /* + * We use this to avoid nforce2 lockups + * Reduces frequency of C1 disconnects + */ +static void c1halt_idle(void) +{ + if (!hlt_counter && current_cpu_data.hlt_works_ok) { + local_irq_disable(); +#if defined(CONFIG_X86_UP_APIC) + /* only hlt disconnect if more than 1.6% of apic interval remains */ + extern int enable_local_apic; + if(!need_resched() && (enable_local_apic < 0 || + (apic_read(APIC_TMCCT) > (apic_read(APIC_TMICT)>>6)))) { +#else + /* just adds a little delay to assist in back to back disconnects */ + if(!need_resched()) { +#endif + ndelay(600); /* helps nforce2 but adds 0.6us hard int latency */ + safe_halt(); /* nothing better to do until we wake up */ + } else { + local_irq_enable(); + } + } +} +/* * On SMP it's slightly faster (but much more power-consuming!) * to poll the ->work.need_resched flag instead of waiting for the * cross-CPU IPI to arrive. Use this option with caution. */ static void poll_idle (void) @@ -135,20 +162,18 @@ static void poll_idle (void) * The idle thread. There's no useful work to be * done, so just try to conserve power and have a * low exit latency (ie sit in a loop waiting for * somebody to say that they'd like to reschedule) */ +static void (*idle)(void); void cpu_idle (void) { /* endless idle loop with no priority at all */ while (1) { while (!need_resched()) { - void (*idle)(void) = pm_idle; - if (!idle) - idle = default_idle; - + idle = pm_idle ? pm_idle : default_idle; irq_stat[smp_processor_id()].idle_timestamp = jiffies; idle(); } schedule(); } @@ -199,16 +224,18 @@ void __init select_idle_routine(const st static int __init idle_setup (char *str) { if (!strncmp(str, "poll", 4)) { printk("using polling idle threads.\n"); - pm_idle = poll_idle; + idle = poll_idle; } else if (!strncmp(str, "halt", 4)) { printk("using halt in idle threads.\n"); - pm_idle = default_idle; + idle = default_idle; + } else if (!strncmp(str, "C1halt", 6)) { + printk("using C1 halt disconnect friendly idle threads.\n"); + idle = c1halt_idle; } - return 1; } __setup("idle=", idle_setup);