(fwd) peer busses

Stefan Reinauer stepan at suse.de
Mon Nov 10 06:22:00 CET 2003


Is this the same issue we were having with Linux not being able to see
bus 1?

  Stefan

----- Forwarded message from Matthew Wilcox <willy at 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



More information about the coreboot mailing list