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);




Reply via email to