Re: clock runs at double speed on x86_64 system w/ATI RS200 chipset

From: Christopher Allen Wing
Date: Wed Apr 06 2005 - 15:41:37 EST


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@xxxxxxxxxxxxxxx



--- 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@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/