Is this the same issue we were having with Linux not being able to see bus 1?
Stefan
----- Forwarded message from Matthew Wilcox willy@debian.org -----
Date: Sun, 9 Nov 2003 23:09:38 +0000 Subject: Re: PROBLEM: sym53c8xx is broken on HP LH 4 after Linux 2.2
On Sun, Nov 09, 2003 at 11:51:36AM -0500, Doug Ledford wrote:
I can tell you what's going on here. This is a 450NX based motherboard. The 450NX chipset from Intel was the first chipset to have peer PCI busses. For backwards compatibility, some machine makers hacked their PCI BIOS to have a fake bridge device on PCI bus 0 that points to the same bus number as the peer bus. This way if the OS didn't know about the peer bus registers it would still find the devices by scanning behind the bridge.
[..]
In this case we are scanning behind this fake bridge and then also scanning based upon the peer bus registers in the chipset, and as a result we are finding the device twice. In order to fix this problem you need to change the peer bus quirk code for the 450NX chipset to scan the list of bus 0 devices looking for a bridge that has the same config as the peer bus registers and if so delete the bridge from the list. That will avoid double scanning and will avoid having the PCI code try and configure sub busses via a fake bridge when it should do all configurations via the 450NX peer bus registers.
Index: arch/i386/pci/fixup.c =================================================================== RCS file: /var/cvs/linux-2.6/arch/i386/pci/fixup.c,v retrieving revision 1.2 diff -u -p -r1.2 fixup.c --- arch/i386/pci/fixup.c 12 Aug 2003 19:10:49 -0000 1.2 +++ arch/i386/pci/fixup.c 9 Nov 2003 23:07:17 -0000 @@ -6,27 +6,52 @@ #include <linux/init.h> #include "pci.h"
+static void __devinit i450nx_scan_bus(struct pci_bus *parent, u8 busnr) +{ + struct list_head *tmp; + + pci_scan_bus(busnr, &pci_root_ops, NULL); + + list_for_each(tmp, &parent->children) { + u8 childnr; + struct pci_dev *dev = pci_dev_b(tmp); + + if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) + continue; + pci_read_config_byte(dev, PCI_PRIMARY_BUS, &childnr); + if (childnr != busnr) + continue; + + printk(KERN_WARNING "PCI: Removing fake PCI bridge %s\n", + pci_name(dev)); + pci_remove_bus_device(dev); + break; + } +}
static void __devinit pci_fixup_i450nx(struct pci_dev *d) { /* * i450NX -- Find and scan all secondary buses on all PXB's. + * Some manufacturers added fake PCI-PCI bridges that also point + * to the peer busses. Look for them and delete them. */ int pxb, reg; u8 busno, suba, subb;
- printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); + printk(KERN_NOTICE "PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); reg = 0xd0; - for(pxb=0; pxb<2; pxb++) { + for (pxb = 0; pxb < 2; pxb++) { pci_read_config_byte(d, reg++, &busno); pci_read_config_byte(d, reg++, &suba); pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(busno, &pci_root_ops, NULL); /* Bus A */ + i450nx_scan_bus(d->bus, busno); /* Bus A */ if (suba < subb) - pci_scan_bus(suba+1, &pci_root_ops, NULL); /* Bus B */ + i450nx_scan_bus(d->bus, suba+1); /* Bus B */ } + pcibios_last_bus = -1; }
----- End forwarded message -----