Re: IO-APIC + timer doesn't work

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

 



Please check the revised patch

YH
[PATCH] x86_64: check_timer with io apic setup before try_apic_pin

add io apic setup before try_apic_pin for check_timer

also add remove_irq_to_pin call in io_apic.c

cc: Andi Kleen <[email protected]>
cc: Eric W. Biederman <[email protected]>
Signed-off-by: Yinghai Lu <[email protected]>

diff --git a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
index 017fddb..1ddfd4d 100644
--- a/include/asm-x86_64/mpspec.h
+++ b/include/asm-x86_64/mpspec.h
@@ -165,6 +165,7 @@ extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 extern unsigned int boot_cpu_physical_apicid;
 extern int smp_found_config;
 extern void find_smp_config (void);
+extern int add_irq_entry (int type, int irqflag, int bus, int irq, int apic, int pin);
 extern void get_smp_config (void);
 extern int nr_ioapics;
 extern unsigned char apic_version [MAX_APICS];
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 0807256..a054798 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -314,6 +314,34 @@ static int __init ELCR_trigger(unsigned int irq)
 	return (inb(port) >> (irq & 7)) & 1;
 }
 
+int add_irq_entry(int type, int irqflag, int bus, int irq, int apic, int pin)
+{
+        struct mpc_config_intsrc intsrc;
+	int idx;
+
+        intsrc.mpc_type = MP_INTSRC;
+        intsrc.mpc_irqflag = irqflag; /* conforming */
+        intsrc.mpc_srcbus = bus;
+        intsrc.mpc_dstapic = (apic != -1) ? mp_ioapics[apic].mpc_apicid: MP_APIC_ALL;
+
+        intsrc.mpc_irqtype = type;
+
+        intsrc.mpc_srcbusirq = irq;
+        intsrc.mpc_dstirq = pin;
+
+        mp_irqs [mp_irq_entries] = intsrc;
+        Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
+                " IRQ %02x, APIC ID %x, APIC INT %02x\n",
+                        intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
+                        (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
+                        intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
+        idx = mp_irq_entries;
+	if (++mp_irq_entries >= MAX_IRQ_SOURCES)
+                panic("Max # of irq sources exceeded!!\n");
+	return idx;
+
+}
+
 static void __init construct_default_ioirq_mptable(int mpc_default_type)
 {
 	struct mpc_config_intsrc intsrc;
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 2a1dcd5..ad1a28a 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -273,10 +273,17 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
 	struct irq_pin_list *entry = irq_2_pin + irq;
 
 	BUG_ON(irq >= NR_IRQS);
-	while (entry->next)
+	while (entry->next) {
+		if (entry->apic == apic && entry->pin == pin) 
+			return;
+		if (entry->pin == -1) 
+			break;
 		entry = irq_2_pin + entry->next;
+	}
 
 	if (entry->pin != -1) {
+		if (entry->apic == apic && entry->pin == pin) 
+			return;
 		entry->next = first_free_entry;
 		entry = irq_2_pin + entry->next;
 		if (++first_free_entry >= PIN_MAP_SIZE)
@@ -286,6 +293,39 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
 	entry->pin = pin;
 }
 
+static void remove_pin_to_irq(unsigned int irq, int apic, int pin)
+{
+	struct irq_pin_list *entry = irq_2_pin + irq;
+	struct irq_pin_list *pri;
+	struct irq_pin_list *next;
+
+	BUG_ON(irq >= NR_IRQS);
+
+	for (;;) {
+		if (entry->apic == apic && entry->pin == pin) {
+			if(entry->next) {
+				next = irq_2_pin + entry->next;
+				entry->apic = next->apic;
+				entry->pin = next->pin;
+				entry->next = next->next;
+				next->apic = -1;
+				next->pin = -1;
+				next->next = 0;
+			} else {
+				entry->apic = -1;
+				entry->pin = -1;
+			}
+			return;
+		}
+		pri = entry;
+		if (pri->next) 
+			entry = irq_2_pin + pri->next;
+		else
+			break;
+	} 
+
+}
+
 
 #define DO_ACTION(name,R,ACTION, FINAL)					\
 									\
@@ -1570,6 +1610,22 @@ static inline void unlock_ExtINT_logic(void)
  * fanatically on his truly buggy board.
  */
 
+static void set_try_apic_pin(int apic, int pin, int type)
+{
+	int idx;
+	int irq = 0;
+	int bus = 0; /* MP_ISA_BUS */
+	int irqflag = 5; /* MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH */
+
+	idx = find_irq_entry(apic,pin,type);
+
+	if (idx == -1) 
+		idx = add_irq_entry(type, irqflag, bus, irq, apic, pin);
+
+	add_pin_to_irq(irq, apic, pin);
+	setup_IO_APIC_irq(apic, pin, idx, irq);
+}
+
 static int try_apic_pin(int apic, int pin, char *msg)
 {
 	apic_printk(APIC_VERBOSE, KERN_INFO
@@ -1588,7 +1644,7 @@ static int try_apic_pin(int apic, int pin, char *msg)
 		}
 		return 1;
 	}
-	clear_IO_APIC_pin(apic, pin);
+
 	apic_printk(APIC_QUIET, KERN_ERR " .. failed\n");
 	return 0;
 }
@@ -1599,6 +1655,7 @@ static void check_timer(void)
 	int apic1, pin1, apic2, pin2;
 	int vector;
 	cpumask_t mask;
+	int i;
 
 	/*
 	 * get/set the timer IRQ vector:
@@ -1621,33 +1678,51 @@ static void check_timer(void)
 	pin2  = ioapic_i8259.pin;
 	apic2 = ioapic_i8259.apic;
 
-	/* Do this first, otherwise we get double interrupts on ATI boards */
-	if ((pin1 != -1) && try_apic_pin(apic1, pin1,"with 8259 IRQ0 disabled"))
-		return;
+	apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
+		vector, apic1, pin1, apic2, pin2);
 
