On Thu, Feb 9, 2012 at 6:36 PM, Bjorn Helgaas <bhelgaas@xxxxxxxxxx> wrote: > 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@xxxxxxxxxx> > --- > drivers/pci/probe.c | 39 ++++++++++++++++++++++++++++++++++----- > include/linux/pci.h | 5 +++++ > 2 files changed, 39 insertions(+), 5 deletions(-) > > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > index da0d655..2ffe8a3 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; > +} > + so pci_host_bridge(dev) still is expensive. > /* > * PCI Bus Class > */ > @@ -1526,20 +1545,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; > @@ -1576,6 +1598,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); > @@ -1591,6 +1615,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); > > @@ -1600,11 +1625,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; > } > > diff --git a/include/linux/pci.h b/include/linux/pci.h > index a16b1df..dfb2b64 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -388,6 +388,11 @@ static inline void pci_add_saved_cap(struct pci_dev *pci_dev, > hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space); > } > > +struct pci_host_bridge { > + struct list_head list; > + struct pci_bus *bus; /* root bus */ > +}; > + also still have two list: one for host bridges and one for root buses. Yinghai -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html