Messages in this thread Patch in this message | | | Date | Thu, 23 Apr 1998 22:35:46 -0700 | From | Steve Sweeney <> | Subject | patch to support peer PCI host bridges |
| |
Hi -
I'm new to Linux and this is my first post. I am running 2.1.97 on a Micron Powerdigm Xsu and found that the pci_scan_bus routine in drivers/pci/pci.c does not properly support peer host-PCI bridges (multiple bridges attached to the host bus). This is not a common configuration but the Powerdigm at least does implement peer host bridges. The peer host bridges must be configured with unique bus numbers in order to distinguish configuration space accesses (since the configuration registers overlay each other in memory in this situation). The patch follows (apologies if it is not in the correct format):
====cut=====
--- linux/drivers/pci/pci.c Fri Apr 17 21:58:48 1998 +++ linux-modpci-2.1.97/drivers/pci/pci.c Thu Apr 23 18:05:42 1998 @@ -92,7 +92,7 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) { - unsigned int devfn, l, max, class; + unsigned int devfn, l, max, class, hostbridges = 0; unsigned char cmd, irq, tmp, hdr_type, is_multi = 0; struct pci_dev *dev; struct pci_bus *child; @@ -289,6 +289,79 @@ } pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr); } + + /* if it's a host bridge, keep track of how many we've seen on this bus. + multiple ones on the same bus need to be assigned their own bus number + */ + if ( (class >> 8 == PCI_CLASS_BRIDGE_HOST) && (++hostbridges > 1) ) { + unsigned int buses; + unsigned short cr; + + /* + * Insert it into the tree of buses. + */ + child = kmalloc(sizeof(*child), GFP_ATOMIC); + memset(child, 0, sizeof(*child)); + bus->next =child; + child->self = dev; + + /* + * Set up the primary, secondary and subordinate + * bus numbers. + */ + child->number = child->primary = child->secondary = ++max; + child->subordinate = 0xff; + /* + * Clear all status bits and turn off memory, + * I/O and master enables. + */ + pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr); + pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000); + pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff); + /* + * Read the existing primary/secondary/subordinate bus + * number configuration to determine if the PCI bridge + * has already been configured by the system. If so, + * do not modify the configuration, merely note it. + */ + pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses); + if ((buses & 0xFFFFFF) != 0) + { + unsigned int cmax; + + child->primary = buses & 0xFF; + child->secondary = (buses >> 8) & 0xFF; + child->subordinate = (buses >> 16) & 0xFF; + child->number = child->secondary; + cmax = pci_scan_bus(child); + if (cmax > max) max = cmax; + } + else + { + /* + * Configure the bus numbers for this bridge: + */ + buses &= 0xff000000; + buses |= + (((unsigned int)(child->primary) << 0) | + ((unsigned int)(child->secondary) << 8) | + ((unsigned int)(child->subordinate) << 16)); + pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); + /* + * Now we can scan all subordinate buses: + */ + max = pci_scan_bus(child); + /* + * Set the subordinate bus number to its real + * value: + */ + child->subordinate = max; + buses = (buses & 0xff00ffff) + | ((unsigned int)(child->subordinate) << 16); + pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); + } + pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr); + } } /* * We've scanned the bus and so we know all about what's on ====cut===== - Steven M. Sweeney <smcs@ricochet.net>
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu
| |