Hi Bjorn and others,
Triggered by Christoph's patches, I had another go at converting
all of the remaining pci host bridge implementations to be based
on pci_alloc_host_bridge and a separate registration function.
This is made possible through work from Lorenzo and others to
convert many of the existing drivers, as well as the removal
of some of the older architectures that nobody used.
I'm adding a bit of duplication into the less maintained code
here, but it makes everything more consistent, and gives an
easy place to hook up callback functions etc.
The three parts of this series are:
a) push up the registration into the callers (this is where
code gets added)
b) clean up some of the more common host bridge
implementations again to integrate that code better.
This could be done for the rest as well, or we could just
leave them alone.
c) start moving the __weak functions into callbacks in
pci_host_bridge. This is intentionally incomplete, since
it is a lot of work to do it for all those functions,
and I want to get consensus on the approach first, as well
as maybe get other developers to help out with the rest.
Please have a look.
Arnd
[1] https://lore.kernel.org/lkml/4288331.jNpl6KXlNO@wuerfel/
[2] https://patchwork.kernel.org/patch/10555657/
Arnd Bergmann (15):
PCI: clean up legacy host bridge scan functions
PCI: move pci_scan_bus into callers
PCI: move pci_scan_root_bus into callers
PCI: export pci_register_host_bridge
PCI: move pci_create_root_bus into callers
powerpc/pci: fold pci_create_root_bus into pcibios_scan_phb
PCI/ACPI: clean up acpi_pci_root_create()
x86: PCI: clean up pcibios_scan_root()
PCI: xenfront: clean up pcifront_scan_root()
sparc/PCI: simplify pci_scan_one_pbm
PCI: hyperv: convert to pci_scan_root_bus_bridge
PCI: make pcibios_bus_add_device() a callback function
PCI: turn pcibios_alloc_irq into a callback
PCI: make pcibios_root_bridge_prepare a callback
PCI: make pcibios_add_bus/remove_bus callbacks
arch/arm64/kernel/pci.c | 40 ++-----
arch/ia64/pci/pci.c | 25 +----
arch/ia64/sn/kernel/io_init.c | 27 +++++
arch/microblaze/pci/pci-common.c | 27 +++++
arch/powerpc/include/asm/pci-bridge.h | 3 +
arch/powerpc/kernel/pci-common.c | 60 +++++------
arch/s390/pci/pci.c | 30 +++++-
arch/sh/drivers/pci/pci.c | 1 +
arch/sh/drivers/pci/pcie-sh7786.c | 3 +-
arch/sh/include/asm/pci.h | 2 +
arch/sparc/kernel/pci.c | 40 ++++---
arch/sparc/kernel/pcic.c | 35 ++++++
arch/x86/pci/acpi.c | 15 +--
arch/x86/pci/common.c | 42 ++++----
arch/xtensa/kernel/pci.c | 27 +++++
drivers/acpi/pci_root.c | 43 +++++---
drivers/parisc/dino.c | 28 +++++
drivers/parisc/lba_pci.c | 28 +++++
drivers/pci/bus.c | 8 +-
drivers/pci/controller/pci-hyperv.c | 47 ++++----
drivers/pci/controller/vmd.c | 30 +++++-
drivers/pci/hotplug/ibmphp_core.c | 35 ++++++
drivers/pci/pci-driver.c | 13 ++-
drivers/pci/probe.c | 150 +++++++++-----------------
drivers/pci/xen-pcifront.c | 40 +++----
include/linux/acpi.h | 2 +
include/linux/pci.h | 17 ++-
27 files changed, 514 insertions(+), 304 deletions(-)
--
2.18.0
Aside from the modern pci_host_bridge based interfaces, we have a couple
of interfaces from old times that are still used in a couple of platforms:
pci_create_root_bus(), pci_scan_bus() and pci_scan_root_bus().
As a first step towards getting everybody to use the new interfaces,
this simplifies the latter two to call the pci_alloc_host_bridge() and
pci_register_host_bridge()/pci_scan_root_bus_bridge() interfaces directly.
The behavior should be entirely unchanged here, but we can then push
down the functions into the individual host implementations.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/pci/probe.c | 86 ++++++++++++++++++++++++---------------------
1 file changed, 45 insertions(+), 41 deletions(-)
@@ -23,13 +23,6 @@#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */#define CARDBUS_RESERVE_BUSNR 3-staticstructresourcebusn_resource={-.name="PCI busn",-.start=0,-.end=255,-.flags=IORESOURCE_BUS,-};-/* Ugh. Need to stop exporting this to modules. */LIST_HEAD(pci_root_buses);EXPORT_SYMBOL(pci_root_buses);
@@ -3060,53 +3053,64 @@ EXPORT_SYMBOL(pci_scan_root_bus_bridge);structpci_bus*pci_scan_root_bus(structdevice*parent,intbus,structpci_ops*ops,void*sysdata,structlist_head*resources){-structresource_entry*window;-boolfound=false;-structpci_bus*b;-intmax;--resource_list_for_each_entry(window,resources)-if(window->res->flags&IORESOURCE_BUS){-found=true;-break;-}+structpci_host_bridge*bridge;+interror;-b=pci_create_root_bus(parent,bus,ops,sysdata,resources);-if(!b)+bridge=pci_alloc_host_bridge(0);+if(!bridge)returnNULL;-if(!found){-dev_info(&b->dev,-"No busn resource found for root bus, will use [bus %02x-ff]\n",-bus);-pci_bus_insert_busn_res(b,bus,255);-}+list_splice_init(resources,&bridge->windows);+bridge->dev.parent=parent;+bridge->sysdata=sysdata;+bridge->busnr=bus;+bridge->ops=ops;-max=pci_scan_child_bus(b);+error=pci_scan_root_bus_bridge(bridge);+if(error<0)+gotoerr_out;-if(!found)-pci_bus_update_busn_res_end(b,max);+returnbridge->bus;-returnb;+err_out:+kfree(bridge);+returnNULL;}EXPORT_SYMBOL(pci_scan_root_bus);+staticstructresourcebusn_resource={+.name="PCI busn",+.start=0,+.end=255,+.flags=IORESOURCE_BUS,+};+structpci_bus*pci_scan_bus(intbus,structpci_ops*ops,void*sysdata){-LIST_HEAD(resources);-structpci_bus*b;+structpci_host_bridge*bridge;+interror;-pci_add_resource(&resources,&ioport_resource);-pci_add_resource(&resources,&iomem_resource);-pci_add_resource(&resources,&busn_resource);-b=pci_create_root_bus(NULL,bus,ops,sysdata,&resources);-if(b){-pci_scan_child_bus(b);-}else{-pci_free_resource_list(&resources);-}-returnb;+bridge=pci_alloc_host_bridge(0);+if(!bridge)+gotoerr;++pci_add_resource(&bridge->windows,&ioport_resource);+pci_add_resource(&bridge->windows,&iomem_resource);+pci_add_resource(&bridge->windows,&busn_resource);+bridge->sysdata=sysdata;+bridge->busnr=bus;+bridge->ops=ops;++error=pci_scan_root_bus_bridge(bridge);+if(error<0)+gotoerr;++returnbridge->bus;++err:+pci_free_host_bridge(bridge);+returnNULL;}EXPORT_SYMBOL(pci_scan_bus);
These are mostly not architecture specific but are meant for particular
PCI host bridge implementations, in particular for the ACPI version.
Turn them both into callback functions that are implemented by the
APCI PCI implementation as well as the one architecture that overrides
pcibios_remove_bus.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm64/kernel/pci.c | 10 ----------
arch/ia64/pci/pci.c | 10 ----------
arch/s390/pci/pci.c | 3 ++-
arch/x86/pci/common.c | 10 ----------
drivers/acpi/pci_root.c | 2 ++
drivers/pci/probe.c | 12 ++++++++++--
include/linux/pci.h | 2 ++
7 files changed, 16 insertions(+), 33 deletions(-)
@@ -367,16 +367,6 @@ void pcibios_fixup_bus(struct pci_bus *b)platform_pci_fixup_bus(b);}-voidpcibios_add_bus(structpci_bus*bus)-{-acpi_pci_add_bus(bus);-}--voidpcibios_remove_bus(structpci_bus*bus)-{-acpi_pci_remove_bus(bus);-}-voidpcibios_set_master(structpci_dev*dev){/* No special bus mastering setup handling */
Weak functions are confusion, and we can now add callback pointers
to pci host bridges for any controller, so let's make this one
a callback rather than a __weak global function.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/powerpc/kernel/pci-common.c | 7 +------
arch/sh/drivers/pci/pci.c | 1 +
arch/sh/drivers/pci/pcie-sh7786.c | 3 ++-
arch/sh/include/asm/pci.h | 2 ++
drivers/pci/bus.c | 8 +++++++-
include/linux/pci.h | 2 +-
6 files changed, 14 insertions(+), 9 deletions(-)
@@ -880,7 +881,6 @@ extern struct list_head pci_root_buses; /* List of all known PCI buses */intno_pci_devices(void);voidpcibios_resource_survey_bus(structpci_bus*bus);-voidpcibios_bus_add_device(structpci_dev*pdev);voidpcibios_add_bus(structpci_bus*bus);voidpcibios_remove_bus(structpci_bus*bus);voidpcibios_fixup_bus(structpci_bus*);
Merging pci_scan_root_bus() into pcifront_scan_root() simplifies
the implementation and makes it more readable. We can allocate
the pcifront_sd structure along with the bridge structure, which
helps manage its lifetime rules so we don't free it before the
device has been released.
There are two small issues that I noticed that could be improved:
- It seems we unregister the 'bus' device that is a child of the
'pci_host_bridge' device after we unregister its parent in
pcifront_free_roots(), which seems odd.
- We probably don't need an extra pci_bus_entry list at all,
but could instead walk the children of the pcifront_device,
which are all pci_host_bridge devices.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/pci/xen-pcifront.c | 67 ++++++++++++--------------------------
1 file changed, 21 insertions(+), 46 deletions(-)
@@ -443,40 +443,12 @@ static int pcifront_scan_bus(struct pcifront_device *pdev,return0;}-staticstructpci_bus*pci_scan_root_bus(structdevice*parent,intbus,-structpci_ops*ops,void*sysdata,structlist_head*resources)-{-structpci_host_bridge*bridge;-interror;--bridge=pci_alloc_host_bridge(0);-if(!bridge)-returnNULL;--list_splice_init(resources,&bridge->windows);-bridge->dev.parent=parent;-bridge->sysdata=sysdata;-bridge->busnr=bus;-bridge->ops=ops;--error=pci_scan_root_bus_bridge(bridge);-if(error<0)-gotoerr_out;--returnbridge->bus;--err_out:-kfree(bridge);-returnNULL;-}-staticintpcifront_scan_root(structpcifront_device*pdev,unsignedintdomain,unsignedintbus){-structpci_bus*b;-LIST_HEAD(resources);structpcifront_sd*sd=NULL;structpci_bus_entry*bus_entry=NULL;+structpci_host_bridge*bridge;interr=0;staticstructresourcebusn_res={.start=0,
@@ -498,50 +470,55 @@ static int pcifront_scan_root(struct pcifront_device *pdev,dev_info(&pdev->xdev->dev,"Creating PCI Frontend Bus %04x:%02x\n",domain,bus);+bridge=pci_alloc_host_bridge(sizeof(*sd));+if(!bridge)+return-ENOMEM;+bus_entry=kzalloc(sizeof(*bus_entry),GFP_KERNEL);-sd=kzalloc(sizeof(*sd),GFP_KERNEL);-if(!bus_entry||!sd){+sd=pci_host_bridge_priv(bridge);+if(!bus_entry){err=-ENOMEM;gotoerr_out;}-pci_add_resource(&resources,&ioport_resource);-pci_add_resource(&resources,&iomem_resource);-pci_add_resource(&resources,&busn_res);+pci_add_resource(&bridge->windows,&ioport_resource);+pci_add_resource(&bridge->windows,&iomem_resource);+pci_add_resource(&bridge->windows,&busn_res);pcifront_init_sd(sd,domain,bus,pdev);+bridge->dev.parent=&pdev->xdev->dev;+bridge->sysdata=sd;+bridge->busnr=bus;+bridge->ops=&pcifront_bus_ops;pci_lock_rescan_remove();-b=pci_scan_root_bus(&pdev->xdev->dev,bus,-&pcifront_bus_ops,sd,&resources);-if(!b){+err=pci_scan_root_bus_bridge(bridge);+if(err<0){dev_err(&pdev->xdev->dev,"Error creating PCI Frontend Bus!\n");-err=-ENOMEM;pci_unlock_rescan_remove();-pci_free_resource_list(&resources);gotoerr_out;}-bus_entry->bus=b;+bus_entry->bus=bridge->bus;list_add(&bus_entry->list,&pdev->root_buses);/* pci_scan_root_bus skips devices which do not have a*devfn==0.Thepcifront_scan_busenumeratesalldevfn.*/-err=pcifront_scan_bus(pdev,domain,bus,b);+err=pcifront_scan_bus(pdev,domain,bus,bridge->bus);/* Claim resources before going "live" with our devices */-pci_walk_bus(b,pcifront_claim_resource,pdev);+pci_walk_bus(bridge->bus,pcifront_claim_resource,pdev);/* Create SysFS and notify udev of the devices. Aka: "going live" */-pci_bus_add_devices(b);+pci_bus_add_devices(bridge->bus);pci_unlock_rescan_remove();returnerr;err_out:+pci_free_host_bridge(bridge);kfree(bus_entry);-kfree(sd);returnerr;}
There are only seven remaining callers of the old pci_scan_root_bus()
interface. Since we want to expose the pci_host_bridge structure
everywhere and discourage users from calling the old interfaces, let's
move the implementation into the respective callsites.
While this duplicates the source code, it makes the object code smaller
for almost all users by avoiding the global implementation, and it allows
further cleanup of the callers.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/powerpc/kernel/pci-common.c | 28 +++++++++++++++++++++++++++
arch/sparc/kernel/pci.c | 28 +++++++++++++++++++++++++++
drivers/acpi/pci_root.c | 30 ++++++++++++++++++++++++++++-
drivers/parisc/dino.c | 28 +++++++++++++++++++++++++++
drivers/parisc/lba_pci.c | 28 +++++++++++++++++++++++++++
drivers/pci/controller/pci-hyperv.c | 28 +++++++++++++++++++++++++++
drivers/pci/controller/vmd.c | 30 ++++++++++++++++++++++++++++-
drivers/pci/probe.c | 29 ----------------------------
include/linux/pci.h | 3 ---
9 files changed, 198 insertions(+), 34 deletions(-)
There are a couple of users of the old pci_create_root_bus() interface,
which calls pci_register_host_bridge() without actually scanning the bus.
In order to get those callers a little closer to the current method
of separating the allocation and probing of the host bridge, this
exports the internal interface to modules. If all the callers can
get moved over to pci_host_probe() or pci_scan_root_bus_bridge()
later, the export can be removed again.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/pci/probe.c | 25 ++++++++++++++++++++++++-
include/linux/pci.h | 1 +
2 files changed, 25 insertions(+), 1 deletion(-)
We no longer need a separate pci_create_root_bus() function, and
merging it into pci_scan_one_pbm() makes the implementation easier
to understand.
A possible future cleanup would move the allocation of the
pci_host_bridge structure into the callers of pci_scan_one_pbm,
and avoid duplication between pci_host_bridge and pci_pbm_info
fields.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/sparc/kernel/pci.c | 62 ++++++++++++++---------------------------
1 file changed, 21 insertions(+), 41 deletions(-)
This slightly simplifies the pcibios_scan_phb() implementation, and
gives us an easier point to add further fields in the pci_host_bridge
structure.
I tried removing fields that are duplicated between pci_host_bridge
and pci_controller (which really serve the same purpose), but
ran into the problem that we can't call pci_alloc_host_bridge()
as early as pcibios_alloc_controller(). Some more refactoring
is needed for that, but it could noticably clean the powerpc code
up more.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/powerpc/include/asm/pci-bridge.h | 3 ++
arch/powerpc/kernel/pci-common.c | 72 ++++++++++-----------------
2 files changed, 30 insertions(+), 45 deletions(-)
@@ -1587,81 +1587,63 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)returnof_node_get(hose->dn);}-staticstructpci_bus*pci_create_root_bus(structdevice*parent,intbus,-structpci_ops*ops,void*sysdata,structlist_head*resources)-{-interror;-structpci_host_bridge*bridge;--bridge=pci_alloc_host_bridge(0);-if(!bridge)-returnNULL;--bridge->dev.parent=parent;--list_splice_init(resources,&bridge->windows);-bridge->sysdata=sysdata;-bridge->busnr=bus;-bridge->ops=ops;--error=pci_register_host_bridge(bridge);-if(error<0)-gotoerr_out;--returnbridge->bus;--err_out:-kfree(bridge);-returnNULL;-}-/***pci_scan_phb-Givenapci_controller,setupandscanthePCIbus*@hose:PointertothePCIhostcontrollerinstancestructure*/voidpcibios_scan_phb(structpci_controller*hose){-LIST_HEAD(resources);-structpci_bus*bus;structdevice_node*node=hose->dn;intmode;+structpci_host_bridge*bridge;+interror;pr_debug("PCI: Scanning PHB %pOF\n",node);+/* The allocation should ideally be done in pcibios_alloc_controller(),+*butpci_alloc_host_bridge()requiresslabtoworkfirst*/+bridge=pci_alloc_host_bridge(0);+if(!bridge)+return;+/* Get some IO space for the new PHB */pcibios_setup_phb_io_space(hose);/* Wire up PHB bus resources */-pcibios_setup_phb_resources(hose,&resources);+pcibios_setup_phb_resources(hose,&bridge->windows);hose->busn.start=hose->first_busno;hose->busn.end=hose->last_busno;hose->busn.flags=IORESOURCE_BUS;-pci_add_resource(&resources,&hose->busn);+pci_add_resource(&bridge->windows,&hose->busn);++bridge->dev.parent=hose->parent;+bridge->sysdata=hose;+bridge->busnr=hose->first_busno;+bridge->ops=hose->ops;-/* Create an empty bus for the toplevel */-bus=pci_create_root_bus(hose->parent,hose->first_busno,-hose->ops,hose,&resources);-if(bus==NULL){+error=pci_register_host_bridge(bridge);+if(error<0){pr_err("Failed to create bus for PCI domain %04x\n",hose->global_number);-pci_free_resource_list(&resources);+pci_free_host_bridge(bridge);return;}-hose->bus=bus;+hose->bridge=bridge;+hose->bus=bridge->bus;/* Get probe mode and perform scan */mode=PCI_PROBE_NORMAL;if(node&&hose->controller_ops.probe_mode)-mode=hose->controller_ops.probe_mode(bus);+mode=hose->controller_ops.probe_mode(bridge->bus);pr_debug(" probe mode: %d\n",mode);if(mode==PCI_PROBE_DEVTREE)-of_scan_bus(node,bus);+of_scan_bus(node,bridge->bus);if(mode==PCI_PROBE_NORMAL){-pci_bus_update_busn_res_end(bus,255);-hose->last_busno=pci_scan_child_bus(bus);-pci_bus_update_busn_res_end(bus,hose->last_busno);+pci_bus_update_busn_res_end(bridge->bus,255);+hose->last_busno=pci_scan_child_bus(bridge->bus);+pci_bus_update_busn_res_end(bridge->bus,hose->last_busno);}/* Platform gets a chance to do some global fixups before
There are only two remaining callers of the old pci_scan_bus()
interface. Since we want to expose the pci_host_bridge structure
everywhere and discourage users from calling the old interfaces,
let's move the implementation into the respective callsites.
While this duplicates the source code, it makes the object code
smaller for all users by avoiding the global implementation,
and it allows further cleanup of the two callers.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/sparc/kernel/pcic.c | 35 ++++++++++++++++++++++++++++++
drivers/pci/hotplug/ibmphp_core.c | 35 ++++++++++++++++++++++++++++++
drivers/pci/probe.c | 36 -------------------------------
include/linux/pci.h | 1 -
4 files changed, 70 insertions(+), 37 deletions(-)
create_root_hv_pci_bus() uses a rather generic method of probing the host
bridge, which can be simplified by just calling pci_scan_root_bus_bridge()
after setting up the pci_host_bridge structure.
Since we can no longer assign hbus->pci_bus in the middle, I just remove
that member completely and use the pci_host_bridge instead.
Ideally we'd convert it to pci_host_probe() for simplicity, but
that is a bit different and I could not easily test it. Using
pci_scan_root_bus_bridge should not change the behavior at all.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/pci/controller/pci-hyperv.c | 75 +++++++++++------------------
1 file changed, 28 insertions(+), 47 deletions(-)
@@ -1493,25 +1465,34 @@ static struct pci_bus *pci_create_root_bus(struct device *parent, int bus,*/staticintcreate_root_hv_pci_bus(structhv_pcibus_device*hbus){-/* Register the device */-hbus->pci_bus=pci_create_root_bus(&hbus->hdev->device,-0,/* bus number is always zero */-&hv_pcifront_ops,-&hbus->sysdata,-&hbus->resources_for_children);-if(!hbus->pci_bus)-return-ENODEV;+structpci_host_bridge*bridge;+intret;++bridge=pci_alloc_host_bridge(0);+if(!bridge)+return-ENOMEM;-hbus->pci_bus->msi=&hbus->msi_chip;-hbus->pci_bus->msi->dev=&hbus->hdev->device;+hbus->bridge=bridge;+bridge->dev.parent=&hbus->hdev->device;+list_splice_init(&hbus->resources_for_children,&bridge->windows);+bridge->sysdata=&hbus->sysdata;+bridge->ops=&hv_pcifront_ops;+bridge->msi=&hbus->msi_chip;+bridge->msi->dev=&hbus->hdev->device;pci_lock_rescan_remove();-pci_scan_child_bus(hbus->pci_bus);-pci_bus_assign_resources(hbus->pci_bus);-pci_bus_add_devices(hbus->pci_bus);-pci_unlock_rescan_remove();+/* ideally we should use pci_host_probe here */+ret=pci_scan_root_bus_bridge(bridge);+if(ret<0){+pci_free_host_bridge(bridge);+gotoerror;+}+pci_bus_assign_resources(bridge->bus);+pci_bus_add_devices(bridge->bus);hbus->state=hv_pcibus_installed;-return0;+error:+pci_unlock_rescan_remove();+returnret;}structq_res_req_compl{
@@ -2669,8 +2650,8 @@ static int hv_pci_remove(struct hv_device *hdev)if(hbus->state==hv_pcibus_installed){/* Remove the bus from PCI's point of view. */pci_lock_rescan_remove();-pci_stop_root_bus(hbus->pci_bus);-pci_remove_root_bus(hbus->pci_bus);+pci_stop_root_bus(hbus->bridge->bus);+pci_remove_root_bus(hbus->bridge->bus);pci_unlock_rescan_remove();hbus->state=hv_pcibus_removed;}
pcibios_root_bridge_prepare() is always used as a per host bridge
function, not per architecture.
Making it a callback in the pci_host_bridge instead lets the host
bridge implementation easily override it, and avoids the checks
in the architecture for which host bridge implementation is being
used.
Alternatively, we could probably just call the pcibios_root_bridge_prepare
after alloc_pci_host_bridge() here and get rid of it as a generic
interface altogether, but doing that has a slightly higher chance
of breaking something subtle.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm64/kernel/pci.c | 18 ++++++++----------
arch/ia64/pci/pci.c | 15 ++++-----------
arch/powerpc/kernel/pci-common.c | 9 +--------
arch/x86/pci/acpi.c | 15 ++++-----------
drivers/acpi/pci_root.c | 1 +
drivers/pci/probe.c | 28 ++++++++++++++++------------
include/linux/acpi.h | 2 ++
include/linux/pci.h | 3 +--
8 files changed, 37 insertions(+), 54 deletions(-)
@@ -71,19 +71,17 @@ int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)returnroot->segment;}-intpcibios_root_bridge_prepare(structpci_host_bridge*bridge)+intacpi_pci_root_bridge_prepare(structpci_host_bridge*bridge){-if(!acpi_disabled){-structpci_config_window*cfg=bridge->bus->sysdata;-structacpi_device*adev=to_acpi_device(cfg->parent);-structdevice*bus_dev=&bridge->bus->dev;+structpci_config_window*cfg=bridge->bus->sysdata;+structacpi_device*adev=to_acpi_device(cfg->parent);+structdevice*bus_dev=&bridge->bus->dev;-ACPI_COMPANION_SET(&bridge->dev,adev);-set_dev_node(bus_dev,acpi_get_node(acpi_device_handle(adev)));+ACPI_COMPANION_SET(&bridge->dev,adev);+set_dev_node(bus_dev,acpi_get_node(acpi_device_handle(adev)));-/* Try to assign the IRQ number when probing a new device */-bridge->alloc_irq=acpi_pci_irq_enable;-}+/* Try to assign the IRQ number when probing a new device */+bridge->alloc_irq=acpi_pci_irq_enable;return0;}
@@ -771,14 +771,6 @@ int pci_proc_domain(struct pci_bus *bus)return1;}-intpcibios_root_bridge_prepare(structpci_host_bridge*bridge)-{-if(ppc_md.pcibios_root_bridge_prepare)-returnppc_md.pcibios_root_bridge_prepare(bridge);--return0;-}-/* This header fixup will do the resource fixup for all devices as they are*probed,butnotforbridgeranges*/
@@ -336,12 +336,14 @@ extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);voidacpi_unregister_gsi(u32gsi);structpci_dev;+structpci_host_bridge;intacpi_pci_irq_enable(structpci_dev*dev);voidacpi_penalize_isa_irq(intirq,intactive);boolacpi_isa_irq_available(intirq);voidacpi_penalize_sci_irq(intirq,inttrigger,intpolarity);voidacpi_pci_irq_disable(structpci_dev*dev);+intacpi_pci_root_bridge_prepare(structpci_host_bridge*bridge);externintec_read(u8addr,u8*val);externintec_write(u8addr,u8val);
There are only six remaining callers of the old pci_scan_root_bus()
interface. Since we want to expose the pci_host_bridge structure
everywhere and discourage users from calling the old interfaces, let's
move the implementation into the respective callsites.
While this duplicates the source code, it makes the object code smaller
for almost all users by avoiding the global implementation, and it allows
further cleanup of the callers.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/ia64/sn/kernel/io_init.c | 27 +++++++++++++++++++++++++++
arch/microblaze/pci/pci-common.c | 27 +++++++++++++++++++++++++++
arch/s390/pci/pci.c | 27 +++++++++++++++++++++++++++
arch/x86/pci/common.c | 27 +++++++++++++++++++++++++++
arch/xtensa/kernel/pci.c | 27 +++++++++++++++++++++++++++
drivers/pci/probe.c | 28 ----------------------------
drivers/pci/xen-pcifront.c | 27 +++++++++++++++++++++++++++
include/linux/pci.h | 3 ---
8 files changed, 162 insertions(+), 31 deletions(-)
Weak functions are a bit confusing, and we can better deal with
this using a callback function. pcibios_free_irq() is actually
completely unused, but it seems better to treat it the same way
as the allocation, unless we want to remove it completely.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm64/kernel/pci.c | 16 +++-------------
drivers/pci/pci-driver.c | 13 +++++++++++--
include/linux/pci.h | 2 ++
3 files changed, 16 insertions(+), 15 deletions(-)
@@ -93,6 +80,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)ACPI_COMPANION_SET(&bridge->dev,adev);set_dev_node(bus_dev,acpi_get_node(acpi_device_handle(adev)));++/* Try to assign the IRQ number when probing a new device */+bridge->alloc_irq=acpi_pci_irq_enable;}return0;
The acpi_pci_create_root_bus() can be fully integrated into
acpi_pci_root_create(), improving a few things:
* We can call pci_scan_root_bus_bridge(), which registers and
scans the bridge in one step.
* After a failure in pci_register_host_bridge(), we correctly
clean up the resources.
* The bridge settings (release function, flags, operations etc)
can get set up before registering the bridge.
* Further cleanup would be possible, removing duplication between
pci_host_bridge and some ACPI structures.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/acpi/pci_root.c | 68 +++++++++++++++--------------------------
1 file changed, 24 insertions(+), 44 deletions(-)
pcibios_scan_root() is now just a wrapper around pci_scan_root_bus(),
and merging the two into one makes it shorter and more readable.
We can also take advantage of pci_alloc_host_bridge() doing the
allocation of the sysdata for us, which helps if we ever want to
allow hot-unplugging the host bridge itself.
We might be able to simplify it further using pci_host_probe(),
but I wasn't sure about the resource registration there.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/x86/pci/common.c | 53 ++++++++++++++-----------------------------
1 file changed, 17 insertions(+), 36 deletions(-)
From: "Rafael J. Wysocki" <rafael@kernel.org> Date: 2018-08-20 08:23:27
On Fri, Aug 17, 2018 at 12:33 PM Arnd Bergmann [off-list ref] wrote:
quoted hunk
The acpi_pci_create_root_bus() can be fully integrated into
acpi_pci_root_create(), improving a few things:
* We can call pci_scan_root_bus_bridge(), which registers and
scans the bridge in one step.
* After a failure in pci_register_host_bridge(), we correctly
clean up the resources.
* The bridge settings (release function, flags, operations etc)
can get set up before registering the bridge.
* Further cleanup would be possible, removing duplication between
pci_host_bridge and some ACPI structures.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/acpi/pci_root.c | 68 +++++++++++++++--------------------------
1 file changed, 24 insertions(+), 44 deletions(-)
From: "Rafael J. Wysocki" <rafael@kernel.org> Date: 2018-08-20 08:31:52
On Fri, Aug 17, 2018 at 12:32 PM Arnd Bergmann [off-list ref] wrote:
quoted hunk
pcibios_scan_root() is now just a wrapper around pci_scan_root_bus(),
and merging the two into one makes it shorter and more readable.
We can also take advantage of pci_alloc_host_bridge() doing the
allocation of the sysdata for us, which helps if we ever want to
allow hot-unplugging the host bridge itself.
We might be able to simplify it further using pci_host_probe(),
but I wasn't sure about the resource registration there.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/x86/pci/common.c | 53 ++++++++++++++-----------------------------
1 file changed, 17 insertions(+), 36 deletions(-)
This looks fishy, as bridge->private is not set at this point AFAICS,
unless one of the previous patches changes that.
bridge->private what comes after the bridge structure, and it's allocated
by pci_alloc_host_bridge() passing the size of the structure we want
for this private area.
Arnd
Why "bridge" and not "host" or even something to stand for "root complex"?
Or maybe it can still be "host_bridge"?
I did this for consistency with the naming in drivers/pci/probe.c,
which always declares the local variable as 'struct pci_host_bridge *bridge'.
It's easy to change here if you feel strongly about it (I don't).
Arnd
Why "bridge" and not "host" or even something to stand for "root complex"?
Or maybe it can still be "host_bridge"?
I did this for consistency with the naming in drivers/pci/probe.c,
which always declares the local variable as 'struct pci_host_bridge *bridge'.
It's easy to change here if you feel strongly about it (I don't).
I would leave host_bridge here. It would make the patch smaller too I think.
This looks fishy, as bridge->private is not set at this point AFAICS,
unless one of the previous patches changes that.
bridge->private what comes after the bridge structure, and it's allocated
by pci_alloc_host_bridge() passing the size of the structure we want
for this private area.
Why "bridge" and not "host" or even something to stand for "root complex"?
Or maybe it can still be "host_bridge"?
I did this for consistency with the naming in drivers/pci/probe.c,
which always declares the local variable as 'struct pci_host_bridge *bridge'.
It's easy to change here if you feel strongly about it (I don't).
I would leave host_bridge here. It would make the patch smaller too I think.
Ok, I've changed my local copy as you suggested now.
Arnd
From: Christoph Hellwig <hch@infradead.org> Date: 2018-08-21 06:14:55
On Fri, Aug 17, 2018 at 12:26:30PM +0200, Arnd Bergmann wrote:
Hi Bjorn and others,
Triggered by Christoph's patches, I had another go at converting
all of the remaining pci host bridge implementations to be based
on pci_alloc_host_bridge and a separate registration function.
I really like the idea behind this series.
I'm adding a bit of duplication into the less maintained code
here, but it makes everything more consistent, and gives an
easy place to hook up callback functions etc.
I wonder if there is a way to avoid some of that by adding a few
more helpers, but even without the helpers that approach looks
ok to me.
Do you have a git tree somewhere to play around with the changes?
On Tue, Aug 21, 2018 at 8:14 AM Christoph Hellwig [off-list ref] wrote:
On Fri, Aug 17, 2018 at 12:26:30PM +0200, Arnd Bergmann wrote:
quoted
Hi Bjorn and others,
Triggered by Christoph's patches, I had another go at converting
all of the remaining pci host bridge implementations to be based
on pci_alloc_host_bridge and a separate registration function.
I really like the idea behind this series.
quoted
I'm adding a bit of duplication into the less maintained code
here, but it makes everything more consistent, and gives an
easy place to hook up callback functions etc.
I wonder if there is a way to avoid some of that by adding a few
more helpers, but even without the helpers that approach looks
ok to me.
Ok, thanks for taking a first look.
One core part that gets duplicated a lot (also in existing drivers)
is the chunk that could be handled by this:
int pci_host_bridge_init(struct pci_host_bridge *bridge,
struct device *parent, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resource_list)
{
if (resources)
list_splice_init(resources, &bridge->windows);
bridge->dev.parent = parent;
bridge->sysdata = sysdata;
bridge->busnr = bus;
bridge->ops = ops;
}
That would probably help, but we should think carefully about
the set of fields that we want pass here, specifically because the
idea of splitting the probing into two parts was to avoid having
to come up with a new interface every time that list changes
due to some rework.
For instance, the numa node is something that might get passed
here, and if we decide to split out the operations into a separate
pci_host_bridge_ops structure, the pointer to that would also
be something we'd want to pass this way.
Do you have a git tree somewhere to play around with the changes?
From: David Woodhouse <dwmw2@infradead.org> Date: 2018-08-21 12:57:26
On Mon, 2018-08-20 at 23:14 -0700, Christoph Hellwig wrote:
On Fri, Aug 17, 2018 at 12:26:30PM +0200, Arnd Bergmann wrote:
quoted
Hi Bjorn and others,
Triggered by Christoph's patches, I had another go at converting
all of the remaining pci host bridge implementations to be based
on pci_alloc_host_bridge and a separate registration function.
I really like the idea behind this series.
Hm... are you turning direct calls into retpolined indirect calls?
From: Christoph Hellwig <hch@infradead.org> Date: 2018-08-21 13:14:46
On Tue, Aug 21, 2018 at 12:30:50PM +0100, David Woodhouse wrote:
On Mon, 2018-08-20 at 23:14 -0700, Christoph Hellwig wrote:
quoted
On Fri, Aug 17, 2018 at 12:26:30PM +0200, Arnd Bergmann wrote:
quoted
Hi Bjorn and others,
Triggered by Christoph's patches, I had another go at converting
all of the remaining pci host bridge implementations to be based
on pci_alloc_host_bridge and a separate registration function.
I really like the idea behind this series.
Hm... are you turning direct calls into retpolined indirect calls?
On Fri, Aug 17, 2018 at 12:26:30PM +0200, Arnd Bergmann wrote:
Hi Bjorn and others,
Triggered by Christoph's patches, I had another go at converting
all of the remaining pci host bridge implementations to be based
on pci_alloc_host_bridge and a separate registration function.
This is made possible through work from Lorenzo and others to
convert many of the existing drivers, as well as the removal
of some of the older architectures that nobody used.
I'm adding a bit of duplication into the less maintained code
here, but it makes everything more consistent, and gives an
easy place to hook up callback functions etc.
The three parts of this series are:
a) push up the registration into the callers (this is where
code gets added)
b) clean up some of the more common host bridge
implementations again to integrate that code better.
This could be done for the rest as well, or we could just
leave them alone.
c) start moving the __weak functions into callbacks in
pci_host_bridge. This is intentionally incomplete, since
it is a lot of work to do it for all those functions,
and I want to get consensus on the approach first, as well
as maybe get other developers to help out with the rest.
Please have a look.
Arnd
[1] https://lore.kernel.org/lkml/4288331.jNpl6KXlNO@wuerfel/
[2] https://patchwork.kernel.org/patch/10555657/
Arnd Bergmann (15):
PCI: clean up legacy host bridge scan functions
PCI: move pci_scan_bus into callers
PCI: move pci_scan_root_bus into callers
PCI: export pci_register_host_bridge
PCI: move pci_create_root_bus into callers
powerpc/pci: fold pci_create_root_bus into pcibios_scan_phb
PCI/ACPI: clean up acpi_pci_root_create()
x86: PCI: clean up pcibios_scan_root()
PCI: xenfront: clean up pcifront_scan_root()
sparc/PCI: simplify pci_scan_one_pbm
PCI: hyperv: convert to pci_scan_root_bus_bridge
PCI: make pcibios_bus_add_device() a callback function
PCI: turn pcibios_alloc_irq into a callback
PCI: make pcibios_root_bridge_prepare a callback
PCI: make pcibios_add_bus/remove_bus callbacks
arch/arm64/kernel/pci.c | 40 ++-----
arch/ia64/pci/pci.c | 25 +----
arch/ia64/sn/kernel/io_init.c | 27 +++++
arch/microblaze/pci/pci-common.c | 27 +++++
arch/powerpc/include/asm/pci-bridge.h | 3 +
arch/powerpc/kernel/pci-common.c | 60 +++++------
arch/s390/pci/pci.c | 30 +++++-
arch/sh/drivers/pci/pci.c | 1 +
arch/sh/drivers/pci/pcie-sh7786.c | 3 +-
arch/sh/include/asm/pci.h | 2 +
arch/sparc/kernel/pci.c | 40 ++++---
arch/sparc/kernel/pcic.c | 35 ++++++
arch/x86/pci/acpi.c | 15 +--
arch/x86/pci/common.c | 42 ++++----
arch/xtensa/kernel/pci.c | 27 +++++
drivers/acpi/pci_root.c | 43 +++++---
drivers/parisc/dino.c | 28 +++++
drivers/parisc/lba_pci.c | 28 +++++
drivers/pci/bus.c | 8 +-
drivers/pci/controller/pci-hyperv.c | 47 ++++----
drivers/pci/controller/vmd.c | 30 +++++-
drivers/pci/hotplug/ibmphp_core.c | 35 ++++++
drivers/pci/pci-driver.c | 13 ++-
drivers/pci/probe.c | 150 +++++++++-----------------
drivers/pci/xen-pcifront.c | 40 +++----
include/linux/acpi.h | 2 +
include/linux/pci.h | 17 ++-
27 files changed, 514 insertions(+), 304 deletions(-)
Sorry for the late response to this.
I think I'm generally on-board with this. I admit I'm a little
hesitant about adding 200 lines of code when this is really more
"cleanup" than new functionality, but I think a lot of that is because
this series contains costs (e.g., duplicating code) for everybody but
only has the corresponding benefits for a few (ACPI, x86, xenfront).
Those cases are much closer to parity in terms of lines added/removed.
I saw some minor comments that suggested you had some updates, so I'll
watch for an updated posting.
Bjorn