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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
[email protected]



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

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux