diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-02-23 20:18:59 -0700 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-02-23 20:18:59 -0700 |
commit | 5a21d70dbd33d20713fb735ad9381711b0ae2c9b (patch) | |
tree | f3c6c65295f1356f62389fafad777d7be047aca5 /drivers | |
parent | a5390aa6dc3646b08bed421944cef0daf78ab994 (diff) | |
download | linux-3.10-5a21d70dbd33d20713fb735ad9381711b0ae2c9b.tar.gz linux-3.10-5a21d70dbd33d20713fb735ad9381711b0ae2c9b.tar.bz2 linux-3.10-5a21d70dbd33d20713fb735ad9381711b0ae2c9b.zip |
PCI: add struct pci_host_bridge and a list of all bridges found
This adds a list of all PCI host bridges we find and a way to look up
the host bridge from a pci_dev.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/probe.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index e4c0d1c6324..3a30023a123 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -15,6 +15,8 @@ #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_RESERVE_BUSNR 3 +static LIST_HEAD(pci_host_bridges); + /* Ugh. Need to stop exporting this to modules. */ LIST_HEAD(pci_root_buses); EXPORT_SYMBOL(pci_root_buses); @@ -42,6 +44,23 @@ int no_pci_devices(void) } EXPORT_SYMBOL(no_pci_devices); +static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev) +{ + struct pci_bus *bus; + struct pci_host_bridge *bridge; + + bus = dev->bus; + while (bus->parent) + bus = bus->parent; + + list_for_each_entry(bridge, &pci_host_bridges, list) { + if (bridge->bus == bus) + return bridge; + } + + return NULL; +} + /* * PCI Bus Class */ @@ -1544,20 +1563,23 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources) { int error, i; + struct pci_host_bridge *bridge; struct pci_bus *b, *b2; struct device *dev; struct pci_bus_resource *bus_res, *n; struct resource *res; + bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); + if (!bridge) + return NULL; + b = pci_alloc_bus(); if (!b) - return NULL; + goto err_bus; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - kfree(b); - return NULL; - } + if (!dev) + goto err_dev; b->sysdata = sysdata; b->ops = ops; @@ -1594,6 +1616,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, b->number = b->secondary = bus; + bridge->bus = b; + /* Add initial resources to the bus */ list_for_each_entry_safe(bus_res, n, resources, list) list_move_tail(&bus_res->list, &b->resources); @@ -1609,6 +1633,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, } down_write(&pci_bus_sem); + list_add_tail(&bridge->list, &pci_host_bridges); list_add_tail(&b->node, &pci_root_buses); up_write(&pci_bus_sem); @@ -1618,11 +1643,15 @@ class_dev_reg_err: device_unregister(dev); dev_reg_err: down_write(&pci_bus_sem); + list_del(&bridge->list); list_del(&b->node); up_write(&pci_bus_sem); err_out: kfree(dev); +err_dev: kfree(b); +err_bus: + kfree(bridge); return NULL; } |