This patch adds a basic PCI<->PCI bridge driver that utilizes the new PCI bus class API.
Signed-off-by: Adam Belay <[EMAIL PROTECTED]> --- a/drivers/pci/bus/pci-bridge.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/pci/bus/pci-bridge.c 2005-07-08 02:18:43.000000000 -0400 @@ -0,0 +1,165 @@ +/* + * pci-bridge.c - a generic PCI bus driver for PCI<->PCI bridges + * + */ + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/module.h> + +static struct pci_device_id ppb_id_tbl[] = { + { PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI << 8, 0xffff00) }, + { 0 }, +}; + +MODULE_DEVICE_TABLE(pci, ppb_id_tbl); + +/** + * ppb_create_bus - allocates a bus and fills in basic information + * @dev: the pci bridge device + */ +static struct pci_bus * ppb_create_bus(struct pci_dev *dev) +{ + int i; + struct pci_bus *bus = pci_alloc_bus(); + + if (!bus) + return NULL; + + bus->parent = dev->bus; + bus->bridge = &dev->dev; + bus->ops = bus->parent->ops; + bus->sysdata = bus->parent->sysdata; + bus->bridge = get_device(&dev->dev); + + /* Set up default resource pointers and names.. */ + for (i = 0; i < 4; i++) { + bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + bus->resource[i]->name = bus->name; + } + + return bus; +} + +/** + * ppb_detect_bus - creates a bus and reads configuration space data + * @dev: the pci bridge device + * + * This function will do some verification to ensure we should drive this + * bridge. + */ +static struct pci_bus * ppb_detect_bus(struct pci_dev *dev) +{ + struct pci_bus *bus; + u32 buses; + u16 bctl; + unsigned int busnr; + + pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); + busnr = (buses >> 8) & 0xFF; + + /* + * FIXME: This driver currently doesn't support bridges that haven't + * been configured by the BIOS. + */ + if (!(buses & 0xffff00)) { + printk(KERN_INFO "PCI: Unable to drive bus %04x:%02x\n", + pci_domain_nr(dev->bus), busnr); + return NULL; + } + + /* + * If we already got to this bus through a different bridge, + * ignore it. This can happen with the i450NX chipset. + */ + if (pci_find_bus(pci_domain_nr(dev->bus), busnr)) { + printk(KERN_INFO "PCI: Bus %04x:%02x already known\n", + pci_domain_nr(dev->bus), busnr); + return NULL; + } + + bus = ppb_create_bus(dev); + if (!bus) + return NULL; + + /* 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); + + bus->number = bus->secondary = busnr; + bus->primary = buses & 0xFF; + bus->subordinate = (buses >> 16) & 0xFF; + bus->bridge_ctl = bctl; + + return bus; +} + +/** + * ppb_detect_children - detects and registers child devices + * @bus: pci bus + */ +static void ppb_detect_children(struct pci_bus *bus) +{ + unsigned int devfn; + + /* Go find them, Rover! */ + for (devfn = 0; devfn < 0x100; devfn += 8) + pci_scan_slot(bus, devfn); + + pcibios_fixup_bus(bus); + pci_bus_add_devices(bus); +} + +static int ppb_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int err; + struct pci_bus *bus; + + if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) + return -ENODEV; + + bus = ppb_detect_bus(dev); + if (!bus) + return -ENODEV; + + err = pci_add_bus(bus); + if (err) + goto out; + + dev->subordinate = bus; + ppb_detect_children(bus); + return 0; + +out: + kfree(bus); + return err; +} + +static void ppb_remove(struct pci_dev *dev) +{ + pci_remove_behind_bridge(dev); + pci_remove_bus(dev->subordinate); +} + +static struct pci_driver ppb_driver = { + .name = "pci-bridge", + .id_table = ppb_id_tbl, + .probe = ppb_probe, + .remove = ppb_remove, +}; + +static int __init ppb_init(void) +{ + return pci_register_driver(&ppb_driver); +} + +static void __exit ppb_exit(void) +{ + pci_unregister_driver(&ppb_driver); +} + +module_init(ppb_init); +module_exit(ppb_exit); --- a/drivers/pci/bus/Makefile 2005-07-07 22:22:49.000000000 -0400 +++ b/drivers/pci/bus/Makefile 2005-07-08 02:16:39.000000000 -0400 @@ -2,4 +2,4 @@ # Makefile for the PCI device detection # -obj-y := bus.o config.o device.o probe.o +obj-y := bus.o config.o device.o probe.o pci-bridge.o - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/