Message ID | 3204351.WykFFcX4zJ@wuerfel (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
On Thu, Feb 13, 2014 at 12:27:05PM +0100, Arnd Bergmann wrote: > I would rather get rid of struct hw_pci for architecture independent > drivers and add a different registration method on arm32 that is > compatible with what we come up with on arm64. The main purpose of > hw_pci is to allow multiple PCI controllers to be initialized at > once, but we don't actually need that for any of the "modern" platforms > where we already have a probe function that gets called once for > each controller. No. The main purpose of hw_pci is as a container to support multiple different platform specific PCI implementations in one kernel. It's exactly what you need for single zImage.
On Thursday 13 February 2014 11:53:27 Russell King - ARM Linux wrote: > On Thu, Feb 13, 2014 at 12:27:05PM +0100, Arnd Bergmann wrote: > > I would rather get rid of struct hw_pci for architecture independent > > drivers and add a different registration method on arm32 that is > > compatible with what we come up with on arm64. The main purpose of > > hw_pci is to allow multiple PCI controllers to be initialized at > > once, but we don't actually need that for any of the "modern" platforms > > where we already have a probe function that gets called once for > > each controller. > > No. The main purpose of hw_pci is as a container to support multiple > different platform specific PCI implementations in one kernel. It's > exactly what you need for single zImage. Well, we definitely need something to manage the assignment of domains, bus numbers and I/O space windows, but the main issue I see with existing hw_pci container is that it assumes that you can pass give it all host bridges for a given domain at once. The problem with this is that the pci host bridge drivers don't interact with one another, so a system that needs two different PCI host drivers can't use hw_pci to register them both, unless we come up with some extra infrastructure. Also, the calling conventions for pci_common_init_dev() mean that it's hard to propagate -EPROBE_DEFER errors back to the driver probe function, so it seems easier to come up with something new that deals with all issues at once and that is outside of architecture specific code. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 317da88..12c2178 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -514,6 +514,26 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, } } +static void pci_common_bus_probe(struct pci_bus *bus) +{ + if (!pci_has_flag(PCI_PROBE_ONLY)) { + /* + * Size the bridge windows. + */ + pci_bus_size_bridges(bus); + + /* + * Assign resources. + */ + pci_bus_assign_resources(bus); + } + + /* + * Tell drivers about devices found. + */ + pci_bus_add_devices(bus); +} + void pci_common_init_dev(struct device *parent, struct hw_pci *hw) { struct pci_sys_data *sys; @@ -528,27 +548,38 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw) pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); - list_for_each_entry(sys, &head, node) { - struct pci_bus *bus = sys->bus; + list_for_each_entry(sys, &head, node) + pci_common_bus_probe(sys->bus); +} - if (!pci_has_flag(PCI_PROBE_ONLY)) { - /* - * Size the bridge windows. - */ - pci_bus_size_bridges(bus); - /* - * Assign resources. - */ - pci_bus_assign_resources(bus); - } - /* - * Tell drivers about devices found. - */ - pci_bus_add_devices(bus); - } + +int pci_host_bridge_register(struct device *parent, struct pci_sys_data *sys, struct pci_ops *ops, int (*setup)(int nr, struct pci_sys_data *)) +{ + int ret; + + pci_add_flags(PCI_REASSIGN_ALL_RSRC); + INIT_LIST_HEAD(&sys->resources); + + ret = setup(0, sys); + if (ret) + return ret; + + ret = pcibios_init_resources(0, sys); + if (ret) + return ret; + + sys->bus = pci_scan_root_bus(parent, sys->busnr, ops, sys, &sys->resources); + if (!sys->bus) + return -ENODEV; + + pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); + + pci_common_bus_probe(sys->bus); + return ret; } +EXPORT_SYMBOL_GPL(pci_host_bridge_register); #ifndef CONFIG_PCI_HOST_ITE8152 void pcibios_set_master(struct pci_dev *dev)