This may actually be an MP BIOS bug...
According to the boot log, the MP table I/O Interrupt entry for the
USB controller (PCI device 00:0f:02) is:
Int: type 0, pol 3, trig 3, bus 0, IRQ 3c, APIC ID 5, APIC INT 00
Which specifies the destination APIC ID 5 (corresponding to the 2nd
IO-APIC, used solely to distribute PCI interrupts) and destination INT
pin 0. So when the IO-APICs are programmed this IRQ is remapped to:
PCI->APIC IRQ transform: (B0,I15,P0) -> 16
The problem is the USB Interrupt is internally routed and should use
the ISA IO-APIC for the destination APIC, and a valid ISA IRQ for the
destination INT. The MP table entry and corresponding IRQ transform
should look something like this:
[I used INT 09 simply because it wasn't already assigned...]
Int: type 0, pol 3, trig 3, bus 0, IRQ 3c, APIC ID 4, APIC INT 09
PCI->APIC IRQ transform: (B0,I15,P0) -> 9
Here's a patch to find & correct this entry on boot. Its not pretty,
and should ONLY be used to verify this particular fix--any real solution
will have to be done in the BIOS. (there doesn't seem to be an easy way
to alter specific MP table entries outside of the BIOS, especially if
they happen to exist in write-protected memory regions...)
There may be bogus data in the PIRQ table as well, which is why this
explicitly routes the interrupt & sets the ELCR. If you enable DEBUG
in pci-i386.h and re-send the dmesg output I will look it over.
-duncan
--- linux/arch/i386/kernel/mpparse.c Tue Nov 14 22:25:34 2000
+++ linux~/arch/i386/kernel/mpparse.c Tue Jan 16 17:11:07 2001
@@ -237,6 +237,37 @@
m->mpc_irqtype, m->mpc_irqflag & 3,
(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
+
+
if ((m->mpc_irqtype == 0) && ((m->mpc_irqflag & 3) == 3) &&
+
((m->mpc_irqflag >> 2) == 3) && (m->mpc_srcbus == 0) &&
+
(m->mpc_dstapic == 5) && (m->mpc_srcbusirq == 0x3c))
+
{
+
struct mpc_config_intsrc usbint = { MP_INTSRC,
+
0x00, 0x000f, 0x00,
+
0x3c, 0x04, 0x09 };
+
unsigned char mask = 1 << (usbint.mpc_dstirq & 7);
+
unsigned int port = 0x4d0 + (usbint.mpc_dstirq >> 3);
+
unsigned char val = inb(port);
+
+
Dprintk("MP BIOS bug, USB INT should use ISA IO-APIC!\n");
+
+
/* fix PIRQ routing entry: index 1 -> dstirq */
+
outb_p(1, 0xc00);
+
outb_p(usbint.mpc_dstirq, 0xc01);
+
if (!(val & mask))
+
outb(val|mask, port);
+
+
/* use modified intsrc struct */
+
mp_irqs[mp_irq_entries] = usbint;
+
+
Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
+
" IRQ %02x, APIC ID %x, APIC INT %02x\n",
+
usbint.mpc_irqtype, usbint.mpc_irqflag & 3,
+
(usbint.mpc_irqflag >> 2) & 3,
+
usbint.mpc_srcbus, usbint.mpc_srcbusirq,
+
usbint.mpc_dstapic, usbint.mpc_dstirq);
+
}
+
if (++mp_irq_entries == MAX_IRQ_SOURCES)
panic("Max # of irq sources exceeded!!\n");
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/