-	/* Now try again with IRQ0 8259A enabled.
-	   Assumes timer is on IO-APIC 0 ?!? */
-	enable_8259A_irq(0);
-	unmask_IO_APIC_irq(0);
-	if (try_apic_pin(apic1, pin1, "with 8259 IRQ0 enabled"))
-		return;
-	disable_8259A_irq(0);
+	if (pin1 != -1) {
+		/* Do this first, otherwise we get double interrupts on ATI boards */
+		/* set_try_apic_pin will call disable_8259A_irq */
+		set_try_apic_pin(apic1, pin1, mp_INT);
+		unmask_IO_APIC_irq(0);
+		if (try_apic_pin(apic1, pin1,"with 8259 IRQ0 disabled"))
+			return;
 
-	/* Always try pin0 and pin2 on APIC 0 to handle buggy timer overrides
-	   on Nvidia boards */
-	if (!(apic1 == 0 && pin1 == 0) &&
-	    try_apic_pin(0, 0, "fallback with 8259 IRQ0 disabled"))
-		return;
-	if (!(apic1 == 0 && pin1 == 2) &&
-	    try_apic_pin(0, 2, "fallback with 8259 IRQ0 disabled"))
-		return;
+		/* Now try again with IRQ0 8259A enabled.
+		   Assumes timer is on IO-APIC 0 ?!? */
+		enable_8259A_irq(0);
+		if (try_apic_pin(apic1, pin1, "with 8259 IRQ0 enabled"))
+			return;
+		disable_8259A_irq(0);
+
+    	        clear_IO_APIC_pin(apic1, pin1);
+		remove_pin_to_irq(0, apic1, pin1);
+	}
 
 	/* Then try pure 8259A routing on the 8259 as reported by BIOS*/
-	enable_8259A_irq(0);
 	if (pin2 != -1) {
 		setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
+		add_pin_to_irq(0, apic2, pin2);
+		enable_8259A_irq(0);
 		if (try_apic_pin(apic2,pin2,"8259A broadcast ExtINT from BIOS"))
 			return;
+		clear_IO_APIC_pin(apic2, pin2);
+		remove_pin_to_irq(0, apic2, pin2);
+	}
+
+	/* Always try pin0 and pin2 on APIC 0 to handle buggy timer overrides
+	   on Nvidia boards */
+	for (i = 0; i <= 2; i += 2) 
+	if (!(apic1 == 0 && pin1 == i)) {
+		/* set_try_apic_pin will call disable_8259A_irq */
+		set_try_apic_pin(0, i, mp_INT); 
+		unmask_IO_APIC_irq(0);
+		if (try_apic_pin(0, i, "fallback with 8259 IRQ0 disabled"))
+			return;
+
+		clear_IO_APIC_pin(0, i);
+		remove_pin_to_irq(0, 0, i);
 	}
 
 	/* Tried all possibilities to go through the IO-APIC. Now come the

[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