On Mon, May 02, 2016 at 09:09:43AM +0200, Thierry Reding wrote: > On Sat, Apr 30, 2016 at 01:01:37AM +0200, Arnd Bergmann wrote: > > This patch makes the existing 'pci_host_bridge' structure a proper device > > that is usable by PCI host drivers in a more standard way. In addition > > to the existing pci_scan_bus, pci_scan_root_bus, pci_scan_root_bus_msi, > > and pci_create_root_bus interfaces, this unfortunately means having to > > add yet another interface doing basically the same thing, and add some > > extra code in the initial step. > > > > However, this time it's more likely to be extensible enough that we > > won't have to do another one again in the future, and we should be > > able to reduce code much more as a result. > > > > The main idea is to pull the allocation of 'struct pci_host_bridge' out > > of the registration, and let individual host drivers and architecture > > code fill the members before calling the registration function. > > > > There are a number of things we can do based on this: > > > > * Use a single memory allocation for the driver-specific structure > > and the generic PCI host bridge > > * consolidate the contents of driver specific structures by moving > > them into pci_host_bridge > > * Add a consistent interface for removing a PCI host bridge again > > when unloading a host driver module > > * Replace the architecture specific __weak pcibios_* functions with > > callbacks in a pci_host_bridge device > > * Move common boilerplate code from host drivers into the generic > > function, based on contents of the structure > > * Extend pci_host_bridge with additional members when needed without > > having to add arguments to pci_scan_*. > > * Move members of struct pci_bus into pci_host_bridge to avoid > > having lots of identical copies. > > > > As mentioned in a previous email, one open question is whether we want > > to export a function for allocating a pci_host_bridge device in > > combination with the per-device structure or let the driver itself > > call kzalloc. > > I think the most common pattern in other parts of the kernel is the > latter. That gives drivers the most flexibility to do whatever they > want or need. > > > Signed-off-by: Arnd Bergmann <arnd@xxxxxxxx> > > --- > > drivers/pci/probe.c | 100 ++++++++++++++++++++++++++++++---------------------- > > include/linux/pci.h | 7 +++- > > 2 files changed, 63 insertions(+), 44 deletions(-) > > > > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > > index ae7daeb83e21..fe9d9221b11e 100644 > > --- a/drivers/pci/probe.c > > +++ b/drivers/pci/probe.c > > @@ -520,19 +520,6 @@ static void pci_release_host_bridge_dev(struct device *dev) > > kfree(bridge); > > } > > > > -static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) > > -{ > > - struct pci_host_bridge *bridge; > > - > > - bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); > > - if (!bridge) > > - return NULL; > > - > > - INIT_LIST_HEAD(&bridge->windows); > > - bridge->bus = b; > > - return bridge; > > -} > > - > > static const unsigned char pcix_bus_speed[] = { > > PCI_SPEED_UNKNOWN, /* 0 */ > > PCI_SPEED_66MHz_PCIX, /* 1 */ > > @@ -2108,51 +2095,47 @@ void __weak pcibios_remove_bus(struct pci_bus *bus) > > { > > } > > > > -struct pci_bus *pci_create_root_bus(struct device *parent, int bus, > > - struct pci_ops *ops, void *sysdata, struct list_head *resources) > > +int pci_register_host(struct pci_host_bridge *bridge) > > Perhaps pci_register_host_bridge() to mirror the structure name in the > registration function? > > > { > > int error; > > - struct pci_host_bridge *bridge; > > struct pci_bus *b, *b2; > > struct resource_entry *window, *n; > > + LIST_HEAD(resources); > > struct resource *res; > > resource_size_t offset; > > char bus_addr[64]; > > char *fmt; > > + struct device *parent = bridge->dev.parent; > > > > b = pci_alloc_bus(NULL); > > if (!b) > > - return NULL; > > + return -ENOMEM; > > + bridge->bus = b; > > > > - b->sysdata = sysdata; > > - b->ops = ops; > > - b->number = b->busn_res.start = bus; > > + /* temporarily move resources off the list */ > > Might be worth mentioning why we move the resources off the list. > > > + list_splice_init(&bridge->windows, &resources); > > + b->sysdata = bridge->sysdata; > > Does the sysdata not become effectively obsolete after this series? My > understanding is that it's primarily used to store driver-specific data > along with a PCI bus, but if drivers can embed struct pci_host_bridge > they can simply upcast bus->bridge. I second that. If we do this change (which is long overdue and I fully support), let's kill sysdata now. Generic host bridge code doesn't use sysdata on purpose. Best regards, Liviu > I do notice that bus->bridge is > currently a struct device *, perhaps we can replace it by a back pointer > to the parent struct pci_host_bridge, which would have to gain a struct > device *parent to point at the device that instantiated the bridge. This > is becoming somewhat complicated, but maybe that can be simplified at > some point. > > > + b->msi = bridge->msi; > > + b->ops = bridge->ops; > > + b->number = b->busn_res.start = bridge->busnr; > > pci_bus_assign_domain_nr(b, parent); > > - b2 = pci_find_bus(pci_domain_nr(b), bus); > > + b2 = pci_find_bus(pci_domain_nr(b), bridge->busnr); > > if (b2) { > > /* If we already got to this bus through a different bridge, ignore it */ > > dev_dbg(&b2->dev, "bus already known\n"); > > + error = -EEXIST; > > goto err_out; > > } > > > > - bridge = pci_alloc_host_bridge(b); > > - if (!bridge) > > - goto err_out; > > - > > - bridge->dev.parent = parent; > > - bridge->dev.release = pci_release_host_bridge_dev; > > - dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); > > + dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bridge->busnr); > > error = pcibios_root_bridge_prepare(bridge); > > - if (error) { > > - kfree(bridge); > > + if (error) > > goto err_out; > > - } > > > > error = device_register(&bridge->dev); > > - if (error) { > > + if (error) > > put_device(&bridge->dev); > > - goto err_out; > > - } > > + > > b->bridge = get_device(&bridge->dev); > > I'm not sure I understand why we continue after failing to register the > device. Is the usage model here that drivers set up bridge->dev with an > initial set of values here, such as what the bridge->dev.parent is? One > complication I can imagine with that is that drivers would need to have > an implementation for the bridge device's ->release() callback. Perhaps > this could be simplified by having a default release callback (maybe > set up by pci_register_host() if none was specified by the driver) that > calls a callback in struct pci_host_bridge which gets passed a struct > pci_host_bridge. I think that would make usage more uniform from the > driver perspective. > > On a side-note, perhaps it would be worth adding a structure that > carries host bridge operations (struct pci_host_bridge_ops)? > > > diff --git a/include/linux/pci.h b/include/linux/pci.h > > index 81f070a47ee7..8bb5dff617a1 100644 > > --- a/include/linux/pci.h > > +++ b/include/linux/pci.h > > @@ -400,10 +400,14 @@ static inline int pci_channel_offline(struct pci_dev *pdev) > > > > struct pci_host_bridge { > > struct device dev; > > - struct pci_bus *bus; /* root bus */ > > + struct pci_ops *ops; > > + void *sysdata; > > + int busnr; > > While at it, is there any reason why this can't be made unsigned? I know > this must sound pedantic, but whenever I see a signed integer variable I > immediately ask myself what the meaning of negative values would be, and > I can't think of any scenario where this one could possible be negative. > But perhaps I'm missing something? > > Thierry -- ==================== | I would like to | | fix the world, | | but they're not | | giving me the | \ source code! / --------------- ¯\_(ツ)_/¯ -- 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