Is this the same issue we were having with Linux not being able to see
bus 1?
Stefan
----- Forwarded message from Matthew Wilcox <willy(a)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 -----
--
Stefan Reinauer, SUSE LINUX AG
Teamleader Architecture Development