From 17d7acc8e1c81f8125730aa900c67412a2ac69e2 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 28 May 2014 15:18:45 +0530 Subject: [PATCH 01/10] PCI: exynos: Fix add_pcie_port() section mismatch warning add_pcie_port() is called only from exynos_pcie_probe(), which is annotated with __init. Thus it makes sense to annotate add_pcie_port() with __init to avoid the following section mismatch warning: WARNING: drivers/pci/built-in.o(.text.unlikely+0xf8): Section mismatch in reference from the function add_pcie_port() to the function .init.text:dw_pcie_host_init() The function add_pcie_port() references the function __init dw_pcie_host_init(). This is often because add_pcie_port lacks a __init annotation or the annotation of dw_pcie_host_init is wrong. [bhelgaas: changelog] Reported-by: kbuild test robot Signed-off-by: Sachin Kamat Signed-off-by: Bjorn Helgaas Acked-by: Jingoo Han --- drivers/pci/host/pci-exynos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index 81aa700a8ada..2c4b27cb4f6c 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -511,7 +511,8 @@ static struct pcie_host_ops exynos_pcie_host_ops = { .host_init = exynos_pcie_host_init, }; -static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) +static int __init add_pcie_port(struct pcie_port *pp, + struct platform_device *pdev) { int ret; From c893d133eaccdda2516a3e71cd05a7dac2e14b00 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 30 May 2014 11:01:03 +0800 Subject: [PATCH 02/10] PCI: Make pci_bus_add_device() void pci_bus_add_device() always returns 0, so there's no point in returning anything at all. Make it a void function and remove the tests of the return value from the callers. [bhelgaas: changelog, remove unused "err" from i82875p_setup_overfl_dev()] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/edac/i82875p_edac.c | 8 +------- drivers/pci/bus.c | 10 ++-------- drivers/pci/iov.c | 2 +- drivers/platform/x86/asus-wmi.c | 3 +-- drivers/platform/x86/eeepc-laptop.c | 3 +-- include/linux/pci.h | 2 +- 6 files changed, 7 insertions(+), 21 deletions(-) diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 8d0450b9b9af..4009077c8839 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -275,7 +275,6 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, { struct pci_dev *dev; void __iomem *window; - int err; *ovrfl_pdev = NULL; *ovrfl_window = NULL; @@ -293,12 +292,7 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, if (dev == NULL) return 1; - err = pci_bus_add_device(dev); - if (err) { - i82875p_printk(KERN_ERR, - "%s(): pci_bus_add_device() Failed\n", - __func__); - } + pci_bus_add_device(dev); pci_bus_assign_resources(dev->bus); } diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index ba2bf55a38df..447d393725e1 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -235,7 +235,7 @@ void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } * * This adds add sysfs entries and start device drivers */ -int pci_bus_add_device(struct pci_dev *dev) +void pci_bus_add_device(struct pci_dev *dev) { int retval; @@ -252,8 +252,6 @@ int pci_bus_add_device(struct pci_dev *dev) WARN_ON(retval < 0); dev->is_added = 1; - - return 0; } /** @@ -266,16 +264,12 @@ void pci_bus_add_devices(const struct pci_bus *bus) { struct pci_dev *dev; struct pci_bus *child; - int retval; list_for_each_entry(dev, &bus->devices, bus_list) { /* Skip already-added devices */ if (dev->is_added) continue; - retval = pci_bus_add_device(dev); - if (retval) - dev_err(&dev->dev, "Error adding device (%d)\n", - retval); + pci_bus_add_device(dev); } list_for_each_entry(dev, &bus->devices, bus_list) { diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index de7a74782f92..cb6f24740ee3 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -106,7 +106,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); - rc = pci_bus_add_device(virtfn); + pci_bus_add_device(virtfn); sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); if (rc) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index c5e082fb82fa..91ef69a52263 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -642,8 +642,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus) dev = pci_scan_single_device(bus, 0); if (dev) { pci_bus_assign_resources(bus); - if (pci_bus_add_device(dev)) - pr_err("Unable to hotplug wifi\n"); + pci_bus_add_device(dev); } } else { dev = pci_get_slot(bus, 0); diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 399e8c562192..9b0c57cd1d4a 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -633,8 +633,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) dev = pci_scan_single_device(bus, 0); if (dev) { pci_bus_assign_resources(bus); - if (pci_bus_add_device(dev)) - pr_err("Unable to hotplug wifi\n"); + pci_bus_add_device(dev); } } else { dev = pci_get_slot(bus, 0); diff --git a/include/linux/pci.h b/include/linux/pci.h index 322335aaa7e1..785149a6aec1 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -764,7 +764,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn); void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); unsigned int pci_scan_child_bus(struct pci_bus *bus); -int __must_check pci_bus_add_device(struct pci_dev *dev); +void pci_bus_add_device(struct pci_dev *dev); void pci_read_bridge_bases(struct pci_bus *child); struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); From 44cb5e94f96cef72a977fc5fdea8095bc0ae25ba Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 30 May 2014 12:08:48 +0530 Subject: [PATCH 03/10] PCI: imx6: Fix imx6_add_pcie_port() section mismatch warning imx6_add_pcie_port() is called only from from imx6_pcie_probe() which is annotated with __init. Thus it makes sense to annotate imx6_add_pcie_port() with __init to avoid section mismatch warnings. [bhelgaas: changelog] Signed-off-by: Sachin Kamat Signed-off-by: Bjorn Helgaas Cc: Sean Cross --- drivers/pci/host/pci-imx6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index ee082509b0ba..facbf8faa353 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -487,7 +487,7 @@ static struct pcie_host_ops imx6_pcie_host_ops = { .host_init = imx6_pcie_host_init, }; -static int imx6_add_pcie_port(struct pcie_port *pp, +static int __init imx6_add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) { int ret; From 8b5742ad156d30ee38486652cdbd152e2d6ebbcc Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Wed, 28 May 2014 13:14:53 -0400 Subject: [PATCH 04/10] ARM/PCI: Call pcie_bus_configure_settings() to set MPS Call pcie_bus_configure_settings() on ARM, like for other platforms. pcie_bus_configure_settings() makes sure the MPS across the bus is uniform and provides the ability to tune the MRSS and MPS to higher performance values. This is particularly important for embedded where there is no firmware to program these PCIe settings for the OS. Signed-off-by: Murali Karicheri Signed-off-by: Bjorn Helgaas CC: Russell King CC: Arnd Bergmann CC: Jason Gunthorpe CC: Santosh Shilimkar --- arch/arm/kernel/bios32.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 16d43cd45619..17a26c17f7f5 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -545,6 +545,18 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw) */ pci_bus_add_devices(bus); } + + list_for_each_entry(sys, &head, node) { + struct pci_bus *bus = sys->bus; + + /* Configure PCI Express settings */ + if (bus && !pci_has_flag(PCI_PROBE_ONLY)) { + struct pci_bus *child; + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + } + } } #ifndef CONFIG_PCI_HOST_ITE8152 From 06b00514b7f931eb94e3f56009ece8ae55488150 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 7 May 2013 16:29:31 -0700 Subject: [PATCH 05/10] i82875p_edac: Assign PCI resources before adding device Assign PCI resources before pci_bus_add_device(). The resources must be assigned before a driver can claim the device. [bhelgaas: changelog] Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/edac/i82875p_edac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 8d0450b9b9af..f2b9ac9ed9f3 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -293,13 +293,14 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, if (dev == NULL) return 1; + pci_bus_assign_resources(dev->bus); + err = pci_bus_add_device(dev); if (err) { i82875p_printk(KERN_ERR, "%s(): pci_bus_add_device() Failed\n", __func__); } - pci_bus_assign_resources(dev->bus); } *ovrfl_pdev = dev; From 57526136532408bacf2f68c26027abc2924b45d1 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 28 Mar 2014 17:52:55 +0100 Subject: [PATCH 06/10] PCI: imx6: Use new clock names As defined in the new binding. Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Richard Zhu --- drivers/pci/host/pci-imx6.c | 74 +++++++++++++++---------------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index facbf8faa353..e080ae326ba6 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -35,10 +35,9 @@ struct imx6_pcie { int power_on_gpio; int wake_up_gpio; int disable_gpio; - struct clk *lvds_gate; - struct clk *sata_ref_100m; - struct clk *pcie_ref_125m; - struct clk *pcie_axi; + struct clk *pcie_bus; + struct clk *pcie_phy; + struct clk *pcie; struct pcie_port pp; struct regmap *iomuxc_gpr; void __iomem *mem_base; @@ -239,28 +238,22 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); - ret = clk_prepare_enable(imx6_pcie->sata_ref_100m); + ret = clk_prepare_enable(imx6_pcie->pcie_phy); if (ret) { - dev_err(pp->dev, "unable to enable sata_ref_100m\n"); - goto err_sata_ref; + dev_err(pp->dev, "unable to enable pcie_phy clock\n"); + goto err_pcie_phy; } - ret = clk_prepare_enable(imx6_pcie->pcie_ref_125m); + ret = clk_prepare_enable(imx6_pcie->pcie_bus); if (ret) { - dev_err(pp->dev, "unable to enable pcie_ref_125m\n"); - goto err_pcie_ref; + dev_err(pp->dev, "unable to enable pcie_bus clock\n"); + goto err_pcie_bus; } - ret = clk_prepare_enable(imx6_pcie->lvds_gate); + ret = clk_prepare_enable(imx6_pcie->pcie); if (ret) { - dev_err(pp->dev, "unable to enable lvds_gate\n"); - goto err_lvds_gate; - } - - ret = clk_prepare_enable(imx6_pcie->pcie_axi); - if (ret) { - dev_err(pp->dev, "unable to enable pcie_axi\n"); - goto err_pcie_axi; + dev_err(pp->dev, "unable to enable pcie clock\n"); + goto err_pcie; } /* allow the clocks to stabilize */ @@ -274,13 +267,11 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) } return 0; -err_pcie_axi: - clk_disable_unprepare(imx6_pcie->lvds_gate); -err_lvds_gate: - clk_disable_unprepare(imx6_pcie->pcie_ref_125m); -err_pcie_ref: - clk_disable_unprepare(imx6_pcie->sata_ref_100m); -err_sata_ref: +err_pcie: + clk_disable_unprepare(imx6_pcie->pcie_bus); +err_pcie_bus: + clk_disable_unprepare(imx6_pcie->pcie_phy); +err_pcie_phy: return ret; } @@ -583,32 +574,25 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) } /* Fetch clocks */ - imx6_pcie->lvds_gate = devm_clk_get(&pdev->dev, "lvds_gate"); - if (IS_ERR(imx6_pcie->lvds_gate)) { + imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy"); + if (IS_ERR(imx6_pcie->pcie_phy)) { dev_err(&pdev->dev, - "lvds_gate clock select missing or invalid\n"); - return PTR_ERR(imx6_pcie->lvds_gate); + "pcie_phy clock source missing or invalid\n"); + return PTR_ERR(imx6_pcie->pcie_phy); } - imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m"); - if (IS_ERR(imx6_pcie->sata_ref_100m)) { + imx6_pcie->pcie_bus = devm_clk_get(&pdev->dev, "pcie_bus"); + if (IS_ERR(imx6_pcie->pcie_bus)) { dev_err(&pdev->dev, - "sata_ref_100m clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->sata_ref_100m); + "pcie_bus clock source missing or invalid\n"); + return PTR_ERR(imx6_pcie->pcie_bus); } - imx6_pcie->pcie_ref_125m = devm_clk_get(&pdev->dev, "pcie_ref_125m"); - if (IS_ERR(imx6_pcie->pcie_ref_125m)) { + imx6_pcie->pcie = devm_clk_get(&pdev->dev, "pcie"); + if (IS_ERR(imx6_pcie->pcie)) { dev_err(&pdev->dev, - "pcie_ref_125m clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie_ref_125m); - } - - imx6_pcie->pcie_axi = devm_clk_get(&pdev->dev, "pcie_axi"); - if (IS_ERR(imx6_pcie->pcie_axi)) { - dev_err(&pdev->dev, - "pcie_axi clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie_axi); + "pcie clock source missing or invalid\n"); + return PTR_ERR(imx6_pcie->pcie); } /* Grab GPR config register range */ From e521519a84f6d796d3cff756969cd5902c9550dd Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 28 Mar 2014 17:52:56 +0100 Subject: [PATCH 07/10] PCI: imx6: Drop old IRQ mapping We don't need this anymore. The IRQs are now properly mapped through the DT. Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Richard Zhu --- drivers/pci/host/pci-imx6.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index e080ae326ba6..ccaeed88597a 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -483,12 +483,6 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp, { int ret; - pp->irq = platform_get_irq(pdev, 0); - if (!pp->irq) { - dev_err(&pdev->dev, "failed to get irq\n"); - return -ENODEV; - } - pp->root_bus_nr = -1; pp->ops = &imx6_pcie_host_ops; From 5c40eea7783bbcdd5795cd7d50b7b3fd9a94dc94 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 28 Mar 2014 17:52:57 +0100 Subject: [PATCH 08/10] PCI: imx6: Remove optional (and unused) IRQs They are dropped with the new binding. Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Richard Zhu --- drivers/pci/host/pci-imx6.c | 42 ------------------------------------- 1 file changed, 42 deletions(-) diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index ccaeed88597a..29e77508d285 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -32,9 +32,6 @@ struct imx6_pcie { int reset_gpio; - int power_on_gpio; - int wake_up_gpio; - int disable_gpio; struct clk *pcie_bus; struct clk *pcie_phy; struct clk *pcie; @@ -230,9 +227,6 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); int ret; - if (gpio_is_valid(imx6_pcie->power_on_gpio)) - gpio_set_value(imx6_pcie->power_on_gpio, 1); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, @@ -531,42 +525,6 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) } } - imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0); - if (gpio_is_valid(imx6_pcie->power_on_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, - imx6_pcie->power_on_gpio, - GPIOF_OUT_INIT_LOW, - "PCIe power enable"); - if (ret) { - dev_err(&pdev->dev, "unable to get power-on gpio\n"); - return ret; - } - } - - imx6_pcie->wake_up_gpio = of_get_named_gpio(np, "wake-up-gpio", 0); - if (gpio_is_valid(imx6_pcie->wake_up_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, - imx6_pcie->wake_up_gpio, - GPIOF_IN, - "PCIe wake up"); - if (ret) { - dev_err(&pdev->dev, "unable to get wake-up gpio\n"); - return ret; - } - } - - imx6_pcie->disable_gpio = of_get_named_gpio(np, "disable-gpio", 0); - if (gpio_is_valid(imx6_pcie->disable_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, - imx6_pcie->disable_gpio, - GPIOF_OUT_INIT_HIGH, - "PCIe disable endpoint"); - if (ret) { - dev_err(&pdev->dev, "unable to get disable-ep gpio\n"); - return ret; - } - } - /* Fetch clocks */ imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy"); if (IS_ERR(imx6_pcie->pcie_phy)) { From 7f4f16eef5aeba31bdfb7702ced06a42f2777e04 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 28 Mar 2014 17:52:58 +0100 Subject: [PATCH 09/10] PCI: designware: Make MSI ISR shared IRQ aware On i.MX6 the host controller MSI IRQ is shared with PCI legacy INTD. Make sure we don't bail too early from the IRQ handler. The issue is fairly theoretical as it would require a system setup with a PCIe switch where one connected device is using legacy INTD and another one using MSI, but better fix it now. Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Jingoo Han Acked-by: Richard Zhu --- drivers/pci/host/pci-exynos.c | 4 +--- drivers/pci/host/pcie-designware.c | 6 +++++- drivers/pci/host/pcie-designware.h | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index 3de6bfbbe8e9..b616d34922d8 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -415,9 +415,7 @@ static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg) { struct pcie_port *pp = arg; - dw_handle_msi_irq(pp); - - return IRQ_HANDLED; + return dw_handle_msi_irq(pp); } static void exynos_pcie_msi_init(struct pcie_port *pp) diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 509a29d84509..77a649dd1473 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -155,15 +155,17 @@ static struct irq_chip dw_msi_irq_chip = { }; /* MSI int handler */ -void dw_handle_msi_irq(struct pcie_port *pp) +irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) { unsigned long val; int i, pos, irq; + irqreturn_t ret = IRQ_NONE; for (i = 0; i < MAX_MSI_CTRLS; i++) { dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, (u32 *)&val); if (val) { + ret = IRQ_HANDLED; pos = 0; while ((pos = find_next_bit(&val, 32, pos)) != 32) { irq = irq_find_mapping(pp->irq_domain, @@ -176,6 +178,8 @@ void dw_handle_msi_irq(struct pcie_port *pp) } } } + + return ret; } void dw_pcie_msi_init(struct pcie_port *pp) diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index 3063b3594d88..a169d22d517e 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -68,7 +68,7 @@ struct pcie_host_ops { int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val); -void dw_handle_msi_irq(struct pcie_port *pp); +irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); void dw_pcie_msi_init(struct pcie_port *pp); int dw_pcie_link_up(struct pcie_port *pp); void dw_pcie_setup_rc(struct pcie_port *pp); From d1dc9749a5b8239d9ae718a176b5cd39ff89f976 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 28 Mar 2014 17:52:59 +0100 Subject: [PATCH 10/10] PCI: imx6: Add support for MSI This patch adds support for Message Signaled Interrupts in the imx6-pcie driver. Signed-off-by: Harro Haan Signed-off-by: Juergen Beisert Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Richard Zhu --- drivers/pci/host/pci-imx6.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 29e77508d285..a5645ae4aef0 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "pcie-designware.h" @@ -314,6 +315,13 @@ static int imx6_pcie_wait_for_link(struct pcie_port *pp) return 0; } +static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg) +{ + struct pcie_port *pp = arg; + + return dw_handle_msi_irq(pp); +} + static int imx6_pcie_start_link(struct pcie_port *pp) { struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); @@ -388,6 +396,9 @@ static void imx6_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); imx6_pcie_start_link(pp); + + if (IS_ENABLED(CONFIG_PCI_MSI)) + dw_pcie_msi_init(pp); } static void imx6_pcie_reset_phy(struct pcie_port *pp) @@ -477,6 +488,22 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp, { int ret; + if (IS_ENABLED(CONFIG_PCI_MSI)) { + pp->msi_irq = platform_get_irq_byname(pdev, "msi"); + if (pp->msi_irq <= 0) { + dev_err(&pdev->dev, "failed to get MSI irq\n"); + return -ENODEV; + } + + ret = devm_request_irq(&pdev->dev, pp->msi_irq, + imx6_pcie_msi_handler, + IRQF_SHARED, "mx6-pcie-msi", pp); + if (ret) { + dev_err(&pdev->dev, "failed to request MSI irq\n"); + return -ENODEV; + } + } + pp->root_bus_nr = -1; pp->ops = &imx6_pcie_host_ops;