summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2012-02-23 20:18:59 -0700
committerBjorn Helgaas <bhelgaas@google.com>2012-02-23 20:18:59 -0700
commit5a21d70dbd33d20713fb735ad9381711b0ae2c9b (patch)
treef3c6c65295f1356f62389fafad777d7be047aca5 /drivers
parenta5390aa6dc3646b08bed421944cef0daf78ab994 (diff)
downloadlinux-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.c39
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;
}