patch-2.4.0-test2 linux/arch/i386/kernel/io_apic.c

Next file: linux/arch/i386/kernel/microcode.c
Previous file: linux/arch/i386/kernel/i8259.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test1/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
@@ -175,8 +175,6 @@
 
 static int __init ioapic_setup(char *str)
 {
-	extern int skip_ioapic_setup;	/* defined in arch/i386/kernel/smp.c */
-
 	skip_ioapic_setup = 1;
 	return 1;
 }
@@ -658,8 +656,6 @@
 	/* mask LVT0 */
 	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
 
-	init_8259A(1);
-
 	/*
 	 * We use logical delivery to get the timer IRQ
 	 * to the first CPU.
@@ -907,24 +903,27 @@
 
 void /*__init*/ print_PIC(void)
 {
+	extern spinlock_t i8259A_lock;
 	unsigned int v, flags;
 
 	printk(KERN_DEBUG "\nprinting PIC contents\n");
 
+	spin_lock_irqsave(&i8259A_lock, flags);
+
 	v = inb(0xa1) << 8 | inb(0x21);
 	printk(KERN_DEBUG "... PIC  IMR: %04x\n", v);
 
 	v = inb(0xa0) << 8 | inb(0x20);
 	printk(KERN_DEBUG "... PIC  IRR: %04x\n", v);
 
-	__save_flags(flags);
-	__cli();
 	outb(0x0b,0xa0);
 	outb(0x0b,0x20);
 	v = inb(0xa0) << 8 | inb(0x20);
 	outb(0x0a,0xa0);
 	outb(0x0a,0x20);
-	__restore_flags(flags);
+
+	spin_unlock_irqrestore(&i8259A_lock, flags);
+
 	printk(KERN_DEBUG "... PIC  ISR: %04x\n", v);
 
 	v = inb(0x4d1) << 8 | inb(0x4d0);
@@ -991,6 +990,14 @@
 		/* Read the register 0 value */
 		*(int *)&reg_00 = io_apic_read(apic, 0);
 		
+		if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
+				apic, mp_ioapics[apic].mpc_apicid);
+			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
+				reg_00.ID);
+			mp_ioapics[apic].mpc_apicid = reg_00.ID;
+		}
+
 		/*
 		 * Read the right value from the MPC table and
 		 * write it into the ID register.
@@ -1295,6 +1302,7 @@
  */
 static inline void check_timer(void)
 {
+	extern int timer_ack;
 	int pin1, pin2;
 	int vector;
 
@@ -1305,6 +1313,18 @@
 	vector = assign_irq_vector(0);
 	set_intr_gate(vector, interrupt[0]);
 
+	/*
+	 * Subtle, code in do_timer_interrupt() expects an AEOI
+	 * mode for the 8259A whenever interrupts are routed
+	 * through I/O APICs.  Also IRQ0 has to be enabled in
+	 * the 8259A which implies the virtual wire has to be
+	 * disabled in the local APIC.
+	 */
+	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
+	init_8259A(1);
+	timer_ack = 1;
+	enable_8259A_irq(0);
+
 	pin1 = find_timer_pin(mp_INT);
 	pin2 = find_timer_pin(mp_ExtINT);
 
@@ -1318,7 +1338,6 @@
 		if (timer_irq_works()) {
 			if (nmi_watchdog) {
 				disable_8259A_irq(0);
-				init_8259A(1);
 				setup_nmi();
 				enable_8259A_irq(0);
 				nmi_irq_works();
@@ -1360,7 +1379,6 @@
 
 	disable_8259A_irq(0);
 	irq_desc[0].handler = &lapic_irq_type;
-	init_8259A(1);						/* AEOI mode */
 	apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);	/* Fixed mode */
 	enable_8259A_irq(0);
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)