Commit 344fd4e1 authored by Randy Dunlap's avatar Randy Dunlap Committed by Linus Torvalds

[PATCH] unexpected IO-APIC update

Recently there has been a rash of Unexpected IO APIC reports on the
linux-smp mailing list.  Most of the most recent ones are due to some
newer Intel chipsets (865, 875).

The IO APIC Version register doesn't indicate the differences in these
IO APICs.

I have an patch that addresses these chipsets.  It has been tested by a
few people with good results and has been blessed by Maciej Rozycki.

Other than conditionally decoding IO APIC registers 2 and 3, we could
alternately ignore them since Linux doesn't use the values for anything
other than printing them.

This patch ignores IO APIC register 2 if it's the same value as IO APIC
register 1.  It also reads IO APIC register 3 if the IO APIC version is
>= 0x20, but some chipsets don't support this register, so it is also
ignored if its value if the same as IO APIC register 1 or 2.

Another possible(?) alternative is to read the PID/VID of the device to
determine which registers it supports.  However, PCI devices have not
been scanned at this point in init, so it would require scanning PCI
config space directly and I don't yet see the point of doing that.

Oh, and the UNEXPECTED_IO_APIC() function doesn't print anything in
2.5.current and I didn't change that.
parent b6c7f357
...@@ -1275,6 +1275,7 @@ void __init print_IO_APIC(void) ...@@ -1275,6 +1275,7 @@ void __init print_IO_APIC(void)
struct IO_APIC_reg_00 reg_00; struct IO_APIC_reg_00 reg_00;
struct IO_APIC_reg_01 reg_01; struct IO_APIC_reg_01 reg_01;
struct IO_APIC_reg_02 reg_02; struct IO_APIC_reg_02 reg_02;
struct IO_APIC_reg_03 reg_03;
unsigned long flags; unsigned long flags;
printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
...@@ -1295,6 +1296,8 @@ void __init print_IO_APIC(void) ...@@ -1295,6 +1296,8 @@ void __init print_IO_APIC(void)
*(int *)&reg_01 = io_apic_read(apic, 1); *(int *)&reg_01 = io_apic_read(apic, 1);
if (reg_01.version >= 0x10) if (reg_01.version >= 0x10)
*(int *)&reg_02 = io_apic_read(apic, 2); *(int *)&reg_02 = io_apic_read(apic, 2);
if (reg_01.version >= 0x20)
*(int *)&reg_03 = io_apic_read(apic, 3);
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
printk("\n"); printk("\n");
...@@ -1332,13 +1335,31 @@ void __init print_IO_APIC(void) ...@@ -1332,13 +1335,31 @@ void __init print_IO_APIC(void)
if (reg_01.__reserved_1 || reg_01.__reserved_2) if (reg_01.__reserved_1 || reg_01.__reserved_2)
UNEXPECTED_IO_APIC(); UNEXPECTED_IO_APIC();
if (reg_01.version >= 0x10) { /*
* Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
* but the value of reg_02 is read as the previous read register
* value, so ignore it if reg_02 == reg_01.
*/
if (reg_01.version >= 0x10 && *(int *)&reg_02 != *(int *)&reg_01) {
printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)&reg_02); printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)&reg_02);
printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.arbitration); printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.arbitration);
if (reg_02.__reserved_1 || reg_02.__reserved_2) if (reg_02.__reserved_1 || reg_02.__reserved_2)
UNEXPECTED_IO_APIC(); UNEXPECTED_IO_APIC();
} }
/*
* Some Intel chipsets with IO APIC VERSION of 0x2? don't have reg_02
* or reg_03, but the value of reg_0[23] is read as the previous read
* register value, so ignore it if reg_03 == reg_0[12].
*/
if (reg_01.version >= 0x20 && *(int *)&reg_03 != *(int *)&reg_02 &&
*(int *)&reg_03 != *(int *)&reg_01) {
printk(KERN_DEBUG ".... register #03: %08X\n", *(int *)&reg_03);
printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.boot_DT);
if (reg_03.__reserved_1)
UNEXPECTED_IO_APIC();
}
printk(KERN_DEBUG ".... IRQ redirection table:\n"); printk(KERN_DEBUG ".... IRQ redirection table:\n");
printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol" printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
......
...@@ -44,6 +44,11 @@ struct IO_APIC_reg_02 { ...@@ -44,6 +44,11 @@ struct IO_APIC_reg_02 {
__reserved_1 : 4; __reserved_1 : 4;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct IO_APIC_reg_03 {
__u32 boot_DT : 1,
__reserved_1 : 31;
} __attribute__ ((packed));
/* /*
* # of IO-APICs and # of IRQ routing registers * # of IO-APICs and # of IRQ routing registers
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment