From 97ad2bdcbe8598a69ee1f372ed6c0fbdb2869218 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 28 Jun 2017 15:13:55 -0500 Subject: ARM/PCI: Convert PCI scan API to pci_scan_root_bus_bridge() The introduction of pci_scan_root_bus_bridge() provides a PCI core API to scan a PCI root bus backed by an already initialized struct pci_host_bridge object, which simplifies the bus scan interface and makes the PCI scan root bus interface easier to generalize as members are added to the struct pci_host_bridge. Convert ARM bios32 code to pci_scan_root_bus_bridge() to improve the PCI root bus scanning interface. Signed-off-by: Lorenzo Pieralisi [bhelgaas: fold in warning fix from Arnd Bergmann : http://lkml.kernel.org/r/20170621215323.3921382-1-arnd@arndb.de] [bhelgaas: set bridge->ops for mv78xx0] [bhelgaas: fold in fixes from Lorenzo Pieralisi : http://lkml.kernel.org/r/20170701135457.GB8977@red-moon] Signed-off-by: Bjorn Helgaas Cc: Jason Cooper Cc: Russell King Cc: Andrew Lunn --- arch/arm/include/asm/mach/pci.h | 3 ++- arch/arm/kernel/bios32.c | 39 +++++++++++++++++++++++++-------------- arch/arm/mach-dove/pcie.c | 17 ++++++++++++----- arch/arm/mach-iop13xx/pci.c | 31 ++++++++++++++++++++----------- arch/arm/mach-iop13xx/pci.h | 3 ++- arch/arm/mach-mv78xx0/pcie.c | 16 +++++++++++----- arch/arm/mach-orion5x/common.h | 3 ++- arch/arm/mach-orion5x/pci.c | 25 +++++++++++++++++-------- 8 files changed, 91 insertions(+), 46 deletions(-) (limited to 'arch') diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h index 2d88af5be45f..233b4b50eff3 100644 --- a/arch/arm/include/asm/mach/pci.h +++ b/arch/arm/include/asm/mach/pci.h @@ -16,6 +16,7 @@ struct pci_sys_data; struct pci_ops; struct pci_bus; +struct pci_host_bridge; struct device; struct hw_pci { @@ -25,7 +26,7 @@ struct hw_pci { unsigned int io_optional:1; void **private_data; int (*setup)(int nr, struct pci_sys_data *); - struct pci_bus *(*scan)(int nr, struct pci_sys_data *); + int (*scan)(int nr, struct pci_host_bridge *); void (*preinit)(void); void (*postinit)(void); u8 (*swizzle)(struct pci_dev *dev, u8 *pin); diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index b259956365a0..4c7621ac389c 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -458,10 +458,14 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, int nr, busnr; for (nr = busnr = 0; nr < hw->nr_controllers; nr++) { - sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL); - if (WARN(!sys, "PCI: unable to allocate sys data!")) + struct pci_host_bridge *bridge; + + bridge = pci_alloc_host_bridge(sizeof(struct pci_sys_data)); + if (WARN(!bridge, "PCI: unable to allocate bridge!")) break; + sys = pci_host_bridge_priv(bridge); + sys->busnr = busnr; sys->swizzle = hw->swizzle; sys->map_irq = hw->map_irq; @@ -473,7 +477,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, ret = hw->setup(nr, sys); if (ret > 0) { - struct pci_host_bridge *host_bridge; ret = pcibios_init_resource(nr, sys, hw->io_optional); if (ret) { @@ -482,25 +485,33 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, } if (hw->scan) - sys->bus = hw->scan(nr, sys); - else - sys->bus = pci_scan_root_bus_msi(parent, - sys->busnr, hw->ops, sys, - &sys->resources, hw->msi_ctrl); + ret = hw->scan(nr, bridge); + else { + list_splice_init(&sys->resources, + &bridge->windows); + bridge->dev.parent = parent; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + bridge->ops = hw->ops; + bridge->msi = hw->msi_ctrl; + bridge->align_resource = + hw->align_resource; + + ret = pci_scan_root_bus_bridge(bridge); + } - if (WARN(!sys->bus, "PCI: unable to scan bus!")) { - kfree(sys); + if (WARN(ret < 0, "PCI: unable to scan bus!")) { + pci_free_host_bridge(bridge); break; } + sys->bus = bridge->bus; + busnr = sys->bus->busn_res.end + 1; list_add(&sys->node, head); - - host_bridge = pci_find_host_bridge(sys->bus); - host_bridge->align_resource = hw->align_resource; } else { - kfree(sys); + pci_free_host_bridge(bridge); if (ret < 0) break; } diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c index 91fe97144570..dfb62f3f5dcf 100644 --- a/arch/arm/mach-dove/pcie.c +++ b/arch/arm/mach-dove/pcie.c @@ -152,16 +152,23 @@ static void rc_pci_fixup(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); -static struct pci_bus __init * -dove_pcie_scan_bus(int nr, struct pci_sys_data *sys) +static int __init +dove_pcie_scan_bus(int nr, struct pci_host_bridge *bridge) { + struct pci_sys_data *sys = pci_host_bridge_priv(bridge); + if (nr >= num_pcie_ports) { BUG(); - return NULL; + return -EINVAL; } - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, - &sys->resources); + list_splice_init(&sys->resources, &bridge->windows); + bridge->dev.parent = NULL; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + bridge->ops = &pcie_ops; + + return pci_scan_root_bus_bridge(bridge); } static int __init dove_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c index 204eb4460271..070d92ae1b6f 100644 --- a/arch/arm/mach-iop13xx/pci.c +++ b/arch/arm/mach-iop13xx/pci.c @@ -504,10 +504,10 @@ iop13xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) /* Scan an IOP13XX PCI bus. nr selects which ATU we use. */ -struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys) +int iop13xx_scan_bus(int nr, struct pci_host_bridge *bridge) { - int which_atu; - struct pci_bus *bus = NULL; + int which_atu, ret; + struct pci_sys_data *sys = pci_host_bridge_priv(bridge); switch (init_atu) { case IOP13XX_INIT_ATU_ATUX: @@ -525,9 +525,14 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys) if (!which_atu) { BUG(); - return NULL; + return -ENODEV; } + list_splice_init(&sys->resources, &bridge->windows); + bridge->dev.parent = NULL; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + switch (which_atu) { case IOP13XX_INIT_ATU_ATUX: if (time_after_eq(jiffies + msecs_to_jiffies(1000), @@ -535,18 +540,22 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys) while(time_before(jiffies, atux_trhfa_timeout)) udelay(100); - bus = pci_bus_atux = pci_scan_root_bus(NULL, sys->busnr, - &iop13xx_atux_ops, - sys, &sys->resources); + bridge->ops = &iop13xx_atux_ops; + ret = pci_scan_root_bus_bridge(bridge); + if (!ret) + pci_bus_atux = bridge->bus; break; case IOP13XX_INIT_ATU_ATUE: - bus = pci_bus_atue = pci_scan_root_bus(NULL, sys->busnr, - &iop13xx_atue_ops, - sys, &sys->resources); + bridge->ops = &iop13xx_atue_ops; + ret = pci_scan_root_bus_bridge(bridge); + if (!ret) + pci_bus_atue = bridge->bus; break; + default: + ret = -EINVAL; } - return bus; + return ret; } /* This function is called from iop13xx_pci_init() after assigning valid diff --git a/arch/arm/mach-iop13xx/pci.h b/arch/arm/mach-iop13xx/pci.h index 71b9c57e1fde..8dc343cb887a 100644 --- a/arch/arm/mach-iop13xx/pci.h +++ b/arch/arm/mach-iop13xx/pci.h @@ -11,9 +11,10 @@ extern size_t iop13xx_atue_mem_size; extern size_t iop13xx_atux_mem_size; struct pci_sys_data; +struct pci_host_bridge; struct hw_pci; int iop13xx_pci_setup(int nr, struct pci_sys_data *sys); -struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *); +int iop13xx_scan_bus(int nr, struct pci_host_bridge *bridge); void iop13xx_atu_select(struct hw_pci *plat_pci); void iop13xx_pci_init(void); void iop13xx_map_pci_memory(void); diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c index 81ff4327a962..636d84b40466 100644 --- a/arch/arm/mach-mv78xx0/pcie.c +++ b/arch/arm/mach-mv78xx0/pcie.c @@ -194,16 +194,22 @@ static void rc_pci_fixup(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); -static struct pci_bus __init * -mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys) +static int __init mv78xx0_pcie_scan_bus(int nr, struct pci_host_bridge *bridge) { + struct pci_sys_data *sys = pci_host_bridge_priv(bridge); + if (nr >= num_pcie_ports) { BUG(); - return NULL; + return -EINVAL; } - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, - &sys->resources); + list_splice_init(&sys->resources, &bridge->windows); + bridge->dev.parent = NULL; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + bridge->ops = &pcie_ops; + + return pci_scan_root_bus_bridge(bridge); } static int __init mv78xx0_pcie_map_irq(const struct pci_dev *dev, u8 slot, diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h index efeffc6b4ebb..4c0c7de665c3 100644 --- a/arch/arm/mach-orion5x/common.h +++ b/arch/arm/mach-orion5x/common.h @@ -54,6 +54,7 @@ void orion5x_restart(enum reboot_mode, const char *); * PCIe/PCI functions. */ struct pci_bus; +struct pci_host_bridge; struct pci_sys_data; struct pci_dev; @@ -61,7 +62,7 @@ void orion5x_pcie_id(u32 *dev, u32 *rev); void orion5x_pci_disable(void); void orion5x_pci_set_cardbus_mode(void); int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys); -struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys); +int orion5x_pci_sys_scan_bus(int nr, struct pci_host_bridge *bridge); int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); struct tag; diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index ecb998e7f8dc..76951bfbacf5 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -555,18 +555,27 @@ int __init orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys) return 0; } -struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys) +int __init orion5x_pci_sys_scan_bus(int nr, struct pci_host_bridge *bridge) { - if (nr == 0) - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, - &sys->resources); + struct pci_sys_data *sys = pci_host_bridge_priv(bridge); - if (nr == 1 && !orion5x_pci_disabled) - return pci_scan_root_bus(NULL, sys->busnr, &pci_ops, sys, - &sys->resources); + list_splice_init(&sys->resources, &bridge->windows); + bridge->dev.parent = NULL; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + + if (nr == 0) { + bridge->ops = &pcie_ops; + return pci_scan_root_bus_bridge(bridge); + } + + if (nr == 1 && !orion5x_pci_disabled) { + bridge->ops = &pci_ops; + return pci_scan_root_bus_bridge(bridge); + } BUG(); - return NULL; + return -ENODEV; } int __init orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -- cgit v1.2.3 From 16508469c0f3198a63923aaec08efa1c63f5fbcc Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 28 Jun 2017 15:14:04 -0500 Subject: ARM/PCI: Remove pci_fixup_irqs() call for bios32 host controllers Legacy PCI host controllers (ie host controllers that set-up the PCI bus through the ARM pci_common_init() API) are currently relying on pci_fixup_irqs() to assign legacy PCI irqs to devices. This is not ideal in that pci_fixup_irqs() assigns IRQs for all PCI devices present in a given system some of which may well be enabled by the time pci_fixup_irqs() is called (ie a system with multiple host controllers). With the introduction of struct pci_host_bridge.(*map_irq) pointer it is possible to assign IRQs for all devices originating from a PCI host bridge at probe time; this is implemented through pci_assign_irq() that relies on the struct pci_host_bridge.map_irq pointer to map IRQ for a given device. The benefits this brings are twofold: - the IRQ for a device is assigned once at probe time - the IRQ assignment works also for hotplugged devices Remove pci_fixup_irqs() call from bios32 code and rely on pci_assign_irq() to carry out the IRQ mapping at device probe time. The map_irq() and swizzle_irq() struct pci_host_bridge callbacks are set-up in the struct pci_host_bridge created in the bios32 pcibios_init_hw() function and mach-* code paths (for PCI mach implementations that require a specific struct hw_pci.(*scan) function callback). Signed-off-by: Lorenzo Pieralisi [bhelgaas: folded in fixes from Lorenzo: http://lkml.kernel.org/r/20170701140629.GC8977@red-moon] Signed-off-by: Bjorn Helgaas Cc: Jason Cooper Cc: Russell King Cc: Andrew Lunn --- arch/arm/kernel/bios32.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 4c7621ac389c..56dc1a3a33b4 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -484,6 +484,9 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, break; } + bridge->map_irq = pcibios_map_irq; + bridge->swizzle_irq = pcibios_swizzle; + if (hw->scan) ret = hw->scan(nr, bridge); else { @@ -530,8 +533,6 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw) if (hw->postinit) hw->postinit(); - pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); - list_for_each_entry(sys, &head, node) { struct pci_bus *bus = sys->bus; -- cgit v1.2.3 From 769b461fc0c0451bacf75826d5830fc07c5a57e4 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 28 Jun 2017 15:14:12 -0500 Subject: arm64: PCI: Drop DT IRQ allocation from pcibios_alloc_irq() With the introduction of struct pci_host_bridge.map_irq pointer it is possible to assign IRQs for all devices originating from a PCI host bridge at probe time; this is implemented through pci_assign_irq() that relies on the struct pci_host_bridge.map_irq pointer to map IRQ for a given device. The benefits this brings are twofold: - the IRQ for a device is assigned once at probe time - the IRQ assignment works also for hotplugged devices With all DT based PCI host bridges converted to the struct pci_host_bridge.{map/swizzle}_irq hooks mechanism the DT IRQ allocation in ARM64 pcibios_alloc_irq() is now redundant and can be removed. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Will Deacon --- arch/arm64/kernel/pci.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 4f0e3ebfea4b..efcc351c518f 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -39,20 +39,18 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, return res->start; } +#ifdef CONFIG_ACPI /* * Try to assign the IRQ number when probing a new device */ int pcibios_alloc_irq(struct pci_dev *dev) { - if (acpi_disabled) - dev->irq = of_irq_parse_and_map_pci(dev, 0, 0); -#ifdef CONFIG_ACPI - else - return acpi_pci_irq_enable(dev); -#endif + if (!acpi_disabled) + acpi_pci_irq_enable(dev); return 0; } +#endif /* * raw_pci_read/write - Platform-specific PCI config space access. -- cgit v1.2.3