From 248d4e59616c632f37f04c233eec6d5008384926 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 6 Apr 2018 16:55:35 +0200 Subject: PCI: aardvark: Introduce an advk_pcie_valid_device() helper In other to mimic other PCIe host controller drivers, introduce an advk_pcie_valid_device() helper, used in the configuration read/write functions. Signed-off-by: Thomas Petazzoni [lorenzo.pieralisi@arm.com: updated host->controller dir move] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-aardvark.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index d3172d5d3d35..7b363437d851 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -433,6 +433,15 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie) return -ETIMEDOUT; } +static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus, + int devfn) +{ + if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0) + return false; + + return true; +} + static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 *val) { @@ -440,7 +449,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, u32 reg; int ret; - if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0) { + if (!advk_pcie_valid_device(pcie, bus, devfn)) { *val = 0xffffffff; return PCIBIOS_DEVICE_NOT_FOUND; } @@ -494,7 +503,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, int offset; int ret; - if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0) + if (!advk_pcie_valid_device(pcie, bus, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; if (where % size) -- cgit v1.2.3 From 6df6ba974a55678a2c7d9a0c06eb15cde0c4b184 Mon Sep 17 00:00:00 2001 From: Evan Wang Date: Fri, 6 Apr 2018 16:55:36 +0200 Subject: PCI: aardvark: Remove PCIe outbound window configuration Outbound window is used to translate CPU space addresses to PCIe space addresses when the CPU initiates PCIe transactions. According to the suggestion of the HW designers, the recommended solution is to use the default outbound parameters, even though the current outbound window setting does not cause any known functional issue. This patch doesn't address any known functional issue, but aligns to HW design guidelines, and removes code that isn't needed. Signed-off-by: Evan Wang [Thomas: tweak commit log.] Signed-off-by: Thomas Petazzoni [lorenzo.pieralisi@arm.com: handled host->controller dir move] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Victor Gu Reviewed-by: Nadav Haklai --- drivers/pci/controller/pci-aardvark.c | 55 ----------------------------------- 1 file changed, 55 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 7b363437d851..c9c72595bd20 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -111,24 +111,6 @@ #define PCIE_MSI_MASK_REG (CONTROL_BASE_ADDR + 0x5C) #define PCIE_MSI_PAYLOAD_REG (CONTROL_BASE_ADDR + 0x9C) -/* PCIe window configuration */ -#define OB_WIN_BASE_ADDR 0x4c00 -#define OB_WIN_BLOCK_SIZE 0x20 -#define OB_WIN_REG_ADDR(win, offset) (OB_WIN_BASE_ADDR + \ - OB_WIN_BLOCK_SIZE * (win) + \ - (offset)) -#define OB_WIN_MATCH_LS(win) OB_WIN_REG_ADDR(win, 0x00) -#define OB_WIN_MATCH_MS(win) OB_WIN_REG_ADDR(win, 0x04) -#define OB_WIN_REMAP_LS(win) OB_WIN_REG_ADDR(win, 0x08) -#define OB_WIN_REMAP_MS(win) OB_WIN_REG_ADDR(win, 0x0c) -#define OB_WIN_MASK_LS(win) OB_WIN_REG_ADDR(win, 0x10) -#define OB_WIN_MASK_MS(win) OB_WIN_REG_ADDR(win, 0x14) -#define OB_WIN_ACTIONS(win) OB_WIN_REG_ADDR(win, 0x18) - -/* PCIe window types */ -#define OB_PCIE_MEM 0x0 -#define OB_PCIE_IO 0x4 - /* LMI registers base address and register offsets */ #define LMI_BASE_ADDR 0x6000 #define CFG_REG (LMI_BASE_ADDR + 0x0) @@ -247,34 +229,9 @@ static int advk_pcie_wait_for_link(struct advk_pcie *pcie) return -ETIMEDOUT; } -/* - * Set PCIe address window register which could be used for memory - * mapping. - */ -static void advk_pcie_set_ob_win(struct advk_pcie *pcie, - u32 win_num, u32 match_ms, - u32 match_ls, u32 mask_ms, - u32 mask_ls, u32 remap_ms, - u32 remap_ls, u32 action) -{ - advk_writel(pcie, match_ls, OB_WIN_MATCH_LS(win_num)); - advk_writel(pcie, match_ms, OB_WIN_MATCH_MS(win_num)); - advk_writel(pcie, mask_ms, OB_WIN_MASK_MS(win_num)); - advk_writel(pcie, mask_ls, OB_WIN_MASK_LS(win_num)); - advk_writel(pcie, remap_ms, OB_WIN_REMAP_MS(win_num)); - advk_writel(pcie, remap_ls, OB_WIN_REMAP_LS(win_num)); - advk_writel(pcie, action, OB_WIN_ACTIONS(win_num)); - advk_writel(pcie, match_ls | BIT(0), OB_WIN_MATCH_LS(win_num)); -} - static void advk_pcie_setup_hw(struct advk_pcie *pcie) { u32 reg; - int i; - - /* Point PCIe unit MBUS decode windows to DRAM space */ - for (i = 0; i < 8; i++) - advk_pcie_set_ob_win(pcie, i, 0, 0, 0, 0, 0, 0, 0); /* Set to Direct mode */ reg = advk_readl(pcie, CTRL_CONFIG_REG); @@ -852,12 +809,6 @@ static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie) switch (resource_type(res)) { case IORESOURCE_IO: - advk_pcie_set_ob_win(pcie, 1, - upper_32_bits(res->start), - lower_32_bits(res->start), - 0, 0xF8000000, 0, - lower_32_bits(res->start), - OB_PCIE_IO); err = pci_remap_iospace(res, iobase); if (err) { dev_warn(dev, "error %d: failed to map resource %pR\n", @@ -866,12 +817,6 @@ static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie) } break; case IORESOURCE_MEM: - advk_pcie_set_ob_win(pcie, 0, - upper_32_bits(res->start), - lower_32_bits(res->start), - 0x0, 0xF8000000, 0, - lower_32_bits(res->start), - (2 << 20) | OB_PCIE_MEM); res_valid |= !(res->flags & IORESOURCE_PREFETCH); break; case IORESOURCE_BUS: -- cgit v1.2.3 From a7f58b9ecfd3c0f63703ec10f4a592cc38dbd1b8 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 8 May 2018 10:00:22 -0600 Subject: PCI: vmd: White list for fast interrupt handlers Devices with slow interrupt handlers are significantly harming performance when their interrupt vector is shared with a fast device. Create a class code white list for devices with known fast interrupt handlers and let all other devices share a single vector so that they don't interfere with performance. At the moment, only the NVM Express class code is on the list, but more may be added if VMD users desire to use other low-latency devices in these domains. Signed-off-by: Keith Busch [lorenzo.pieralisi@arm.com: changelog] Signed-off-by: Lorenzo Pieralisi Acked-by: Jon Derrick: --- drivers/pci/controller/vmd.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 942b64fc7f1f..fd2dbd7eed7b 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -197,9 +197,20 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d int i, best = 1; unsigned long flags; - if (pci_is_bridge(msi_desc_to_pci_dev(desc)) || vmd->msix_count == 1) + if (vmd->msix_count == 1) return &vmd->irqs[0]; + /* + * White list for fast-interrupt handlers. All others will share the + * "slow" interrupt vector. + */ + switch (msi_desc_to_pci_dev(desc)->class) { + case PCI_CLASS_STORAGE_EXPRESS: + break; + default: + return &vmd->irqs[0]; + } + raw_spin_lock_irqsave(&list_lock, flags); for (i = 1; i < vmd->msix_count; i++) if (vmd->irqs[i].count < vmd->irqs[best].count) -- cgit v1.2.3 From 7403bd14d7b545ef89c3443c09ccdb3c631a9a27 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Sun, 18 Mar 2018 22:53:28 +0800 Subject: PCI: hv: Replace GFP_ATOMIC with GFP_KERNEL in new_pcichild_device() new_pcichild_device() is not called in atomic context. The call chain ending up at new_pcichild_device() is: [1] new_pcichild_device() <- pci_devices_present_work() pci_devices_present_work() is only set in INIT_WORK(). Despite never getting called from atomic context, new_pcichild_device() calls kzalloc with GFP_ATOMIC, which waits busily for allocation. GFP_ATOMIC is not necessary and can be replaced with GFP_KERNEL to avoid busy waiting. Signed-off-by: Jia-Ju Bai [lorenzo.pieralisi@arm.com: reworked commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Michael Kelley --- drivers/pci/controller/pci-hyperv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 6cc5036ac83c..ba1d4b556064 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1543,7 +1543,7 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus, unsigned long flags; int ret; - hpdev = kzalloc(sizeof(*hpdev), GFP_ATOMIC); + hpdev = kzalloc(sizeof(*hpdev), GFP_KERNEL); if (!hpdev) return NULL; -- cgit v1.2.3 From 91a2968e245d6ba616db37001fa1a043078b1a65 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Fri, 29 Jun 2018 11:16:19 +0200 Subject: PCI: aardvark: Size bridges before resources allocation The PCIE I/O and MEM resource allocation mechanism is that root bus goes through the following steps: 1. Check PCI bridges' range and computes I/O and Mem base/limits. 2. Sort all subordinate devices I/O and MEM resource requirements and allocate the resources and writes/updates subordinate devices' requirements to PCI bridges I/O and Mem MEM/limits registers. Currently, PCI Aardvark driver only handles the second step and lacks the first step, so there is an I/O and MEM resource allocation failure when using a PCI switch. This commit fixes that by sizing bridges before doing the resource allocation. Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Signed-off-by: Zachary Zhang [Thomas: edit commit log.] Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi Cc: --- drivers/pci/controller/pci-aardvark.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index c9c72595bd20..10543ed7b500 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -906,6 +906,7 @@ static int advk_pcie_probe(struct platform_device *pdev) bus = bridge->bus; + pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); list_for_each_entry(child, &bus->children, node) -- cgit v1.2.3 From c8e144f8ab00e6c4a070a932ef9c57db09aa41cf Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 29 Jun 2018 11:16:20 +0200 Subject: PCI: aardvark: Convert to use pci_host_probe() Part of advk_pcie_probe() is exactly an open-coded version of pci_host_probe(). So instead of duplicating this code, use pci_host_probe() directly. Signed-off-by: Thomas Petazzoni [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-aardvark.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 10543ed7b500..d5030cd06197 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -843,7 +843,6 @@ static int advk_pcie_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct advk_pcie *pcie; struct resource *res; - struct pci_bus *bus, *child; struct pci_host_bridge *bridge; int ret, irq; @@ -897,22 +896,13 @@ static int advk_pcie_probe(struct platform_device *pdev) bridge->map_irq = of_irq_parse_and_map_pci; bridge->swizzle_irq = pci_common_swizzle; - ret = pci_scan_root_bus_bridge(bridge); + ret = pci_host_probe(bridge); if (ret < 0) { advk_pcie_remove_msi_irq_domain(pcie); advk_pcie_remove_irq_domain(pcie); return ret; } - bus = bridge->bus; - - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); - - list_for_each_entry(child, &bus->children, node) - pcie_bus_configure_settings(child); - - pci_bus_add_devices(bus); return 0; } -- cgit v1.2.3 From 7e37dc1db594d5a4ed062dbaf51ef89596a9df8a Mon Sep 17 00:00:00 2001 From: Alan Douglas Date: Mon, 25 Jun 2018 09:30:49 +0100 Subject: PCI: cadence: Update cdns_pcie_writel() function signature cdns_pcie_writel() writes a long value; change the value parameter type from u16 to u32 to rectify the function signature and related behaviour. Signed-off-by: Alan Douglas [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-cadence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-cadence.h b/drivers/pci/controller/pcie-cadence.h index 4bb27333b05c..ed336cc7f4ba 100644 --- a/drivers/pci/controller/pcie-cadence.h +++ b/drivers/pci/controller/pcie-cadence.h @@ -279,7 +279,7 @@ static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn, } static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn, - u32 reg, u16 value) + u32 reg, u32 value) { writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg); } -- cgit v1.2.3 From dfb80534692ddc5b97e1da4384f13dc0287fccb2 Mon Sep 17 00:00:00 2001 From: Alan Douglas Date: Mon, 25 Jun 2018 09:30:50 +0100 Subject: PCI: cadence: Add generic PHY support to host and EP drivers If PHYs are present, initialize and enable them at driver probe. Signed-off-by: Alan Douglas [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-cadence-ep.c | 14 ++++- drivers/pci/controller/pcie-cadence-host.c | 15 +++++ drivers/pci/controller/pcie-cadence.c | 93 ++++++++++++++++++++++++++++++ drivers/pci/controller/pcie-cadence.h | 7 +++ 4 files changed, 128 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c index e3fe4124e3af..c02f33d8e506 100644 --- a/drivers/pci/controller/pcie-cadence-ep.c +++ b/drivers/pci/controller/pcie-cadence-ep.c @@ -439,6 +439,7 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev) struct pci_epc *epc; struct resource *res; int ret; + int phy_count; ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); if (!ep) @@ -473,6 +474,12 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev) if (!ep->ob_addr) return -ENOMEM; + ret = cdns_pcie_init_phy(dev, pcie); + if (ret) { + dev_err(dev, "failed to init phy\n"); + return ret; + } + platform_set_drvdata(pdev, pcie); pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); if (ret < 0) { @@ -521,6 +528,10 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev) err_get_sync: pm_runtime_disable(dev); + cdns_pcie_disable_phy(pcie); + phy_count = pcie->phy_count; + while (phy_count--) + device_link_del(pcie->link[phy_count]); return ret; } @@ -528,6 +539,7 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev) static void cdns_pcie_ep_shutdown(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct cdns_pcie *pcie = dev_get_drvdata(dev); int ret; ret = pm_runtime_put_sync(dev); @@ -536,7 +548,7 @@ static void cdns_pcie_ep_shutdown(struct platform_device *pdev) pm_runtime_disable(dev); - /* The PCIe controller can't be disabled. */ + cdns_pcie_disable_phy(pcie); } static struct platform_driver cdns_pcie_ep_driver = { diff --git a/drivers/pci/controller/pcie-cadence-host.c b/drivers/pci/controller/pcie-cadence-host.c index a4ebbd37b553..36f31092562f 100644 --- a/drivers/pci/controller/pcie-cadence-host.c +++ b/drivers/pci/controller/pcie-cadence-host.c @@ -58,6 +58,9 @@ static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, return pcie->reg_base + (where & 0xfff); } + /* Check that the link is up */ + if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1)) + return NULL; /* Update Output registers for AXI region 0. */ addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | @@ -239,6 +242,7 @@ static int cdns_pcie_host_probe(struct platform_device *pdev) struct cdns_pcie *pcie; struct resource *res; int ret; + int phy_count; bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); if (!bridge) @@ -290,6 +294,13 @@ static int cdns_pcie_host_probe(struct platform_device *pdev) } pcie->mem_res = res; + ret = cdns_pcie_init_phy(dev, pcie); + if (ret) { + dev_err(dev, "failed to init phy\n"); + return ret; + } + platform_set_drvdata(pdev, pcie); + pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); if (ret < 0) { @@ -322,6 +333,10 @@ static int cdns_pcie_host_probe(struct platform_device *pdev) err_get_sync: pm_runtime_disable(dev); + cdns_pcie_disable_phy(pcie); + phy_count = pcie->phy_count; + while (phy_count--) + device_link_del(pcie->link[phy_count]); return ret; } diff --git a/drivers/pci/controller/pcie-cadence.c b/drivers/pci/controller/pcie-cadence.c index 138d113eb45d..2edc12661e44 100644 --- a/drivers/pci/controller/pcie-cadence.c +++ b/drivers/pci/controller/pcie-cadence.c @@ -124,3 +124,96 @@ void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r) cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); } + +void cdns_pcie_disable_phy(struct cdns_pcie *pcie) +{ + int i = pcie->phy_count; + + while (i--) { + phy_power_off(pcie->phy[i]); + phy_exit(pcie->phy[i]); + } +} + +int cdns_pcie_enable_phy(struct cdns_pcie *pcie) +{ + int ret; + int i; + + for (i = 0; i < pcie->phy_count; i++) { + ret = phy_init(pcie->phy[i]); + if (ret < 0) + goto err_phy; + + ret = phy_power_on(pcie->phy[i]); + if (ret < 0) { + phy_exit(pcie->phy[i]); + goto err_phy; + } + } + + return 0; + +err_phy: + while (--i >= 0) { + phy_power_off(pcie->phy[i]); + phy_exit(pcie->phy[i]); + } + + return ret; +} + +int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie) +{ + struct device_node *np = dev->of_node; + int phy_count; + struct phy **phy; + struct device_link **link; + int i; + int ret; + const char *name; + + phy_count = of_property_count_strings(np, "phy-names"); + if (phy_count < 1) { + dev_err(dev, "no phy-names. PHY will not be initialized\n"); + pcie->phy_count = 0; + return 0; + } + + phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL); + if (!phy) + return -ENOMEM; + + link = devm_kzalloc(dev, sizeof(*link) * phy_count, GFP_KERNEL); + if (!link) + return -ENOMEM; + + for (i = 0; i < phy_count; i++) { + of_property_read_string_index(np, "phy-names", i, &name); + phy[i] = devm_phy_optional_get(dev, name); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS); + if (!link[i]) { + ret = -EINVAL; + goto err_link; + } + } + + pcie->phy_count = phy_count; + pcie->phy = phy; + pcie->link = link; + + ret = cdns_pcie_enable_phy(pcie); + if (ret) + goto err_link; + + return 0; + +err_link: + while (--i >= 0) + device_link_del(link[i]); + + return ret; +} diff --git a/drivers/pci/controller/pcie-cadence.h b/drivers/pci/controller/pcie-cadence.h index ed336cc7f4ba..b342c808f7d6 100644 --- a/drivers/pci/controller/pcie-cadence.h +++ b/drivers/pci/controller/pcie-cadence.h @@ -8,6 +8,7 @@ #include #include +#include /* * Local Management Registers @@ -229,6 +230,9 @@ struct cdns_pcie { struct resource *mem_res; bool is_rc; u8 bus; + int phy_count; + struct phy **phy; + struct device_link **link; }; /* Register access */ @@ -307,5 +311,8 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn, u32 r, u64 cpu_addr); void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r); +void cdns_pcie_disable_phy(struct cdns_pcie *pcie); +int cdns_pcie_enable_phy(struct cdns_pcie *pcie); +int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie); #endif /* _PCIE_CADENCE_H */ -- cgit v1.2.3 From 141cb3d4ee521eff45d0520327106ddfe0abe90a Mon Sep 17 00:00:00 2001 From: Xiaowei Song Date: Wed, 11 Jul 2018 16:09:46 +0800 Subject: PCI: kirin: Add MSI support Add support for MSI to the kirin host controller driver, based on the generic dwc infrastructure. Signed-off-by: Xiaowei Song Signed-off-by: Yao Chen [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andy Shevchenko --- drivers/pci/controller/dwc/pcie-kirin.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d2970a009eb5..5352e0c3be82 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -430,6 +430,9 @@ static int kirin_pcie_host_init(struct pcie_port *pp) { kirin_pcie_establish_link(pp); + if (IS_ENABLED(CONFIG_PCI_MSI)) + dw_pcie_msi_init(pp); + return 0; } @@ -445,9 +448,34 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = { .host_init = kirin_pcie_host_init, }; +static int kirin_pcie_add_msi(struct dw_pcie *pci, + struct platform_device *pdev) +{ + int irq; + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, + "failed to get MSI IRQ (%d)\n", irq); + return irq; + } + + pci->pp.msi_irq = irq; + } + + return 0; +} + static int __init kirin_add_pcie_port(struct dw_pcie *pci, struct platform_device *pdev) { + int ret; + + ret = kirin_pcie_add_msi(pci, pdev); + if (ret) + return ret; + pci->pp.ops = &kirin_pcie_host_ops; return dw_pcie_host_init(&pci->pp); -- cgit v1.2.3 From ee12c9efe685428ebfae1bf5347b5375f54ce44e Mon Sep 17 00:00:00 2001 From: Alan Douglas Date: Mon, 25 Jun 2018 09:30:52 +0100 Subject: PCI: cadence: Add Power Management ops for host and EP These PM ops will enable/disable the optional PHYs if present. The AXI link-down register in the host driver is now cleared in cdns_pci_map_bus() since the link-down bit will be set if the PHY has been disabled. It is not cleared when enabling the PHY, since the link will not yet be up (e.g. when an EP controller is connected back-to-back to the host controller and its PHY is still disabled). Link: http://lkml.kernel.org/r/1529915453-4633-5-git-send-email-adouglas@cadence.com Signed-off-by: Alan Douglas [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-cadence-ep.c | 1 + drivers/pci/controller/pcie-cadence-host.c | 3 +++ drivers/pci/controller/pcie-cadence.c | 30 ++++++++++++++++++++++++++++++ drivers/pci/controller/pcie-cadence.h | 4 ++++ 4 files changed, 38 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c index c02f33d8e506..3eabd99a1233 100644 --- a/drivers/pci/controller/pcie-cadence-ep.c +++ b/drivers/pci/controller/pcie-cadence-ep.c @@ -555,6 +555,7 @@ static struct platform_driver cdns_pcie_ep_driver = { .driver = { .name = "cdns-pcie-ep", .of_match_table = cdns_pcie_ep_of_match, + .pm = &cdns_pcie_pm_ops, }, .probe = cdns_pcie_ep_probe, .shutdown = cdns_pcie_ep_shutdown, diff --git a/drivers/pci/controller/pcie-cadence-host.c b/drivers/pci/controller/pcie-cadence-host.c index 36f31092562f..e3e9b7de8592 100644 --- a/drivers/pci/controller/pcie-cadence-host.c +++ b/drivers/pci/controller/pcie-cadence-host.c @@ -61,6 +61,8 @@ static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, /* Check that the link is up */ if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1)) return NULL; + /* Clear AXI link-down status */ + cdns_pcie_writel(pcie, CDNS_PCIE_AT_LINKDOWN, 0x0); /* Update Output registers for AXI region 0. */ addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | @@ -345,6 +347,7 @@ static struct platform_driver cdns_pcie_host_driver = { .driver = { .name = "cdns-pcie-host", .of_match_table = cdns_pcie_host_of_match, + .pm = &cdns_pcie_pm_ops, }, .probe = cdns_pcie_host_probe, }; diff --git a/drivers/pci/controller/pcie-cadence.c b/drivers/pci/controller/pcie-cadence.c index 2edc12661e44..86f1b002c846 100644 --- a/drivers/pci/controller/pcie-cadence.c +++ b/drivers/pci/controller/pcie-cadence.c @@ -217,3 +217,33 @@ err_link: return ret; } + +#ifdef CONFIG_PM_SLEEP +static int cdns_pcie_suspend_noirq(struct device *dev) +{ + struct cdns_pcie *pcie = dev_get_drvdata(dev); + + cdns_pcie_disable_phy(pcie); + + return 0; +} + +static int cdns_pcie_resume_noirq(struct device *dev) +{ + struct cdns_pcie *pcie = dev_get_drvdata(dev); + int ret; + + ret = cdns_pcie_enable_phy(pcie); + if (ret) { + dev_err(dev, "failed to enable phy\n"); + return ret; + } + + return 0; +} +#endif + +const struct dev_pm_ops cdns_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq, + cdns_pcie_resume_noirq) +}; diff --git a/drivers/pci/controller/pcie-cadence.h b/drivers/pci/controller/pcie-cadence.h index b342c808f7d6..ae6bf2a2b3d3 100644 --- a/drivers/pci/controller/pcie-cadence.h +++ b/drivers/pci/controller/pcie-cadence.h @@ -166,6 +166,9 @@ #define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \ (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008) +/* AXI link down register */ +#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824) + enum cdns_pcie_rp_bar { RP_BAR0, RP_BAR1, @@ -314,5 +317,6 @@ void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r); void cdns_pcie_disable_phy(struct cdns_pcie *pcie); int cdns_pcie_enable_phy(struct cdns_pcie *pcie); int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie); +extern const struct dev_pm_ops cdns_pcie_pm_ops; #endif /* _PCIE_CADENCE_H */ -- cgit v1.2.3 From 0ae7383e83c6b1cea1e31173e362765dc24068c7 Mon Sep 17 00:00:00 2001 From: Alan Douglas Date: Mon, 25 Jun 2018 09:30:53 +0100 Subject: PCI: cadence: Add shutdown callback to host driver Add shutdown callback to host driver which will disable PHY and PM runtime. Signed-off-by: Alan Douglas Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-cadence-host.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-cadence-host.c b/drivers/pci/controller/pcie-cadence-host.c index e3e9b7de8592..ec394f6a19c8 100644 --- a/drivers/pci/controller/pcie-cadence-host.c +++ b/drivers/pci/controller/pcie-cadence-host.c @@ -343,6 +343,20 @@ static int cdns_pcie_host_probe(struct platform_device *pdev) return ret; } +static void cdns_pcie_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cdns_pcie *pcie = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_put_sync(dev); + if (ret < 0) + dev_dbg(dev, "pm_runtime_put_sync failed\n"); + + pm_runtime_disable(dev); + cdns_pcie_disable_phy(pcie); +} + static struct platform_driver cdns_pcie_host_driver = { .driver = { .name = "cdns-pcie-host", @@ -350,5 +364,6 @@ static struct platform_driver cdns_pcie_host_driver = { .pm = &cdns_pcie_pm_ops, }, .probe = cdns_pcie_host_probe, + .shutdown = cdns_pcie_shutdown, }; builtin_platform_driver(cdns_pcie_host_driver); -- cgit v1.2.3 From 3bc70825e4361eaedffeb4e85e1b2774547e66a0 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 11 Jun 2018 17:21:04 -0700 Subject: PCI: iproc: Fix up corrupted PAXC root complex config registers On certain versions of Broadcom PAXC based root complexes, certain regions of the configuration space are corrupted. As a result, it prevents the Linux PCIe stack from traversing the linked list of the capability registers completely and therefore the root complex is not advertised as "PCIe capable". This prevents the correct PCIe RID from being parsed in the kernel PCIe stack. A correct RID is required for mapping to a stream ID from the SMMU or the device ID from the GICv3 ITS. This patch fixes up the issue by manually populating the related PCIe capabilities. Signed-off-by: Ray Jui Signed-off-by: Lorenzo Pieralisi Reviewed-by: Oza Pawandeep --- drivers/pci/controller/pcie-iproc.c | 65 +++++++++++++++++++++++++++++++++---- drivers/pci/controller/pcie-iproc.h | 3 ++ 2 files changed, 62 insertions(+), 6 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 3c76c5fa4f32..680f6b170845 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -85,6 +85,8 @@ #define IMAP_VALID_SHIFT 0 #define IMAP_VALID BIT(IMAP_VALID_SHIFT) +#define IPROC_PCI_PM_CAP 0x48 +#define IPROC_PCI_PM_CAP_MASK 0xffff #define IPROC_PCI_EXP_CAP 0xac #define IPROC_PCIE_REG_INVALID 0xffff @@ -375,6 +377,17 @@ static const u16 iproc_pcie_reg_paxc_v2[] = { [IPROC_PCIE_CFG_DATA] = 0x1fc, }; +/* + * List of device IDs of controllers that have corrupted capability list that + * require SW fixup + */ +static const u16 iproc_pcie_corrupt_cap_did[] = { + 0x16cd, + 0x16f0, + 0xd802, + 0xd804 +}; + static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) { struct iproc_pcie *pcie = bus->sysdata; @@ -495,6 +508,49 @@ static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p) return data; } +static void iproc_pcie_fix_cap(struct iproc_pcie *pcie, int where, u32 *val) +{ + u32 i, dev_id; + + switch (where & ~0x3) { + case PCI_VENDOR_ID: + dev_id = *val >> 16; + + /* + * Activate fixup for those controllers that have corrupted + * capability list registers + */ + for (i = 0; i < ARRAY_SIZE(iproc_pcie_corrupt_cap_did); i++) + if (dev_id == iproc_pcie_corrupt_cap_did[i]) + pcie->fix_paxc_cap = true; + break; + + case IPROC_PCI_PM_CAP: + if (pcie->fix_paxc_cap) { + /* advertise PM, force next capability to PCIe */ + *val &= ~IPROC_PCI_PM_CAP_MASK; + *val |= IPROC_PCI_EXP_CAP << 8 | PCI_CAP_ID_PM; + } + break; + + case IPROC_PCI_EXP_CAP: + if (pcie->fix_paxc_cap) { + /* advertise root port, version 2, terminate here */ + *val = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2) << 16 | + PCI_CAP_ID_EXP; + } + break; + + case IPROC_PCI_EXP_CAP + PCI_EXP_RTCTL: + /* Don't advertise CRS SV support */ + *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16); + break; + + default: + break; + } +} + static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { @@ -509,13 +565,10 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, /* root complex access */ if (busno == 0) { ret = pci_generic_config_read32(bus, devfn, where, size, val); - if (ret != PCIBIOS_SUCCESSFUL) - return ret; + if (ret == PCIBIOS_SUCCESSFUL) + iproc_pcie_fix_cap(pcie, where, val); - /* Don't advertise CRS SV support */ - if ((where & ~0x3) == IPROC_PCI_EXP_CAP + PCI_EXP_RTCTL) - *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16); - return PCIBIOS_SUCCESSFUL; + return ret; } cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where); diff --git a/drivers/pci/controller/pcie-iproc.h b/drivers/pci/controller/pcie-iproc.h index 814b600b383a..9d5cfeea3046 100644 --- a/drivers/pci/controller/pcie-iproc.h +++ b/drivers/pci/controller/pcie-iproc.h @@ -60,6 +60,8 @@ struct iproc_msi; * @ep_is_internal: indicates an internal emulated endpoint device is connected * @has_apb_err_disable: indicates the controller can be configured to prevent * unsupported request from being forwarded as an APB bus error + * @fix_paxc_cap: indicates the controller has corrupted capability list in its + * config space registers and requires SW based fixup * * @need_ob_cfg: indicates SW needs to configure the outbound mapping window * @ob: outbound mapping related parameters @@ -85,6 +87,7 @@ struct iproc_pcie { int (*map_irq)(const struct pci_dev *, u8, u8); bool ep_is_internal; bool has_apb_err_disable; + bool fix_paxc_cap; bool need_ob_cfg; struct iproc_pcie_ob ob; -- cgit v1.2.3 From 1e5748c27ad6669ec4a377f44ef40898c28184e5 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 11 Jun 2018 17:21:05 -0700 Subject: PCI: iproc: Disable MSI parsing in certain PAXC blocks The internal MSI parsing logic in certain revisions of PAXC root complexes does not work properly and can cause corruptions on the writes transactions so they need to be disabled. Signed-off-by: Ray Jui Signed-off-by: Lorenzo Pieralisi Reviewed-by: Scott Branden Reviewed-by: Oza Pawandeep --- drivers/pci/controller/pcie-iproc.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 680f6b170845..0804aa284b87 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1197,10 +1197,22 @@ static int iproc_pcie_paxb_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr) return ret; } -static void iproc_pcie_paxc_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr) +static void iproc_pcie_paxc_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr, + bool enable) { u32 val; + if (!enable) { + /* + * Disable PAXC MSI steering. All write transfers will be + * treated as non-MSI transfers + */ + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_EN_CFG); + val &= ~MSI_ENABLE_CFG; + iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_EN_CFG, val); + return; + } + /* * Program bits [43:13] of address of GITS_TRANSLATER register into * bits [30:0] of the MSI base address register. In fact, in all iProc @@ -1254,7 +1266,7 @@ static int iproc_pcie_msi_steer(struct iproc_pcie *pcie, return ret; break; case IPROC_PCIE_PAXC_V2: - iproc_pcie_paxc_v2_msi_steer(pcie, msi_addr); + iproc_pcie_paxc_v2_msi_steer(pcie, msi_addr, true); break; default: return -EINVAL; @@ -1480,6 +1492,24 @@ int iproc_pcie_remove(struct iproc_pcie *pcie) } EXPORT_SYMBOL(iproc_pcie_remove); +/* + * The MSI parsing logic in certain revisions of Broadcom PAXC based root + * complex does not work and needs to be disabled + */ +static void quirk_paxc_disable_msi_parsing(struct pci_dev *pdev) +{ + struct iproc_pcie *pcie = iproc_data(pdev->bus); + + if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + iproc_pcie_paxc_v2_msi_steer(pcie, 0, false); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16f0, + quirk_paxc_disable_msi_parsing); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd802, + quirk_paxc_disable_msi_parsing); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd804, + quirk_paxc_disable_msi_parsing); + MODULE_AUTHOR("Ray Jui "); MODULE_DESCRIPTION("Broadcom iPROC PCIe common driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From f78e60a29d4ff27531770cf2c6eee89292379209 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 11 Jun 2018 17:21:06 -0700 Subject: PCI: iproc: Reject unconfigured physical functions from PAXC PAXC is an emulated PCIe root complex internally in various Broadcom based SoCs. PAXC internally connects to the embedded network processor within these SoCs, with the embedeed network processor exposed as an endpoint device. The number of physical functions from the embedded network processor that can be accessed depends on the firmware configuration. Unfortunately, due to an ASIC bug, unconfigured physical functions cannot be properly hidden from the root complex during enumerattion. As a result, config write access to these unconfigured physical functions during enumeration will cause a bus lock up on the embedded network processor. Fortunately, these unconfigured physical functions contain a very specific, staled PCIe device ID 0x168e. By making use of this device ID, one is able to terminate the enumeration early in the vendor/device ID config read. Signed-off-by: Ray Jui Signed-off-by: Lorenzo Pieralisi Reviewed-by: Scott Branden Reviewed-by: Oza Pawandeep --- drivers/pci/controller/pcie-iproc.c | 26 +++++++++++++++++++++++++- drivers/pci/controller/pcie-iproc.h | 5 +++++ 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 0804aa284b87..59be1e02ba65 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -582,6 +582,25 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, if (size <= 2) *val = (data >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); + /* + * For PAXC and PAXCv2, the total number of PFs that one can enumerate + * depends on the firmware configuration. Unfortunately, due to an ASIC + * bug, unconfigured PFs cannot be properly hidden from the root + * complex. As a result, write access to these PFs will cause bus lock + * up on the embedded processor + * + * Since all unconfigured PFs are left with an incorrect, staled device + * ID of 0x168e (PCI_DEVICE_ID_NX2_57810), we try to catch those access + * early here and reject them all + */ +#define DEVICE_ID_MASK 0xffff0000 +#define DEVICE_ID_SHIFT 16 + if (pcie->rej_unconfig_pf && + (where & CFG_ADDR_REG_NUM_MASK) == PCI_VENDOR_ID) + if ((*val & DEVICE_ID_MASK) == + (PCI_DEVICE_ID_NX2_57810 << DEVICE_ID_SHIFT)) + return PCIBIOS_FUNC_NOT_SUPPORTED; + return PCIBIOS_SUCCESSFUL; } @@ -681,7 +700,7 @@ static int iproc_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, struct iproc_pcie *pcie = iproc_data(bus); iproc_pcie_apb_err_disable(bus, true); - if (pcie->type == IPROC_PCIE_PAXB_V2) + if (pcie->iproc_cfg_read) ret = iproc_pcie_config_read(bus, devfn, where, size, val); else ret = pci_generic_config_read32(bus, devfn, where, size, val); @@ -1336,6 +1355,7 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) break; case IPROC_PCIE_PAXB: regs = iproc_pcie_reg_paxb; + pcie->iproc_cfg_read = true; pcie->has_apb_err_disable = true; if (pcie->need_ob_cfg) { pcie->ob_map = paxb_ob_map; @@ -1358,10 +1378,14 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) case IPROC_PCIE_PAXC: regs = iproc_pcie_reg_paxc; pcie->ep_is_internal = true; + pcie->iproc_cfg_read = true; + pcie->rej_unconfig_pf = true; break; case IPROC_PCIE_PAXC_V2: regs = iproc_pcie_reg_paxc_v2; pcie->ep_is_internal = true; + pcie->iproc_cfg_read = true; + pcie->rej_unconfig_pf = true; pcie->need_msi_steer = true; break; default: diff --git a/drivers/pci/controller/pcie-iproc.h b/drivers/pci/controller/pcie-iproc.h index 9d5cfeea3046..4f03ea539805 100644 --- a/drivers/pci/controller/pcie-iproc.h +++ b/drivers/pci/controller/pcie-iproc.h @@ -58,6 +58,9 @@ struct iproc_msi; * @phy: optional PHY device that controls the Serdes * @map_irq: function callback to map interrupts * @ep_is_internal: indicates an internal emulated endpoint device is connected + * @iproc_cfg_read: indicates the iProc config read function should be used + * @rej_unconfig_pf: indicates the root complex needs to detect and reject + * enumeration against unconfigured physical functions emulated in the ASIC * @has_apb_err_disable: indicates the controller can be configured to prevent * unsupported request from being forwarded as an APB bus error * @fix_paxc_cap: indicates the controller has corrupted capability list in its @@ -86,6 +89,8 @@ struct iproc_pcie { struct phy *phy; int (*map_irq)(const struct pci_dev *, u8, u8); bool ep_is_internal; + bool iproc_cfg_read; + bool rej_unconfig_pf; bool has_apb_err_disable; bool fix_paxc_cap; -- cgit v1.2.3 From 0043d4ae812e474d4edd28b60f203bfbb4edc93b Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 11 Jun 2018 17:21:07 -0700 Subject: PCI: iproc: Reduce inbound/outbound mapping print level Reduce inbound/outbound mapping print level from dev_info() to dev_dbg(). This reduces the console logs during Linux boot process. Signed-off-by: Ray Jui Signed-off-by: Lorenzo Pieralisi Reviewed-by: Scott Branden Reviewed-by: Oza Pawandeep --- drivers/pci/controller/pcie-iproc.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 59be1e02ba65..3160e9342a2f 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -880,14 +880,14 @@ static inline int iproc_pcie_ob_write(struct iproc_pcie *pcie, int window_idx, writel(lower_32_bits(pci_addr), pcie->base + omap_offset); writel(upper_32_bits(pci_addr), pcie->base + omap_offset + 4); - dev_info(dev, "ob window [%d]: offset 0x%x axi %pap pci %pap\n", - window_idx, oarr_offset, &axi_addr, &pci_addr); - dev_info(dev, "oarr lo 0x%x oarr hi 0x%x\n", - readl(pcie->base + oarr_offset), - readl(pcie->base + oarr_offset + 4)); - dev_info(dev, "omap lo 0x%x omap hi 0x%x\n", - readl(pcie->base + omap_offset), - readl(pcie->base + omap_offset + 4)); + dev_dbg(dev, "ob window [%d]: offset 0x%x axi %pap pci %pap\n", + window_idx, oarr_offset, &axi_addr, &pci_addr); + dev_dbg(dev, "oarr lo 0x%x oarr hi 0x%x\n", + readl(pcie->base + oarr_offset), + readl(pcie->base + oarr_offset + 4)); + dev_dbg(dev, "omap lo 0x%x omap hi 0x%x\n", + readl(pcie->base + omap_offset), + readl(pcie->base + omap_offset + 4)); return 0; } @@ -1054,8 +1054,8 @@ static int iproc_pcie_ib_write(struct iproc_pcie *pcie, int region_idx, iproc_pcie_reg_is_invalid(imap_offset)) return -EINVAL; - dev_info(dev, "ib region [%d]: offset 0x%x axi %pap pci %pap\n", - region_idx, iarr_offset, &axi_addr, &pci_addr); + dev_dbg(dev, "ib region [%d]: offset 0x%x axi %pap pci %pap\n", + region_idx, iarr_offset, &axi_addr, &pci_addr); /* * Program the IARR registers. The upper 32-bit IARR register is @@ -1065,9 +1065,9 @@ static int iproc_pcie_ib_write(struct iproc_pcie *pcie, int region_idx, pcie->base + iarr_offset); writel(upper_32_bits(pci_addr), pcie->base + iarr_offset + 4); - dev_info(dev, "iarr lo 0x%x iarr hi 0x%x\n", - readl(pcie->base + iarr_offset), - readl(pcie->base + iarr_offset + 4)); + dev_dbg(dev, "iarr lo 0x%x iarr hi 0x%x\n", + readl(pcie->base + iarr_offset), + readl(pcie->base + iarr_offset + 4)); /* * Now program the IMAP registers. Each IARR region may have one or @@ -1081,10 +1081,10 @@ static int iproc_pcie_ib_write(struct iproc_pcie *pcie, int region_idx, writel(upper_32_bits(axi_addr), pcie->base + imap_offset + ib_map->imap_addr_offset); - dev_info(dev, "imap window [%d] lo 0x%x hi 0x%x\n", - window_idx, readl(pcie->base + imap_offset), - readl(pcie->base + imap_offset + - ib_map->imap_addr_offset)); + dev_dbg(dev, "imap window [%d] lo 0x%x hi 0x%x\n", + window_idx, readl(pcie->base + imap_offset), + readl(pcie->base + imap_offset + + ib_map->imap_addr_offset)); imap_offset += ib_map->imap_window_offset; axi_addr += size; -- cgit v1.2.3 From a0476b3a678b4145a993f56071989af39d5718fb Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:43 +0800 Subject: PCI: exynos: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han --- drivers/pci/controller/dwc/pci-exynos.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 4cc1e5df8c79..cee5f2f590e2 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -421,7 +421,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep, } } - pp->root_bus_nr = -1; pp->ops = &exynos_pcie_host_ops; ret = dw_pcie_host_init(pp); -- cgit v1.2.3 From 39f712e989c5e591c58b65b62981b85027ba3103 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:44 +0800 Subject: PCI: imx6: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Richard Zhu Cc: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 80f604602783..4a9a673b4777 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -667,7 +667,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, } } - pp->root_bus_nr = -1; pp->ops = &imx6_pcie_host_ops; ret = dw_pcie_host_init(pp); -- cgit v1.2.3 From 8519bc8fe88fbe5c1e448ae1dd1ba215a1723abe Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:45 +0800 Subject: PCI: keystone: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Cc: Murali Karicheri --- drivers/pci/controller/dwc/pci-keystone.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 3722a5f31e5e..e88bd221fffe 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -347,7 +347,6 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, } } - pp->root_bus_nr = -1; pp->ops = &keystone_pcie_host_ops; ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); if (ret) { -- cgit v1.2.3 From 53b801fd020d4d00a1eebbab9f042a8b9fe03b78 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:46 +0800 Subject: PCI: armada8k: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Acked-by: Thomas Petazzoni --- drivers/pci/controller/dwc/pcie-armada8k.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index 072fd7ecc29f..0c389a30ef5d 100644 --- a/drivers/pci/controller/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c @@ -172,7 +172,6 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie, struct device *dev = &pdev->dev; int ret; - pp->root_bus_nr = -1; pp->ops = &armada8k_pcie_host_ops; pp->irq = platform_get_irq(pdev, 0); -- cgit v1.2.3 From 84b88219553af870a47e28d6ba288bd6fbd129f7 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:47 +0800 Subject: PCI: artpec6: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Acked-by: Jesper Nilsson Cc: Jesper Nilsson --- drivers/pci/controller/dwc/pcie-artpec6.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 321b56cfd5d0..128b182648b3 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -399,7 +399,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, } } - pp->root_bus_nr = -1; pp->ops = &artpec6_pcie_host_ops; ret = dw_pcie_host_init(pp); -- cgit v1.2.3 From 3513f81816ef085c0068c8aea04b78b0a06a8720 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:48 +0800 Subject: PCI: designware-plat: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Acked-by: Gustavo Pimentel Cc: Joao Pinto --- drivers/pci/controller/dwc/pcie-designware-plat.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 5937fed4c938..6e048c0b67f2 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -118,7 +118,6 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, return pp->msi_irq; } - pp->root_bus_nr = -1; pp->ops = &dw_plat_pcie_host_ops; ret = dw_pcie_host_init(pp); -- cgit v1.2.3 From 73fb9924d26b835f67acedacfe032343c9ed4f06 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:49 +0800 Subject: PCI: histb: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Cc: Jianguo Sun --- drivers/pci/controller/dwc/pcie-histb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 3611d6ce9a92..7b32e619b959 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -420,7 +420,6 @@ static int histb_pcie_probe(struct platform_device *pdev) phy_init(hipcie->phy); } - pp->root_bus_nr = -1; pp->ops = &histb_pcie_host_ops; platform_set_drvdata(pdev, hipcie); -- cgit v1.2.3 From 739cd35918b7cf495ea2d7abb2ff6ee97605f41d Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:50 +0800 Subject: PCI: qcom: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index a1d0198081a6..4352c1cb926d 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1251,7 +1251,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) if (ret) return ret; - pp->root_bus_nr = -1; pp->ops = &qcom_pcie_dw_ops; if (IS_ENABLED(CONFIG_PCI_MSI)) { -- cgit v1.2.3 From 53dd0c51f16be5f215d3ecad435062df99ee29ae Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 1 Jul 2018 11:54:51 +0800 Subject: PCI: spear13xx: Drop unnecessary root_bus_nr setting Function dw_pcie_host_init() already initializes the root_bus_nr field of 'struct pcie_port', so the -1 assignment prior to calling dw_pcie_host_init() in platform specific driver is not really needed. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Lorenzo Pieralisi Acked-by: Pratyush Anand --- drivers/pci/controller/dwc/pcie-spear13xx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index ecb58f7b7566..7d0cdfd8138b 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -210,7 +210,6 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie, return ret; } - pp->root_bus_nr = -1; pp->ops = &spear13xx_pcie_host_ops; ret = dw_pcie_host_init(pp); -- cgit v1.2.3 From eb1e39f784e83321353314da1b2e8cbb2fceaba9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 11 Jul 2018 09:01:03 +0100 Subject: PCI: pcie-cadence-ep: Remove redundant variable mmc Variable mmc is being assigned but is never used hence it is redundant and can be removed. Cleans up clang warning: warning: variable 'mmc' set but not used [-Wunused-but-set-variable] Signed-off-by: Colin Ian King [lorenzo.pieralisi@arm.com: reworked commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Alan Douglas --- drivers/pci/controller/pcie-cadence-ep.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c index 3eabd99a1233..04fe76c3d59d 100644 --- a/drivers/pci/controller/pcie-cadence-ep.c +++ b/drivers/pci/controller/pcie-cadence-ep.c @@ -238,7 +238,7 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn) struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; - u16 flags, mmc, mme; + u16 flags, mme; /* Validate that the MSI feature is actually enabled. */ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); @@ -249,7 +249,6 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn) * Get the Multiple Message Enable bitfield from the Message Control * register. */ - mmc = (flags & PCI_MSI_FLAGS_QMASK) >> 1; mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4; return mme; -- cgit v1.2.3 From 4e965ede1856ed62c7ac8b7ad905a4a285e4a9f3 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Thu, 19 Jul 2018 10:32:11 +0200 Subject: PCI: dwc: Fix EP link notification implementation Move specific features settings from EP shared code (pcie-designware-ep.c) to the driver (pcie-designware-plat.c). Previous implementation disables the EP link notification by default for all SoCs that uses EP DesignWare IP, which affects directly the dra7xx and artpec6 SoCs. Signed-off-by: Gustavo Pimentel Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pcie-designware-ep.c | 14 ++++++-------- drivers/pci/controller/dwc/pcie-designware-plat.c | 3 +++ 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 8650416f6f9e..04092a7aba89 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -386,15 +386,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) return -ENOMEM; ep->outbound_addr = addr; - if (ep->ops->ep_init) - ep->ops->ep_init(ep); - epc = devm_pci_epc_create(dev, &epc_ops); if (IS_ERR(epc)) { dev_err(dev, "Failed to create epc device\n"); return PTR_ERR(epc); } + ep->epc = epc; + epc_set_drvdata(epc, ep); + + if (ep->ops->ep_init) + ep->ops->ep_init(ep); + ret = of_property_read_u8(np, "max-functions", &epc->max_functions); if (ret < 0) epc->max_functions = 1; @@ -413,11 +416,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) return -ENOMEM; } - epc->features = EPC_FEATURE_NO_LINKUP_NOTIFIER; - EPC_FEATURE_SET_BAR(epc->features, BAR_0); - - ep->epc = epc; - epc_set_drvdata(epc, ep); dw_pcie_setup(pci); return 0; diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 6e048c0b67f2..a37dc92a03c7 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -70,10 +70,13 @@ static const struct dw_pcie_ops dw_pcie_ops = { static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct pci_epc *epc = ep->epc; enum pci_barno bar; for (bar = BAR_0; bar <= BAR_5; bar++) dw_pcie_ep_reset_bar(pci, bar); + + epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER; } static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, -- cgit v1.2.3 From d3c70a98d7d63cae02d50ebfafea04264a767401 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Thu, 19 Jul 2018 10:32:13 +0200 Subject: PCI: Update xxx_pcie_ep_raise_irq() and pci_epc_raise_irq() signatures Change {cdns, dra7xx, artpec6, dw, rockchip}_pcie_ep_raise_irq() and pci_epc_raise_irq() signature, namely the interrupt_num variable type from u8 to u16 to accommodate 2048 maximum MSI-X interrupts. Signed-off-by: Gustavo Pimentel Signed-off-by: Lorenzo Pieralisi Acked-by: Alan Douglas Acked-by: Shawn Lin Acked-by: Jesper Nilsson Acked-by: Joao Pinto Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pci-dra7xx.c | 2 +- drivers/pci/controller/dwc/pcie-artpec6.c | 2 +- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +- drivers/pci/controller/dwc/pcie-designware.h | 2 +- drivers/pci/controller/pcie-cadence-ep.c | 3 ++- drivers/pci/controller/pcie-rockchip-ep.c | 2 +- 7 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 345aab56ce8b..ce9224a36f62 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -370,7 +370,7 @@ static void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx, } static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, - enum pci_epc_irq_type type, u8 interrupt_num) + enum pci_epc_irq_type type, u16 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 128b182648b3..dba83abfe764 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -427,7 +427,7 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) } static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, - enum pci_epc_irq_type type, u8 interrupt_num) + enum pci_epc_irq_type type, u16 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 04092a7aba89..69d039de2af6 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -242,7 +242,7 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int) } static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, - enum pci_epc_irq_type type, u8 interrupt_num) + enum pci_epc_irq_type type, u16 interrupt_num) { struct dw_pcie_ep *ep = epc_get_drvdata(epc); diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index a37dc92a03c7..cca69ac63319 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -81,7 +81,7 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, enum pci_epc_irq_type type, - u8 interrupt_num) + u16 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index bee4e2535a61..9d581c077329 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -191,7 +191,7 @@ enum dw_pcie_as_type { struct dw_pcie_ep_ops { void (*ep_init)(struct dw_pcie_ep *ep); int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, - enum pci_epc_irq_type type, u8 interrupt_num); + enum pci_epc_irq_type type, u16 interrupt_num); }; struct dw_pcie_ep { diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c index e3fe4124e3af..208d11f27d5d 100644 --- a/drivers/pci/controller/pcie-cadence-ep.c +++ b/drivers/pci/controller/pcie-cadence-ep.c @@ -363,7 +363,8 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, } static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, - enum pci_epc_irq_type type, u8 interrupt_num) + enum pci_epc_irq_type type, + u16 interrupt_num) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 6beba8ed7b84..b8163c56a142 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -472,7 +472,7 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn, static int rockchip_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, enum pci_epc_irq_type type, - u8 interrupt_num) + u16 interrupt_num) { struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); -- cgit v1.2.3 From beb4641a787df79a1423a8789d185b6b78fcbfea Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Thu, 19 Jul 2018 10:32:14 +0200 Subject: PCI: dwc: Add MSI-X callbacks handler Add PCIe config space capability search function. Add sysfs set/get interface to allow the change of EP MSI-X maximum number. Add EP MSI-X callback for triggering interruptions. Signed-off-by: Gustavo Pimentel Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pcie-designware-ep.c | 137 +++++++++++++++++++++- drivers/pci/controller/dwc/pcie-designware-plat.c | 2 + drivers/pci/controller/dwc/pcie-designware.h | 10 ++ 3 files changed, 148 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 69d039de2af6..23be2c0249ee 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -40,6 +40,39 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) __dw_pcie_ep_reset_bar(pci, bar, 0); } +static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr, + u8 cap) +{ + u8 cap_id, next_cap_ptr; + u16 reg; + + reg = dw_pcie_readw_dbi(pci, cap_ptr); + next_cap_ptr = (reg & 0xff00) >> 8; + cap_id = (reg & 0x00ff); + + if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX) + return 0; + + if (cap_id == cap) + return cap_ptr; + + return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); +} + +static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap) +{ + u8 next_cap_ptr; + u16 reg; + + reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST); + next_cap_ptr = (reg & 0x00ff); + + if (!next_cap_ptr) + return 0; + + return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); +} + static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, struct pci_epf_header *hdr) { @@ -241,6 +274,45 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int) return 0; } +static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no) +{ + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + u32 val, reg; + + if (!ep->msix_cap) + return -EINVAL; + + reg = ep->msix_cap + PCI_MSIX_FLAGS; + val = dw_pcie_readw_dbi(pci, reg); + if (!(val & PCI_MSIX_FLAGS_ENABLE)) + return -EINVAL; + + val &= PCI_MSIX_FLAGS_QSIZE; + + return val; +} + +static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts) +{ + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + u32 val, reg; + + if (!ep->msix_cap) + return -EINVAL; + + reg = ep->msix_cap + PCI_MSIX_FLAGS; + val = dw_pcie_readw_dbi(pci, reg); + val &= ~PCI_MSIX_FLAGS_QSIZE; + val |= interrupts; + dw_pcie_dbi_ro_wr_en(pci); + dw_pcie_writew_dbi(pci, reg, val); + dw_pcie_dbi_ro_wr_dis(pci); + + return 0; +} + static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, enum pci_epc_irq_type type, u16 interrupt_num) { @@ -282,6 +354,8 @@ static const struct pci_epc_ops epc_ops = { .unmap_addr = dw_pcie_ep_unmap_addr, .set_msi = dw_pcie_ep_set_msi, .get_msi = dw_pcie_ep_get_msi, + .set_msix = dw_pcie_ep_set_msix, + .get_msix = dw_pcie_ep_get_msix, .raise_irq = dw_pcie_ep_raise_irq, .start = dw_pcie_ep_start, .stop = dw_pcie_ep_stop, @@ -322,6 +396,64 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct pci_epc *epc = ep->epc; + u16 tbl_offset, bir; + u32 bar_addr_upper, bar_addr_lower; + u32 msg_addr_upper, msg_addr_lower; + u32 reg, msg_data, vec_ctrl; + u64 tbl_addr, msg_addr, reg_u64; + void __iomem *msix_tbl; + int ret; + + reg = ep->msix_cap + PCI_MSIX_TABLE; + tbl_offset = dw_pcie_readl_dbi(pci, reg); + bir = (tbl_offset & PCI_MSIX_TABLE_BIR); + tbl_offset &= PCI_MSIX_TABLE_OFFSET; + tbl_offset >>= 3; + + reg = PCI_BASE_ADDRESS_0 + (4 * bir); + bar_addr_upper = 0; + bar_addr_lower = dw_pcie_readl_dbi(pci, reg); + reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK); + if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64) + bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4); + + tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower; + tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE)); + tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK; + + msix_tbl = ioremap_nocache(ep->phys_base + tbl_addr, + PCI_MSIX_ENTRY_SIZE); + if (!msix_tbl) + return -EINVAL; + + msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR); + msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR); + msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; + msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA); + vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL); + + iounmap(msix_tbl); + + if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) + return -EPERM; + + ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, + epc->mem->page_size); + if (ret) + return ret; + + writel(msg_data, ep->msi_mem); + + dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys); + + return 0; +} + void dw_pcie_ep_exit(struct dw_pcie_ep *ep) { struct pci_epc *epc = ep->epc; @@ -412,9 +544,12 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, epc->mem->page_size); if (!ep->msi_mem) { - dev_err(dev, "Failed to reserve memory for MSI\n"); + dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n"); return -ENOMEM; } + ep->msi_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSI); + + ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX); dw_pcie_setup(pci); diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index cca69ac63319..35d2291c6ba5 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -91,6 +91,8 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, return -EINVAL; case PCI_EPC_IRQ_MSI: return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); + case PCI_EPC_IRQ_MSIX: + return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); default: dev_err(pci->dev, "UNKNOWN IRQ type\n"); } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 9d581c077329..00ac4197c457 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -208,6 +208,8 @@ struct dw_pcie_ep { u32 num_ob_windows; void __iomem *msi_mem; phys_addr_t msi_mem_phys; + u8 msi_cap; /* MSI capability offset */ + u8 msix_cap; /* MSI-X capability offset */ }; struct dw_pcie_ops { @@ -359,6 +361,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep); void dw_pcie_ep_exit(struct dw_pcie_ep *ep); int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num); +int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num); void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); #else static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) @@ -380,6 +384,12 @@ static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num) +{ + return 0; +} + static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { } -- cgit v1.2.3 From 3920a5d7b24dc5229abe6fb8409e4c9de2c8c7a0 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Thu, 19 Jul 2018 10:32:15 +0200 Subject: PCI: dwc: Rework MSI callbacks handler Remove duplicate defines located on pcie-designware.h file already available on /include/uapi/linux/pci-regs.h file. Signed-off-by: Gustavo Pimentel Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pcie-designware-ep.c | 49 +++++++++++++++++-------- drivers/pci/controller/dwc/pcie-designware.h | 11 ------ 2 files changed, 33 insertions(+), 27 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 23be2c0249ee..dd9c36678cba 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -246,29 +246,38 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no, static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no) { - int val; struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + u32 val, reg; + + if (!ep->msi_cap) + return -EINVAL; - val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); - if (!(val & MSI_CAP_MSI_EN_MASK)) + reg = ep->msi_cap + PCI_MSI_FLAGS; + val = dw_pcie_readw_dbi(pci, reg); + if (!(val & PCI_MSI_FLAGS_ENABLE)) return -EINVAL; - val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT; + val = (val & PCI_MSI_FLAGS_QSIZE) >> 4; + return val; } -static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int) +static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) { - int val; struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + u32 val, reg; - val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); - val &= ~MSI_CAP_MMC_MASK; - val |= (encode_int << MSI_CAP_MMC_SHIFT) & MSI_CAP_MMC_MASK; + if (!ep->msi_cap) + return -EINVAL; + + reg = ep->msi_cap + PCI_MSI_FLAGS; + val = dw_pcie_readw_dbi(pci, reg); + val &= ~PCI_MSI_FLAGS_QMASK; + val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK; dw_pcie_dbi_ro_wr_en(pci); - dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val); + dw_pcie_writew_dbi(pci, reg, val); dw_pcie_dbi_ro_wr_dis(pci); return 0; @@ -367,21 +376,29 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct pci_epc *epc = ep->epc; u16 msg_ctrl, msg_data; - u32 msg_addr_lower, msg_addr_upper; + u32 msg_addr_lower, msg_addr_upper, reg; u64 msg_addr; bool has_upper; int ret; + if (!ep->msi_cap) + return -EINVAL; + /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ - msg_ctrl = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); + reg = ep->msi_cap + PCI_MSI_FLAGS; + msg_ctrl = dw_pcie_readw_dbi(pci, reg); has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); - msg_addr_lower = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32); + reg = ep->msi_cap + PCI_MSI_ADDRESS_LO; + msg_addr_lower = dw_pcie_readl_dbi(pci, reg); if (has_upper) { - msg_addr_upper = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32); - msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_64); + reg = ep->msi_cap + PCI_MSI_ADDRESS_HI; + msg_addr_upper = dw_pcie_readl_dbi(pci, reg); + reg = ep->msi_cap + PCI_MSI_DATA_64; + msg_data = dw_pcie_readw_dbi(pci, reg); } else { msg_addr_upper = 0; - msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_32); + reg = ep->msi_cap + PCI_MSI_DATA_32; + msg_data = dw_pcie_readw_dbi(pci, reg); } msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 00ac4197c457..e8b97f5a64be 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -96,17 +96,6 @@ #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ ((0x3 << 20) | ((region) << 9) | (0x1 << 8)) -#define MSI_MESSAGE_CONTROL 0x52 -#define MSI_CAP_MMC_SHIFT 1 -#define MSI_CAP_MMC_MASK (7 << MSI_CAP_MMC_SHIFT) -#define MSI_CAP_MME_SHIFT 4 -#define MSI_CAP_MSI_EN_MASK 0x1 -#define MSI_CAP_MME_MASK (7 << MSI_CAP_MME_SHIFT) -#define MSI_MESSAGE_ADDR_L32 0x54 -#define MSI_MESSAGE_ADDR_U32 0x58 -#define MSI_MESSAGE_DATA_32 0x58 -#define MSI_MESSAGE_DATA_64 0x5C - #define MAX_MSI_IRQS 256 #define MAX_MSI_IRQS_PER_CTRL 32 #define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL) -- cgit v1.2.3 From cb22d40b5f2bcf9d374ae92ea504df620daea342 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Thu, 19 Jul 2018 10:32:16 +0200 Subject: PCI: dwc: Add legacy interrupt callback handler Currently DesignWare IP does not handle legacy interrupts. Add a legacy interrupt callback handler. Signed-off-by: Gustavo Pimentel [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pcie-designware-ep.c | 10 ++++++++++ drivers/pci/controller/dwc/pcie-designware-plat.c | 3 +-- drivers/pci/controller/dwc/pcie-designware.h | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index dd9c36678cba..1e7b02221eac 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -370,6 +370,16 @@ static const struct pci_epc_ops epc_ops = { .stop = dw_pcie_ep_stop, }; +int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct device *dev = pci->dev; + + dev_err(dev, "EP cannot trigger legacy IRQs\n"); + + return -EINVAL; +} + int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num) { diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 35d2291c6ba5..3f8a3aa3a91e 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -87,8 +87,7 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, switch (type) { case PCI_EPC_IRQ_LEGACY: - dev_err(pci->dev, "EP cannot trigger legacy IRQs\n"); - return -EINVAL; + return dw_pcie_ep_raise_legacy_irq(ep, func_no); case PCI_EPC_IRQ_MSI: return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); case PCI_EPC_IRQ_MSIX: diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index e8b97f5a64be..96126fd8403c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -348,6 +348,7 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp) void dw_pcie_ep_linkup(struct dw_pcie_ep *ep); int dw_pcie_ep_init(struct dw_pcie_ep *ep); void dw_pcie_ep_exit(struct dw_pcie_ep *ep); +int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no); int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num); int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, @@ -367,6 +368,11 @@ static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep) { } +static inline int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no) +{ + return 0; +} + static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num) { -- cgit v1.2.3 From c2e00e31087e58f6c49b90b4702fc3df4fad6a83 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Thu, 19 Jul 2018 10:32:19 +0200 Subject: pci-epf-test/pci_endpoint_test: Add MSI-X support Add MSI-X support and update driver documentation accordingly. Signed-off-by: Gustavo Pimentel Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pcie-designware-plat.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 3f8a3aa3a91e..c12bf794d69c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -77,6 +77,7 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) dw_pcie_ep_reset_bar(pci, bar); epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER; + epc->features |= EPC_FEATURE_MSIX_AVAILABLE; } static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, -- cgit v1.2.3 From 014562071c96524b518d4d3513fcde072c8e63b5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Jul 2018 12:45:39 +0300 Subject: PCI: mobiveil: Integer overflow in IB_WIN_SIZE IB_WIN_SIZE is larger than INT_MAX so we need to cast it to u64. Fixes: 9af6bcb11e12 ("PCI: mobiveil: Add Mobiveil PCIe Host Bridge IP driver") Signed-off-by: Dan Carpenter Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-mobiveil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/pcie-mobiveil.c index 4d6c20e47bed..cf0aa7cee5b0 100644 --- a/drivers/pci/controller/pcie-mobiveil.c +++ b/drivers/pci/controller/pcie-mobiveil.c @@ -107,7 +107,7 @@ #define CFG_WINDOW_TYPE 0 #define IO_WINDOW_TYPE 1 #define MEM_WINDOW_TYPE 2 -#define IB_WIN_SIZE (256 * 1024 * 1024 * 1024) +#define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024) #define MAX_PIO_WINDOWS 8 /* Parameters for the waiting for link up routine */ -- cgit v1.2.3 From af3f606e0bbb6d811c50b7b90fe324b07fb7cab8 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 30 Jul 2018 13:24:12 +0100 Subject: PCI: mobiveil: Fix struct mobiveil_pcie.pcie_reg_base address type The field pcie_reg_base in struct mobiveil_pcie represents a physical address so it should be of phys_addr_t type rather than void __iomem*; this results in the following compilation warnings: drivers/pci/controller/pcie-mobiveil.c: In function 'mobiveil_pcie_parse_dt': drivers/pci/controller/pcie-mobiveil.c:326:22: warning: assignment makes pointer from integer without a cast [-Wint-conversion] pcie->pcie_reg_base = res->start; ^ drivers/pci/controller/pcie-mobiveil.c: In function 'mobiveil_pcie_enable_msi': drivers/pci/controller/pcie-mobiveil.c:485:25: warning: initialization makes integer from pointer without a cast [-Wint-conversion] phys_addr_t msg_addr = pcie->pcie_reg_base; ^~~~ drivers/pci/controller/pcie-mobiveil.c: In function 'mobiveil_compose_msi_msg': drivers/pci/controller/pcie-mobiveil.c:640:21: warning: initialization makes integer from pointer without a cast [-Wint-conversion] phys_addr_t addr = pcie->pcie_reg_base + (data->hwirq * sizeof(int)); Fix the type and with it the compilation warnings. Fixes: 9af6bcb11e12 ("PCI: mobiveil: Add Mobiveil PCIe Host Bridge IP driver") Signed-off-by: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Subrahmanya Lingappa --- drivers/pci/controller/pcie-mobiveil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/pcie-mobiveil.c index cf0aa7cee5b0..8b45f77d70f9 100644 --- a/drivers/pci/controller/pcie-mobiveil.c +++ b/drivers/pci/controller/pcie-mobiveil.c @@ -130,7 +130,7 @@ struct mobiveil_pcie { void __iomem *config_axi_slave_base; /* endpoint config base */ void __iomem *csr_axi_slave_base; /* root port config base */ void __iomem *apb_csr_base; /* MSI register base */ - void __iomem *pcie_reg_base; /* Physical PCIe Controller Base */ + phys_addr_t pcie_reg_base; /* Physical PCIe Controller Base */ struct irq_domain *intx_domain; raw_spinlock_t intx_mask_lock; int irq; -- cgit v1.2.3 From d3743012230f8dab30d47caba1f2ee9e382385e7 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 30 Jul 2018 13:24:33 +0100 Subject: PCI: mobiveil: Add missing ../pci.h include PCI mobiveil host controller driver currently fails to compile with the following error: drivers/pci/controller/pcie-mobiveil.c: In function 'mobiveil_pcie_probe': drivers/pci/controller/pcie-mobiveil.c:788:8: error: implicit declaration of function 'devm_of_pci_get_host_bridge_resources'; did you mean 'pci_get_host_bridge_device'? [-Werror=implicit-function-declaration] ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pci_get_host_bridge_device Add the missing include file to pull in the required function declaration. Fixes: 9af6bcb11e12 ("PCI: mobiveil: Add Mobiveil PCIe Host Bridge IP driver") Signed-off-by: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Subrahmanya Lingappa --- drivers/pci/controller/pcie-mobiveil.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/pcie-mobiveil.c index 8b45f77d70f9..a939e8d31735 100644 --- a/drivers/pci/controller/pcie-mobiveil.c +++ b/drivers/pci/controller/pcie-mobiveil.c @@ -23,6 +23,8 @@ #include #include +#include "../pci.h" + /* register offsets and bit positions */ /* -- cgit v1.2.3 From 6f2c73c124b14808d210722fd1c0c8938f9db3ba Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 30 Jul 2018 13:09:56 +0100 Subject: PCI: mobiveil: Add Kconfig/Makefile entries commit 9af6bcb11e12 ("PCI: mobiveil: Add Mobiveil PCIe Host Bridge IP driver") did not add the configuration and build infrastructure to configure and build the mobiveil controller driver, so at present the driver code is in the kernel but cannot be compiled. Add the mobiveil controller driver Kconfig/Makefile infrastructure. Fixes: 9af6bcb11e12 ("PCI: mobiveil: Add Mobiveil PCIe Host Bridge IP driver") Signed-off-by: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Subrahmanya Lingappa --- drivers/pci/controller/Kconfig | 10 ++++++++++ drivers/pci/controller/Makefile | 1 + 2 files changed, 11 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 18fa09b3ac8f..fc4dbcd35e8f 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -242,6 +242,16 @@ config PCIE_MEDIATEK Say Y here if you want to enable PCIe controller support on MediaTek SoCs. +config PCIE_MOBIVEIL + bool "Mobiveil AXI PCIe controller" + depends on ARCH_ZYNQMP || COMPILE_TEST + depends on OF + depends on PCI_MSI_IRQ_DOMAIN + help + Say Y here if you want to enable support for the Mobiveil AXI PCIe + Soft IP. It has up to 8 outbound and inbound windows + for address translation and it is a PCIe Gen4 IP. + config PCIE_TANGO_SMP8759 bool "Tango SMP8759 PCIe controller (DANGEROUS)" depends on ARCH_TANGO && PCI_MSI && OF diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index 24322b92f200..d56a507495c5 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o +obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o obj-$(CONFIG_VMD) += vmd.o # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW -- cgit v1.2.3 From 34dbc9c6584d28d307690e13af882d159562581f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 4 Aug 2018 12:14:02 +0200 Subject: PCI/xilinx: Depend on OF instead of the ARCH There isn't a hard dependency of the Xilinx AXI-PCIe host bridge on any architecture. For example: at SiFive we map RISC-V cores to Xilinx FPGAs and connect the Xilinx IP via a TileLink adapter, so the RISC-V Linux port will need to be able to enable PCIE_XILINX in order to have PCIe support. This patch decouples the PCIE_XILINX support from ARCH. Instead it just depends on OF, which is the only true dependency. Signed-off-by: Palmer Dabbelt [hch: switch to OF instead of OF_PCI now that the latter is gone] Signed-off-by: Christoph Hellwig [lorenzo.pieralisi@arm.com: trimmed the commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 18fa09b3ac8f..1fc3d4eb373d 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -103,7 +103,7 @@ config PCI_HOST_GENERIC config PCIE_XILINX bool "Xilinx AXI PCIe host bridge support" - depends on ARCH_ZYNQ || MICROBLAZE || (MIPS && PCI_DRIVERS_GENERIC) || COMPILE_TEST + depends on OF || COMPILE_TEST help Say 'Y' here if you want kernel to support the Xilinx AXI PCIe Host Bridge driver. -- cgit v1.2.3 From 6554f9501915101ba89aab6e40c83139d23f853a Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 3 Aug 2018 16:38:43 +0200 Subject: PCI: mvebu: Remove redundant platform_set_drvdata() call This is already done earlier in mvebu_pcie_probe(). Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-mvebu.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 23e270839e6a..38fa2d08527d 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -1283,8 +1283,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev) mvebu_pcie_enable(pcie); - platform_set_drvdata(pdev, pcie); - return 0; } -- cgit v1.2.3 From dfd0309fd7b30a5baffaf47b2fccb88b46d64d69 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 3 Aug 2018 16:38:44 +0200 Subject: PCI: mvebu: Fix I/O space end address calculation pcie->realio.end should be the address of last byte of the area, therefore using resource_size() of another resource is not correct, we must substract 1 to get the address of the last byte. Fixes: 11be65472a427 ("PCI: mvebu: Adapt to the new device tree layout") Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-mvebu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 38fa2d08527d..a195592723c2 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -1219,7 +1219,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) pcie->realio.start = PCIBIOS_MIN_IO; pcie->realio.end = min_t(resource_size_t, IO_SPACE_LIMIT, - resource_size(&pcie->io)); + resource_size(&pcie->io) - 1); } else pcie->realio = pcie->io; -- cgit v1.2.3 From ee1604381a371b3ea6aec7d5e43b6e3f5e153854 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 3 Aug 2018 16:38:45 +0200 Subject: PCI: mvebu: Only remap I/O space if configured If there is no PCI I/O aperture configured in the Device Tree, it does not make sense to create the virtual mapping for the PCI I/O space, since we will anyway not create the MBus window that will allow to access it. Therefore, do the pci_ioremap_io() only if necessary. Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-mvebu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index a195592723c2..9aa224f2f009 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -1220,6 +1220,9 @@ static int mvebu_pcie_probe(struct platform_device *pdev) pcie->realio.end = min_t(resource_size_t, IO_SPACE_LIMIT, resource_size(&pcie->io) - 1); + + for (i = 0; i < (IO_SPACE_LIMIT - SZ_64K); i += SZ_64K) + pci_ioremap_io(i, pcie->io.start + i); } else pcie->realio = pcie->io; @@ -1278,9 +1281,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev) pcie->nports = i; - for (i = 0; i < (IO_SPACE_LIMIT - SZ_64K); i += SZ_64K) - pci_ioremap_io(i, pcie->io.start + i); - mvebu_pcie_enable(pcie); return 0; -- cgit v1.2.3 From 5a553d6ba103e28247f4e2d10bcc25545cd4d9cb Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 3 Aug 2018 16:38:46 +0200 Subject: PCI: mvebu: Use resource_size() to remap I/O space Instead of hardcoding the remapping of IO_SPACE_LIMIT - SZ_64K, use resource_size(). However, we cannot use just IO_SPACE_LIMIT, because pci_ioremap_io() has a bug and doesn't allow remapping the last 64 KB before IO_SPACE_LIMIT, so we ensure that we do not exceed this limit. When the pci_ioremap_io() issue is fixed, this work around can be dropped. Note that this workaround already existed, since we were mapping only up to IO_SPACE_LIMIT - SZ_64K. Suggested-by: Lorenzo Pieralisi Signed-off-by: Thomas Petazzoni [lorenzo.pieralisi@arm.com: tweaked the commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 9aa224f2f009..05f863435e5e 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -1218,10 +1218,10 @@ static int mvebu_pcie_probe(struct platform_device *pdev) pcie->realio.flags = pcie->io.flags; pcie->realio.start = PCIBIOS_MIN_IO; pcie->realio.end = min_t(resource_size_t, - IO_SPACE_LIMIT, + IO_SPACE_LIMIT - SZ_64K, resource_size(&pcie->io) - 1); - for (i = 0; i < (IO_SPACE_LIMIT - SZ_64K); i += SZ_64K) + for (i = 0; i < resource_size(&pcie->realio); i += SZ_64K) pci_ioremap_io(i, pcie->io.start + i); } else pcie->realio = pcie->io; -- cgit v1.2.3 From 42342073e38b50113354944cd51dcfed28d857a1 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 3 Aug 2018 16:38:47 +0200 Subject: PCI: mvebu: Convert to use pci_host_bridge directly Rather than using the ARM-specific pci_common_init_dev() API, use the pci_host_bridge logic directly. Unfortunately, we can't use devm_of_pci_get_host_bridge_resources(), because the DT binding for describing PCIe apertures for this PCI controller is a bit special, and we cannot retrieve them from the 'ranges' property. Therefore, we still have some special code to handle this. Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-mvebu.c | 136 +++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 73 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 05f863435e5e..9055f03596ef 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -125,6 +125,7 @@ struct mvebu_pcie { struct platform_device *pdev; struct mvebu_pcie_port *ports; struct msi_controller *msi; + struct list_head resources; struct resource io; struct resource realio; struct resource mem; @@ -800,7 +801,7 @@ static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie, static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 val) { - struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); + struct mvebu_pcie *pcie = bus->sysdata; struct mvebu_pcie_port *port; int ret; @@ -826,7 +827,7 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 *val) { - struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); + struct mvebu_pcie *pcie = bus->sysdata; struct mvebu_pcie_port *port; int ret; @@ -857,36 +858,6 @@ static struct pci_ops mvebu_pcie_ops = { .write = mvebu_pcie_wr_conf, }; -static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) -{ - struct mvebu_pcie *pcie = sys_to_pcie(sys); - int err, i; - - pcie->mem.name = "PCI MEM"; - pcie->realio.name = "PCI I/O"; - - if (resource_size(&pcie->realio) != 0) - pci_add_resource_offset(&sys->resources, &pcie->realio, - sys->io_offset); - - pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); - pci_add_resource(&sys->resources, &pcie->busn); - - err = devm_request_pci_bus_resources(&pcie->pdev->dev, &sys->resources); - if (err) - return 0; - - for (i = 0; i < pcie->nports; i++) { - struct mvebu_pcie_port *port = &pcie->ports[i]; - - if (!port->base) - continue; - mvebu_pcie_setup_hw(port); - } - - return 1; -} - static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, const struct resource *res, resource_size_t start, @@ -917,26 +888,6 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, return start; } -static void mvebu_pcie_enable(struct mvebu_pcie *pcie) -{ - struct hw_pci hw; - - memset(&hw, 0, sizeof(hw)); - -#ifdef CONFIG_PCI_MSI - hw.msi_ctrl = pcie->msi; -#endif - - hw.nr_controllers = 1; - hw.private_data = (void **)&pcie; - hw.setup = mvebu_pcie_setup; - hw.map_irq = of_irq_parse_and_map_pci; - hw.ops = &mvebu_pcie_ops; - hw.align_resource = mvebu_pcie_align_resource; - - pci_common_init_dev(&pcie->pdev->dev, &hw); -} - /* * Looks up the list of register addresses encoded into the reg = * <...> property for one that matches the given port/lane. Once @@ -1190,28 +1141,39 @@ static void mvebu_pcie_powerdown(struct mvebu_pcie_port *port) clk_disable_unprepare(port->clk); } -static int mvebu_pcie_probe(struct platform_device *pdev) +/* + * We can't use devm_of_pci_get_host_bridge_resources() because we + * need to parse our special DT properties encoding the MEM and IO + * apertures. + */ +static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie) { - struct device *dev = &pdev->dev; - struct mvebu_pcie *pcie; + struct device *dev = &pcie->pdev->dev; struct device_node *np = dev->of_node; - struct device_node *child; - int num, i, ret; + unsigned int i; + int ret; - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) - return -ENOMEM; + INIT_LIST_HEAD(&pcie->resources); - pcie->pdev = pdev; - platform_set_drvdata(pdev, pcie); + /* Get the bus range */ + ret = of_pci_parse_bus_range(np, &pcie->busn); + if (ret) { + dev_err(dev, "failed to parse bus-range property: %d\n", ret); + return ret; + } + pci_add_resource(&pcie->resources, &pcie->busn); - /* Get the PCIe memory and I/O aperture */ + /* Get the PCIe memory aperture */ mvebu_mbus_get_pcie_mem_aperture(&pcie->mem); if (resource_size(&pcie->mem) == 0) { dev_err(dev, "invalid memory aperture size\n"); return -EINVAL; } + pcie->mem.name = "PCI MEM"; + pci_add_resource(&pcie->resources, &pcie->mem); + + /* Get the PCIe IO aperture */ mvebu_mbus_get_pcie_io_aperture(&pcie->io); if (resource_size(&pcie->io) != 0) { @@ -1220,19 +1182,38 @@ static int mvebu_pcie_probe(struct platform_device *pdev) pcie->realio.end = min_t(resource_size_t, IO_SPACE_LIMIT - SZ_64K, resource_size(&pcie->io) - 1); + pcie->realio.name = "PCI I/O"; for (i = 0; i < resource_size(&pcie->realio); i += SZ_64K) pci_ioremap_io(i, pcie->io.start + i); - } else - pcie->realio = pcie->io; - /* Get the bus range */ - ret = of_pci_parse_bus_range(np, &pcie->busn); - if (ret) { - dev_err(dev, "failed to parse bus-range property: %d\n", ret); - return ret; + pci_add_resource(&pcie->resources, &pcie->realio); } + return devm_request_pci_bus_resources(dev, &pcie->resources); +} + +static int mvebu_pcie_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mvebu_pcie *pcie; + struct pci_host_bridge *bridge; + struct device_node *np = dev->of_node; + struct device_node *child; + int num, i, ret; + + bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct mvebu_pcie)); + if (!bridge) + return -ENOMEM; + + pcie = pci_host_bridge_priv(bridge); + pcie->pdev = pdev; + platform_set_drvdata(pdev, pcie); + + ret = mvebu_pcie_parse_request_resources(pcie); + if (ret) + return ret; + num = of_get_available_child_count(np); pcie->ports = devm_kcalloc(dev, num, sizeof(*pcie->ports), GFP_KERNEL); @@ -1275,15 +1256,24 @@ static int mvebu_pcie_probe(struct platform_device *pdev) continue; } + mvebu_pcie_setup_hw(port); mvebu_pcie_set_local_dev_nr(port, 1); mvebu_sw_pci_bridge_init(port); } pcie->nports = i; - mvebu_pcie_enable(pcie); - - return 0; + list_splice_init(&pcie->resources, &bridge->windows); + bridge->dev.parent = dev; + bridge->sysdata = pcie; + bridge->busnr = 0; + bridge->ops = &mvebu_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; + bridge->align_resource = mvebu_pcie_align_resource; + bridge->msi = pcie->msi; + + return pci_host_probe(bridge); } static const struct of_device_id mvebu_pcie_of_match_table[] = { -- cgit v1.2.3 From f23d0d449c169d94cc958196a1d088705ef26ebc Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 3 Aug 2018 16:38:48 +0200 Subject: PCI: mvebu: Drop bogus comment above mvebu_pcie_map_registers() This comment has been there since the driver was introduced, but seems to be a leftover from previous iterations of the driver. Indeed, we do not lookup in a list to find the register ranges that matches the given port/lane, as the "reg" property is in each sub-node representing a PCI port. There is no lookup involved at all. Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-mvebu.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 9055f03596ef..50eb0729385b 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -888,11 +888,6 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, return start; } -/* - * Looks up the list of register addresses encoded into the reg = - * <...> property for one that matches the given port/lane. Once - * found, maps it. - */ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev, struct device_node *np, struct mvebu_pcie_port *port) -- cgit v1.2.3