Messages in this thread Patch in this message | | | Date | Wed, 6 Apr 2005 16:36:21 -0400 (EDT) | From | Christopher Allen Wing <> | Subject | Re: clock runs at double speed on x86_64 system w/ATI RS200 chipset |
| |
I noticed that the x86_64 kernel has 4 different ways of configuring the timer interrupt in APIC mode:
arch/x86_64/kernel/io_apic.c :
/* style 1 */ if (pin1 != -1) { /* * Ok, does IRQ0 through the IOAPIC work? */
/* style 2 */ apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); if (pin2 != -1) { apic_printk(APIC_VERBOSE,"\n..... (found pin %d) ...", pin2); /* * legacy devices should be connected to IO APIC #0 */
/* style 3 */ apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
/* style 4 */ apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ...");
I hacked the kernel with the following patch to try using all 4 timer configurations. (by overriding 'pin1' and 'pin2', and by bypassing the code that sets up 'Virtual Wire IRQ')
Unfortunately I wasn't able to change the behavior in any case. I couldn't get the last configuration ('trying to set up timer as ExtINT IRQ') to work; the machine just hung. I'm guessing that the code io_apic.c::unlock_ExtINT_logic() may have never been tested on AMD chips?
No matter what I did, the clock still ran at double normal speed. Perhaps we are just programming the APIC incorrectly for this board in some way?
booting with standard options (ACPI enabled, 'apic=debug'); this uses method 1: http://www-personal.engin.umich.edu/~wingc/apictimer/dmesg/dmesg-2.6.11.6-acpi-apicdebug http://www-personal.engin.umich.edu/~wingc/apictimer/dmesg/interrupts-2.6.11-6-acpi-apic
booting with 'force_apic_timer=-1,0 apic=debug' to force it to use method #2 to route the timer interrupt: http://www-personal.engin.umich.edu/~wingc/apictimer/dmesg/dmesg-2.6.11.6-acpi-apicdebug-forcetimer=-1,0 http://www-personal.engin.umich.edu/~wingc/apictimer/dmesg/interrupts-2.6.11-6-acpi-apic-forcetimer=-1,0
booting with 'force_apic_timer=-1,-1 apic=debug' to force it to use method #3: http://www-personal.engin.umich.edu/~wingc/apictimer/dmesg/dmesg-2.6.11.6-acpi-apicdebug-forcetimer=-1,-1 http://www-personal.engin.umich.edu/~wingc/apictimer/dmesg/interrupts-2.6.11-6-acpi-apic-forcetimer=-1,-1
(note that /proc/interrupts says 'local-APIC-edge' for timer interrupt, but it still receives twice as many interrupts)
booting with 'force_apic_timer=-1,-1 novwtimer apic=debug' to force it to use method #4:
(machine just hangs when trying to set up the timer)
-Chris wingc@engin.umich.edu
--- linux-2.6.11.6/arch/x86_64/kernel/io_apic.c.orig 2005-03-25 22:28:21.000000000 -0500 +++ linux-2.6.11.6/arch/x86_64/kernel/io_apic.c 2005-04-06 16:28:25.120441232 -0400 @@ -1564,6 +1564,10 @@ * is so screwy. Thanks to Brian Perkins for testing/hacking this beast * fanatically on his truly buggy board. */ +static int apic_timer_forced = 0; +static int force_pin1, force_pin2; +static int force_novwtimer = 0; + static inline void check_timer(void) { int pin1, pin2; @@ -1587,8 +1591,13 @@ init_8259A(1); enable_8259A_irq(0);
- pin1 = find_isa_irq_pin(0, mp_INT); - pin2 = find_isa_irq_pin(0, mp_ExtINT); + if (apic_timer_forced) { + pin1 = force_pin1; + pin2 = force_pin2; + } else { + pin1 = find_isa_irq_pin(0, mp_INT); + pin2 = find_isa_irq_pin(0, mp_ExtINT); + }
apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
@@ -1639,6 +1648,7 @@ nmi_watchdog = 0; }
+ if (!force_novwtimer) { apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
disable_8259A_irq(0); @@ -1652,6 +1662,7 @@ } apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); apic_printk(APIC_VERBOSE," failed.\n"); + }
apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ...");
@@ -1669,6 +1680,41 @@ panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); }
+static int __init force_apic_timer(char *str) +{ + int timer_irqs[3]; + + get_options(str, ARRAY_SIZE(timer_irqs), timer_irqs); + if (timer_irqs[0] != 2) { + printk(KERN_WARNING "force_apic_timer must specify pin1,pin2\n"); + goto out; + } + + apic_timer_forced = 1; + force_pin1 = timer_irqs[1]; + force_pin2 = timer_irqs[2]; + +out: + return 1; +} + +static int __init novwtimer(char *str) +{ + force_novwtimer = 1; + return 1; +} + +static int __init noirq(char *str) +{ + force_noirq = 1; + return 1; +} + +__setup("force_apic_timer=", force_apic_timer); +__setup("novwtimer", novwtimer); +__setup("noirq", noirq); + + /* * * IRQ's that are handled by the PIC in the MPS IOAPIC case. - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |