[RFC/RFT PATCH 18/18] ARM/ARM64: PCI: Drop pci_fixup_irqs() usage for DT based host controllers
Lorenzo Pieralisi
lorenzo.pieralisi at arm.com
Wed Apr 26 07:18:09 EDT 2017
DT based PCI host controllers are currently relying on
pci_fixup_irqs() to assign legacy PCI irqs to devices. This is
broken in that pci_fixup_irqs() assign 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 all DT based PCI host controller
drivers. The map_irq() and swizzle_irq() struct pci_host_bridge callbacks
are either set-up in the respective PCI host controller driver or
delegated to ARM/ARM64 pcibios_root_bridge_prepare() implementations,
where, upon DT probe detection, the functions are set to DT defaults (ie
of_irq_parse_and_map_pci() and pci_common_swizzle() respectively.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi at arm.com>
Cc: Will Deacon <will.deacon at arm.com>
Cc: Jingoo Han <jingoohan1 at gmail.com>
Cc: Bjorn Helgaas <bhelgaas at google.com>
Cc: Rob Herring <robh at kernel.org>
Cc: Simon Horman <horms at verge.net.au>
Cc: Bharat Kumar Gogada <bharat.kumar.gogada at xilinx.com>
Cc: Ray Jui <rjui at broadcom.com>
Cc: Joao Pinto <Joao.Pinto at synopsys.com>
Cc: Thierry Reding <thierry.reding at gmail.com>
Cc: Michal Simek <michal.simek at xilinx.com>
Cc: Ley Foon Tan <lftan at altera.com>
---
arch/arm/kernel/bios32.c | 25 ++++++++++++++++++++
arch/arm64/kernel/pci.c | 32 ++++++++++++++++++++-----
drivers/pci/dwc/pcie-designware-host.c | 5 ----
drivers/pci/host/pci-host-common.c | 4 ----
drivers/pci/host/pci-tegra.c | 3 ++-
drivers/pci/host/pci-versatile.c | 1 -
drivers/pci/host/pcie-altera.c | 1 -
drivers/pci/host/pcie-iproc.c | 43 ++++++++++++++++++++++------------
drivers/pci/host/pcie-rcar.c | 2 --
drivers/pci/host/pcie-xilinx.c | 3 ---
10 files changed, 81 insertions(+), 38 deletions(-)
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index a5b6d4f..09b2278 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -8,6 +8,7 @@
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/of_pci.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -527,6 +528,30 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
}
}
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ /*
+ * Set-up IRQ mapping/swizzingly functions.
+ * If the either function pointer is already set,
+ * do not override any of them since it is a host
+ * controller specific mapping/swizzling function.
+ */
+ if (!bridge->map_irq && !bridge->swizzle_irq) {
+ struct device *parent = bridge->dev.parent;
+ /*
+ * If we have a parent pointer with a valid
+ * OF node this means we are probing a PCI host
+ * controller configured through DT firmware.
+ */
+ if (IS_ENABLED(CONFIG_OF) && parent && parent->of_node) {
+ bridge->map_irq = of_irq_parse_and_map_pci;
+ bridge->swizzle_irq = pci_common_swizzle;
+ }
+ }
+
+ return 0;
+}
+
void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
{
struct pci_sys_data *sys;
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index 4f0e3eb..a680dcc 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.
@@ -105,12 +103,34 @@ int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
+ struct device *parent = bridge->dev.parent;
+
if (!acpi_disabled) {
struct pci_config_window *cfg = bridge->bus->sysdata;
struct acpi_device *adev = to_acpi_device(cfg->parent);
ACPI_COMPANION_SET(&bridge->dev, adev);
}
+ /*
+ * DT and ACPI systems use different mechanism to set-up legacy
+ * IRQs. Through the bridge map_irq and swizzle_irq function
+ * pointer we are capable of setting up legacy IRQs on DT systems,
+ * check if we are probing a DT based host controller and initialize
+ * the host bridge mapping/swizzling IRQ function accordingly.
+ */
+ if (parent && parent->of_node) {
+ /*
+ * Set-up IRQ mapping/swizzingly functions.
+ * If the either function pointer is already set,
+ * do not override any of them since it is a host
+ * controller specific mapping/swizzling function.
+ */
+ if (!bridge->map_irq && !bridge->swizzle_irq) {
+ bridge->map_irq = of_irq_parse_and_map_pci;
+ bridge->swizzle_irq = pci_common_swizzle;
+ }
+ }
+
return 0;
}
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index e43c21a..8eeddb9 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -421,11 +421,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
if (pp->ops->scan_bus)
pp->ops->scan_bus(pp);
-#ifdef CONFIG_ARM
- /* support old dtbs that incorrectly describe IRQs */
- pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
-#endif
-
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
index e9a53ba..3e8fb57 100644
--- a/drivers/pci/host/pci-host-common.c
+++ b/drivers/pci/host/pci-host-common.c
@@ -145,10 +145,6 @@ int pci_host_common_probe(struct platform_device *pdev,
return -ENODEV;
}
-#ifdef CONFIG_ARM
- pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
-#endif
-
/*
* We insert PCI resources into the iomem_resource and
* ioport_resource trees in either pci_bus_claim_resources()
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index ed8a93f..0527a89 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -2284,6 +2284,8 @@ static int tegra_pcie_probe(struct platform_device *pdev)
host->busnr = pcie->busn.start;
host->dev.parent = &pdev->dev;
host->ops = &tegra_pcie_ops;
+ host->map_irq = tegra_pcie_map_irq;
+ host->swizzle_irq = pci_common_swizzle;
err = pci_register_host_bridge(host);
if (err < 0) {
@@ -2293,7 +2295,6 @@ static int tegra_pcie_probe(struct platform_device *pdev)
pci_scan_child_bus(host->bus);
- pci_fixup_irqs(pci_common_swizzle, tegra_pcie_map_irq);
pci_bus_size_bridges(host->bus);
pci_bus_assign_resources(host->bus);
diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c
index 5ebee7d..c364b6a8 100644
--- a/drivers/pci/host/pci-versatile.c
+++ b/drivers/pci/host/pci-versatile.c
@@ -202,7 +202,6 @@ static int versatile_pci_probe(struct platform_device *pdev)
if (!bus)
return -ENOMEM;
- pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
pci_assign_unassigned_bus_resources(bus);
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child);
diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c
index 75ec5ce..0550f9d 100644
--- a/drivers/pci/host/pcie-altera.c
+++ b/drivers/pci/host/pcie-altera.c
@@ -618,7 +618,6 @@ static int altera_pcie_probe(struct platform_device *pdev)
if (!bus)
return -ENOMEM;
- pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
pci_assign_unassigned_bus_resources(bus);
/* Configure PCI Express setting. */
diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c
index 0f39bd2..bc9e36a 100644
--- a/drivers/pci/host/pcie-iproc.c
+++ b/drivers/pci/host/pcie-iproc.c
@@ -1205,7 +1205,8 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
struct device *dev;
int ret;
void *sysdata;
- struct pci_bus *bus, *child;
+ struct pci_bus *child;
+ struct pci_host_bridge *host;
dev = pcie->dev;
@@ -1252,15 +1253,30 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
sysdata = pcie;
#endif
- bus = pci_create_root_bus(dev, 0, &iproc_pcie_ops, sysdata, res);
- if (!bus) {
- dev_err(dev, "unable to create PCI root bus\n");
+ host = pci_alloc_host_bridge(0);
+ if (!host) {
+ dev_err(dev, "unable to allocate PCI host bridge\n");
ret = -ENOMEM;
goto err_power_off_phy;
}
- pcie->root_bus = bus;
- ret = iproc_pcie_check_link(pcie, bus);
+ list_splice_init(res, &host->windows);
+ host->busnr = 0;
+ host->dev.parent = dev;
+ host->ops = &iproc_pcie_ops;
+ host->sysdata = sysdata;
+ host->map_irq = pcie->map_irq;
+ host->swizzle_irq = pci_common_swizzle;
+
+ ret = pci_register_host_bridge(host);
+ if (ret < 0) {
+ dev_err(dev, "failed to register host: %d\n", ret);
+ goto err_power_off_phy;
+ }
+
+ pcie->root_bus = host->bus;
+
+ ret = iproc_pcie_check_link(pcie, host->bus);
if (ret) {
dev_err(dev, "no PCIe EP device detected\n");
goto err_rm_root_bus;
@@ -1272,22 +1288,19 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
if (iproc_pcie_msi_enable(pcie))
dev_info(dev, "not using iProc MSI\n");
- pci_scan_child_bus(bus);
- pci_assign_unassigned_bus_resources(bus);
-
- if (pcie->map_irq)
- pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
+ pci_scan_child_bus(host->bus);
+ pci_assign_unassigned_bus_resources(host->bus);
- list_for_each_entry(child, &bus->children, node)
+ list_for_each_entry(child, &host->bus->children, node)
pcie_bus_configure_settings(child);
- pci_bus_add_devices(bus);
+ pci_bus_add_devices(host->bus);
return 0;
err_rm_root_bus:
- pci_stop_root_bus(bus);
- pci_remove_root_bus(bus);
+ pci_stop_root_bus(host->bus);
+ pci_remove_root_bus(host->bus);
err_power_off_phy:
phy_power_off(pcie->phy);
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 051b4db..d8b3679 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -480,8 +480,6 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie)
bus = bridge->bus;
- pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
-
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c
index 7f030f5..22e7f61 100644
--- a/drivers/pci/host/pcie-xilinx.c
+++ b/drivers/pci/host/pcie-xilinx.c
@@ -683,9 +683,6 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
#endif
pci_scan_child_bus(bus);
pci_assign_unassigned_bus_resources(bus);
-#ifndef CONFIG_MICROBLAZE
- pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
-#endif
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child);
pci_bus_add_devices(bus);
--
2.10.0
More information about the linux-arm-kernel
mailing list