Hi Ingo, Martin and the rest of the Gang,
Before I send this to Linus I would be honoured if you could spare a few
minutes to cast your eye over this small patch. It adds a few lines to
arch/i386/kernel/bios32.c/pcibios_fixup_devices() to help it avoid falling
into the trap of assigning IRQ to a PCI device that corresponds to an IO
APIC pin which is not connected. This (as discussed with Ingo earlier) can
happen if the device lies behind a P2P bridge on a bus unlucky enough not
to have its own bus entry in MP table.
What we do here is map the pin of our device + device number to the pin
on the bridge by "swizzling" in accordance with PCI-PCI bridge spec 1.0:
bridge_pin = (device_pin + device_num) %4
(all pins are understood in IO APIC sense, not PCI sense, so we start from
0, not 1)
Then we get the IRQ corresponding to (bridge_pin, bridge_devicenum) pair
based on MP table (IO_APIC_get_PCI_irq_vector() function).
The if(dev->bus->parent) is to avoid panicing in the case where device in
question is not in fact behind any bridge.
If we do succeed we print a KERN_WARNING saying that information was
obtained through a bridge.
I think the above is enough explanation for a small patch like this...
Also, I would be interested to hear comments from people who have cards
with such bridges that contain devices supported by Linux. In my case, the
device is, unfortunately, Compaq SMART-2/P RAID controller, not (yet) supported
by Linux so the calculations can only be verified theoretically.
Waiting for your comments,
Tigran
--- linux/arch/i386/kernel/bios32.c Sat Sep 26 17:34:49 1998
+++ linux-2.1.125.mine/arch/i386/kernel/bios32.c Thu Oct 22 13:30:25 1998
@@ -1063,6 +1063,16 @@
if (pin) {
pin--; /* interrupt pins are numbered
starting from 1 */
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
PCI_SLOT(dev->devfn), pin);
+ if (irq < 0 && dev->bus->parent) { /* go back to the
+bridge */
+ struct pci_dev * bridge = dev->bus->self;
+
+ pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+ irq =
+IO_APIC_get_PCI_irq_vector(bridge->bus->number,
+ PCI_SLOT(bridge->devfn), pin);
+ if (irq >= 0)
+ printk(KERN_WARNING "PCI: using
+PPB(B%d,I%d,P%d) to get irq %d\n",
+ bridge->bus->number,
+PCI_SLOT(bridge->devfn), pin, irq);
+ }
if (irq >= 0) {
printk("PCI->APIC IRQ transform: (B%d,I%d,P%d)
-> %d\n",
dev->bus->number,
PCI_SLOT(dev->devfn), pin, irq);