]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
PCI: Workaround invalid P2P bridge bus numbers
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 20 Oct 2008 23:06:29 +0000 (10:06 +1100)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Wed, 22 Oct 2008 23:42:44 +0000 (16:42 -0700)
Some firmware fail to properly configure P2P bridges, leaving them
with invalid bus numbers. In some cases, this happens on some embedded
4xx boards as the result of the kernel allocating different bus space
than the firmware does to host bridges while not setting
pcibios_assign_all_busses() for various reasons. In other cases, it can
just be bogus firmware.

This adds some sanity checking to the PCI probing code. If a bridge is
found whose primary bus number doesn't match the bus it's sitting on,
or whose secondary bus number not strictly above it's primary bus
number, then the bridge bus numbers are deconfigured in the first pass
of pci_scan_bridge() to be re-assigned in the second pass.

Tested-by: "Ayman El-Khashab" <AymanE@tanisys.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/pci/probe.c

index aaaf0a1fed223364b82bd4e79d9fd29f2c178788..6f1e51d77bce010b53ec7a4f55069fe6302ebf78 100644 (file)
@@ -480,19 +480,27 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
        int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
        u32 buses, i, j = 0;
        u16 bctl;
+       int broken = 0;
 
        pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
 
        dev_dbg(&dev->dev, "scanning behind bridge, config %06x, pass %d\n",
                buses & 0xffffff, pass);
 
+       /* Check if setup is sensible at all */
+       if (!pass &&
+           ((buses & 0xff) != bus->number || ((buses >> 8) & 0xff) <= bus->number)) {
+               dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");
+               broken = 1;
+       }
+
        /* Disable MasterAbortMode during probing to avoid reporting
           of bus errors (in some architectures) */ 
        pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
        pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
                              bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
 
-       if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) {
+       if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus && !broken) {
                unsigned int cmax, busnr;
                /*
                 * Bus already configured by firmware, process it in the first
@@ -530,7 +538,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
                 * do in the second pass.
                 */
                if (!pass) {
-                       if (pcibios_assign_all_busses())
+                       if (pcibios_assign_all_busses() || broken)
                                /* Temporarily disable forwarding of the
                                   configuration cycles on all bridges in
                                   this bus segment to avoid possible