From 16270a92355722e387e9ca19627c5a4d7bae1354 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Tue, 18 Aug 2020 17:27:46 +0800 Subject: PCI: designware-ep: Fix the Header Type check The current check will result in the multiple function device fails to initialize. So fix the check by masking out the multiple function bit. Link: https://lore.kernel.org/r/20200818092746.24366-1-Zhiqiang.Hou@nxp.com Fixes: 0b24134f7888 ("PCI: dwc: Add validation that PCIe core is set to correct mode") Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/dwc/pcie-designware-ep.c | 3 ++- 1 file changed, 2 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 305bfec2424d..29f5c616c3bc 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -505,7 +505,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) u32 reg; int i; - hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE); + hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) & + PCI_HEADER_TYPE_MASK; if (hdr_type != PCI_HEADER_TYPE_NORMAL) { dev_err(pci->dev, "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n", -- cgit v1.2.3 From f81c770df72e72183269fc8d7ceb0497957cdf1f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:42 -0600 Subject: PCI: dwc: Use DBI accessors instead of own config accessors The Designware DBI space contains the root bus bridge config space. Platforms needing custom {rd,wr}_own_conf functions are also the ones needing custom {read,write}_dbi ops functions and the access sequences are the same. Replace all dw_pcie_{rd,wr}_own_conf() calls with the DBI variants in preparation to remove dw_pcie_{rd,wr}_own_conf(). Link: https://lore.kernel.org/r/20200821035420.380495-3-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-host.c | 55 ++++++++--------------- 1 file changed, 19 insertions(+), 36 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 9dafecba347f..1d98554db009 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -82,13 +82,13 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) unsigned long val; u32 status, num_ctrls; irqreturn_t ret = IRQ_NONE; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; for (i = 0; i < num_ctrls; i++) { - dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + - (i * MSI_REG_CTRL_BLOCK_SIZE), - 4, &status); + status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS + + (i * MSI_REG_CTRL_BLOCK_SIZE)); if (!status) continue; @@ -148,6 +148,7 @@ static int dw_pci_msi_set_affinity(struct irq_data *d, static void dw_pci_bottom_mask(struct irq_data *d) { struct pcie_port *pp = irq_data_get_irq_chip_data(d); + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); unsigned int res, bit, ctrl; unsigned long flags; @@ -158,8 +159,7 @@ static void dw_pci_bottom_mask(struct irq_data *d) bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; pp->irq_mask[ctrl] |= BIT(bit); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, - pp->irq_mask[ctrl]); + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, pp->irq_mask[ctrl]); raw_spin_unlock_irqrestore(&pp->lock, flags); } @@ -167,6 +167,7 @@ static void dw_pci_bottom_mask(struct irq_data *d) static void dw_pci_bottom_unmask(struct irq_data *d) { struct pcie_port *pp = irq_data_get_irq_chip_data(d); + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); unsigned int res, bit, ctrl; unsigned long flags; @@ -177,8 +178,7 @@ static void dw_pci_bottom_unmask(struct irq_data *d) bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; pp->irq_mask[ctrl] &= ~BIT(bit); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, - pp->irq_mask[ctrl]); + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, pp->irq_mask[ctrl]); raw_spin_unlock_irqrestore(&pp->lock, flags); } @@ -186,13 +186,14 @@ static void dw_pci_bottom_unmask(struct irq_data *d) static void dw_pci_bottom_ack(struct irq_data *d) { struct pcie_port *pp = irq_data_get_irq_chip_data(d); + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); unsigned int res, bit, ctrl; ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit)); + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit)); } static struct irq_chip dw_pci_msi_bottom_irq_chip = { @@ -310,10 +311,8 @@ void dw_pcie_msi_init(struct pcie_port *pp) msi_target = (u64)pp->msi_data; /* Program the msi_data */ - dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4, - lower_32_bits(msi_target)); - dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, - upper_32_bits(msi_target)); + dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target)); + dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target)); } EXPORT_SYMBOL_GPL(dw_pcie_msi_init); @@ -327,7 +326,6 @@ int dw_pcie_host_init(struct pcie_port *pp) struct pci_bus *child; struct pci_host_bridge *bridge; struct resource *cfg_res; - u32 hdr_type; int ret; raw_spin_lock_init(&pci->pp.lock); @@ -453,21 +451,6 @@ int dw_pcie_host_init(struct pcie_port *pp) goto err_free_msi; } - ret = dw_pcie_rd_own_conf(pp, PCI_HEADER_TYPE, 1, &hdr_type); - if (ret != PCIBIOS_SUCCESSFUL) { - dev_err(pci->dev, "Failed reading PCI_HEADER_TYPE cfg space reg (ret: 0x%x)\n", - ret); - ret = pcibios_err_to_errno(ret); - goto err_free_msi; - } - if (hdr_type != PCI_HEADER_TYPE_BRIDGE) { - dev_err(pci->dev, - "PCIe controller is not set to bridge type (hdr_type: 0x%x)!\n", - hdr_type); - ret = -EIO; - goto err_free_msi; - } - bridge->sysdata = pp; bridge->ops = &dw_pcie_ops; @@ -638,12 +621,12 @@ void dw_pcie_setup_rc(struct pcie_port *pp) /* Initialize IRQ Status array */ for (ctrl = 0; ctrl < num_ctrls; ctrl++) { pp->irq_mask[ctrl] = ~0; - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), - 4, pp->irq_mask[ctrl]); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + + pp->irq_mask[ctrl]); + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), - 4, ~0); + ~0); } } @@ -685,14 +668,14 @@ void dw_pcie_setup_rc(struct pcie_port *pp) pp->io_bus_addr, pp->io_size); } - dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0); + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); /* Program correct class for RC */ - dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI); + dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); - dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val); + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); val |= PORT_LOGIC_SPEED_CHANGE; - dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val); + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); dw_pcie_dbi_ro_wr_dis(pci); } -- cgit v1.2.3 From 444ddca52484e95ae3e4dbd9fcb496419141f669 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:43 -0600 Subject: PCI: dwc: Allow overriding bridge pci_ops In preparation to allow drivers to set their own root and child pci_ops instead of using the DWC specific config space ops, we need to make the pci_host_bridge pointer available and move setting the bridge->ops and bridge->child_ops pointer to before the .host_init() hook. Link: https://lore.kernel.org/r/20200821035420.380495-4-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-host.c | 15 ++++++++++----- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 1d98554db009..b626cc7cd43a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -344,6 +344,8 @@ int dw_pcie_host_init(struct pcie_port *pp) if (!bridge) return -ENOMEM; + pp->bridge = bridge; + /* Get the I/O and memory ranges from DT */ resource_list_for_each_entry(win, &bridge->windows) { switch (resource_type(win->res)) { @@ -445,6 +447,10 @@ int dw_pcie_host_init(struct pcie_port *pp) } } + /* Set default bus ops */ + bridge->ops = &dw_pcie_ops; + bridge->child_ops = &dw_pcie_ops; + if (pp->ops->host_init) { ret = pp->ops->host_init(pp); if (ret) @@ -452,7 +458,6 @@ int dw_pcie_host_init(struct pcie_port *pp) } bridge->sysdata = pp; - bridge->ops = &dw_pcie_ops; ret = pci_scan_root_bus_bridge(bridge); if (ret) @@ -654,11 +659,11 @@ void dw_pcie_setup_rc(struct pcie_port *pp) dw_pcie_writel_dbi(pci, PCI_COMMAND, val); /* - * If the platform provides ->rd_other_conf, it means the platform - * uses its own address translation component rather than ATU, so - * we should not program the ATU here. + * If the platform provides its own child bus config accesses, it means + * the platform uses its own address translation component rather than + * ATU, so we should not program the ATU here. */ - if (!pp->ops->rd_other_conf) { + if (pp->bridge->child_ops == &dw_pcie_ops && !pp->ops->rd_other_conf) { dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, PCIE_ATU_TYPE_MEM, pp->mem_base, pp->mem_bus_addr, pp->mem_size); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index f911760dcc69..8b8ea5f3e7af 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -200,6 +200,7 @@ struct pcie_port { u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; struct pci_bus *root_bus; + struct pci_host_bridge *bridge; raw_spinlock_t lock; DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); }; -- cgit v1.2.3 From d27b1cdc10e7b2d8611b83e8db92eb7dc13d0cd5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 18 Aug 2020 15:37:39 +0200 Subject: PCI: tegra: No need to check return value of debugfs_create() functions When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Link: https://lore.kernel.org/r/20200818133739.463193-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Lorenzo Pieralisi Acked-by: Thierry Reding Cc: Lorenzo Pieralisi Cc: Rob Herring Cc: Bjorn Helgaas Cc: Thierry Reding Cc: Jonathan Hunter Cc: Vidya Sagar Cc: Andrew Murray Cc: Greg Kroah-Hartman Cc: linux-pci@vger.kernel.org Cc: linux-tegra@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/dwc/pcie-tegra194.c | 20 +++++--------------- drivers/pci/controller/pci-tegra.c | 25 +++++-------------------- 2 files changed, 10 insertions(+), 35 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 70498689d0c0..87f8dd63df0a 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -699,23 +699,16 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie) dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val); } -static int init_debugfs(struct tegra_pcie_dw *pcie) +static void init_debugfs(struct tegra_pcie_dw *pcie) { - struct dentry *d; - - d = debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt", - pcie->debugfs, aspm_state_cnt); - if (IS_ERR_OR_NULL(d)) - dev_err(pcie->dev, - "Failed to create debugfs file \"aspm_state_cnt\"\n"); - - return 0; + debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt", pcie->debugfs, + aspm_state_cnt); } #else static inline void disable_aspm_l12(struct tegra_pcie_dw *pcie) { return; } static inline void disable_aspm_l11(struct tegra_pcie_dw *pcie) { return; } static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; } -static inline int init_debugfs(struct tegra_pcie_dw *pcie) { return 0; } +static inline void init_debugfs(struct tegra_pcie_dw *pcie) { return; } #endif static void tegra_pcie_enable_system_interrupts(struct pcie_port *pp) @@ -1641,10 +1634,7 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) } pcie->debugfs = debugfs_create_dir(name, NULL); - if (!pcie->debugfs) - dev_err(dev, "Failed to create debugfs\n"); - else - init_debugfs(pcie); + init_debugfs(pcie); return ret; diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index c1d34353c29b..e1a6f9db36f7 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -2601,24 +2601,12 @@ static void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie) pcie->debugfs = NULL; } -static int tegra_pcie_debugfs_init(struct tegra_pcie *pcie) +static void tegra_pcie_debugfs_init(struct tegra_pcie *pcie) { - struct dentry *file; - pcie->debugfs = debugfs_create_dir("pcie", NULL); - if (!pcie->debugfs) - return -ENOMEM; - - file = debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, - pcie, &tegra_pcie_ports_ops); - if (!file) - goto remove; - - return 0; -remove: - tegra_pcie_debugfs_exit(pcie); - return -ENOMEM; + debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, pcie, + &tegra_pcie_ports_ops); } static int tegra_pcie_probe(struct platform_device *pdev) @@ -2672,11 +2660,8 @@ static int tegra_pcie_probe(struct platform_device *pdev) goto pm_runtime_put; } - if (IS_ENABLED(CONFIG_DEBUG_FS)) { - err = tegra_pcie_debugfs_init(pcie); - if (err < 0) - dev_err(dev, "failed to setup debugfs: %d\n", err); - } + if (IS_ENABLED(CONFIG_DEBUG_FS)) + tegra_pcie_debugfs_init(pcie); return 0; -- cgit v1.2.3 From 7d69b117c31305a36a72f337e80860478a5c8e4a Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Fri, 4 Sep 2020 15:27:10 +0100 Subject: PCI: xilinx-cpm: Remove leftover bridge initialization Some fields in the host bridge structure are now initialized by default in the PCI/OF core functions therefore their initialization in the host controller driver is superfluous. Remove it. Link: https://lore.kernel.org/r/20200904142710.8018-1-lorenzo.pieralisi@arm.com Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Cc: Rob Herring --- drivers/pci/controller/pcie-xilinx-cpm.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-xilinx-cpm.c b/drivers/pci/controller/pcie-xilinx-cpm.c index f3082de44e8a..f92e0152e65e 100644 --- a/drivers/pci/controller/pcie-xilinx-cpm.c +++ b/drivers/pci/controller/pcie-xilinx-cpm.c @@ -572,12 +572,8 @@ static int xilinx_cpm_pcie_probe(struct platform_device *pdev) goto err_setup_irq; } - bridge->dev.parent = dev; bridge->sysdata = port->cfg; - bridge->busnr = port->cfg->busr.start; bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops; - bridge->map_irq = of_irq_parse_and_map_pci; - bridge->swizzle_irq = pci_common_swizzle; err = pci_host_probe(bridge); if (err < 0) -- cgit v1.2.3 From d3d4d028afb785e52c55024d779089654f8302e7 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Tue, 1 Sep 2020 14:49:54 +0200 Subject: PCI: qcom: Make sure PCIe is reset before init for rev 2.1.0 Qsdk U-Boot can incorrectly leave the PCIe interface in an undefined state if bootm command is used instead of bootipq. This is caused by the not deinit of PCIe when bootm is called. Reset the PCIe before init anyway to fix this U-Boot bug. Link: https://lore.kernel.org/r/20200901124955.137-1-ansuelsmth@gmail.com Fixes: 82a823833f4e ("PCI: qcom: Add Qualcomm PCIe controller driver") Signed-off-by: Ansuel Smith Signed-off-by: Lorenzo Pieralisi Reviewed-by: Bjorn Andersson Cc: stable@vger.kernel.org # v4.19+ --- drivers/pci/controller/dwc/pcie-qcom.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 3aac77a295ba..82336bbaf8dc 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -302,6 +302,9 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie) reset_control_assert(res->por_reset); reset_control_assert(res->ext_reset); reset_control_assert(res->phy_reset); + + writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL); + regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies); } @@ -314,6 +317,16 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie) u32 val; int ret; + /* reset the PCIe interface as uboot can leave it undefined state */ + reset_control_assert(res->pci_reset); + reset_control_assert(res->axi_reset); + reset_control_assert(res->ahb_reset); + reset_control_assert(res->por_reset); + reset_control_assert(res->ext_reset); + reset_control_assert(res->phy_reset); + + writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL); + ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies); if (ret < 0) { dev_err(dev, "cannot enable regulators\n"); -- cgit v1.2.3 From b32c012e4b98f0126aa327be2d1f409963057643 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 7 Sep 2020 13:10:34 +0200 Subject: PCI: aardvark: Fix compilation on s390 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include linux/gpio/consumer.h instead of linux/gpio.h, as is said in the latter file. This was reported by kernel test bot when compiling for s390. drivers/pci/controller/pci-aardvark.c:350:2: error: implicit declaration of function 'gpiod_set_value_cansleep' [-Werror,-Wimplicit-function-declaration] drivers/pci/controller/pci-aardvark.c:1074:21: error: implicit declaration of function 'devm_gpiod_get_from_of_node' [-Werror,-Wimplicit-function-declaration] drivers/pci/controller/pci-aardvark.c:1076:14: error: use of undeclared identifier 'GPIOD_OUT_LOW' Link: https://lore.kernel.org/r/202006211118.LxtENQfl%25lkp@intel.com Link: https://lore.kernel.org/r/20200907111038.5811-2-pali@kernel.org Fixes: 5169a9851daa ("PCI: aardvark: Issue PERST via GPIO") Reported-by: kernel test robot Signed-off-by: Pali Rohár Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún --- drivers/pci/controller/pci-aardvark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 1559f79e63b6..1c5f2fd47c51 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include #include -- cgit v1.2.3 From 7862a6134456c8b4f8c39e8c94aa97e5c2f7f2b7 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 7 Sep 2020 13:10:35 +0200 Subject: PCI: aardvark: Check for errors from pci_bridge_emul_init() call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function pci_bridge_emul_init() may fail so correctly check for errors. Link: https://lore.kernel.org/r/20200907111038.5811-3-pali@kernel.org Fixes: 8a3ebd8de328 ("PCI: aardvark: Implement emulated root PCI bridge config space") Signed-off-by: Pali Rohár Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún --- drivers/pci/controller/pci-aardvark.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 1c5f2fd47c51..2e2e2a2ff51d 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -607,7 +607,7 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = { * Initialize the configuration space of the PCI-to-PCI bridge * associated with the given PCIe interface. */ -static void advk_sw_pci_bridge_init(struct advk_pcie *pcie) +static int advk_sw_pci_bridge_init(struct advk_pcie *pcie) { struct pci_bridge_emul *bridge = &pcie->bridge; @@ -633,8 +633,7 @@ static void advk_sw_pci_bridge_init(struct advk_pcie *pcie) bridge->data = pcie; bridge->ops = &advk_pci_bridge_emul_ops; - pci_bridge_emul_init(bridge, 0); - + return pci_bridge_emul_init(bridge, 0); } static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus, @@ -1167,7 +1166,11 @@ static int advk_pcie_probe(struct platform_device *pdev) advk_pcie_setup_hw(pcie); - advk_sw_pci_bridge_init(pcie); + ret = advk_sw_pci_bridge_init(pcie); + if (ret) { + dev_err(dev, "Failed to register emulated root PCI bridge\n"); + return ret; + } ret = advk_pcie_init_irq_domain(pcie); if (ret) { -- cgit v1.2.3 From 526a76991b7b791aa00037c27a653536e5f01c26 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 7 Sep 2020 13:10:37 +0200 Subject: PCI: aardvark: Implement driver 'remove' function and allow to build it as module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Providing driver's 'remove' function allows kernel to bind and unbind devices from aardvark driver. It also allows to build aardvark driver as a module. Compiling aardvark as a module simplifies development and debugging of this driver as it can be reloaded at runtime without the need to reboot to new kernel. Link: https://lore.kernel.org/r/20200907111038.5811-5-pali@kernel.org Signed-off-by: Pali Rohár Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún --- drivers/pci/controller/Kconfig | 2 +- drivers/pci/controller/pci-aardvark.c | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index f18c3725ef80..a7aa22512a92 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -12,7 +12,7 @@ config PCI_MVEBU select PCI_BRIDGE_EMUL config PCI_AARDVARK - bool "Aardvark PCIe controller" + tristate "Aardvark PCIe controller" depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST depends on OF depends on PCI_MSI_IRQ_DOMAIN diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 2e2e2a2ff51d..b16822e344ab 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1121,6 +1122,7 @@ static int advk_pcie_probe(struct platform_device *pdev) pcie = pci_host_bridge_priv(bridge); pcie->pdev = pdev; + platform_set_drvdata(pdev, pcie); pcie->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pcie->base)) @@ -1198,18 +1200,37 @@ static int advk_pcie_probe(struct platform_device *pdev) return 0; } +static int advk_pcie_remove(struct platform_device *pdev) +{ + struct advk_pcie *pcie = platform_get_drvdata(pdev); + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); + + pci_lock_rescan_remove(); + pci_stop_root_bus(bridge->bus); + pci_remove_root_bus(bridge->bus); + pci_unlock_rescan_remove(); + + advk_pcie_remove_msi_irq_domain(pcie); + advk_pcie_remove_irq_domain(pcie); + + return 0; +} + static const struct of_device_id advk_pcie_of_match_table[] = { { .compatible = "marvell,armada-3700-pcie", }, {}, }; +MODULE_DEVICE_TABLE(of, advk_pcie_of_match_table); static struct platform_driver advk_pcie_driver = { .driver = { .name = "advk-pcie", .of_match_table = advk_pcie_of_match_table, - /* Driver unloading/unbinding currently not supported */ - .suppress_bind_attrs = true, }, .probe = advk_pcie_probe, + .remove = advk_pcie_remove, }; -builtin_platform_driver(advk_pcie_driver); +module_platform_driver(advk_pcie_driver); + +MODULE_DESCRIPTION("Aardvark PCIe controller"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From d0c6a3475b033960e85ae2bf176b14cab0a627d2 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 7 Sep 2020 13:10:38 +0200 Subject: PCI: aardvark: Move PCIe reset card code to advk_pcie_train_link() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move code which belongs to link training (delays and resets) into advk_pcie_train_link() function, so everything related to link training, including timings is at one place. After experiments it can be observed that link training in aardvark hardware is very sensitive to timings and delays, so it is a good idea to have this code at the same place as link training calls. This patch does not change behavior of aardvark initialization. Link: https://lore.kernel.org/r/20200907111038.5811-6-pali@kernel.org Tested-by: Marek Behún Signed-off-by: Pali Rohár Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-aardvark.c | 64 +++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 30 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index b16822e344ab..50ab6d7519ae 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -252,6 +252,25 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie) } } +static void advk_pcie_issue_perst(struct advk_pcie *pcie) +{ + u32 reg; + + if (!pcie->reset_gpio) + return; + + /* PERST does not work for some cards when link training is enabled */ + reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG); + reg &= ~LINK_TRAINING_EN; + advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG); + + /* 10ms delay is needed for some cards */ + dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n"); + gpiod_set_value_cansleep(pcie->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(pcie->reset_gpio, 0); +} + static int advk_pcie_train_at_gen(struct advk_pcie *pcie, int gen) { int ret, neg_gen; @@ -299,6 +318,21 @@ static void advk_pcie_train_link(struct advk_pcie *pcie) struct device *dev = &pcie->pdev->dev; int neg_gen = -1, gen; + /* + * Reset PCIe card via PERST# signal. Some cards are not detected + * during link training when they are in some non-initial state. + */ + advk_pcie_issue_perst(pcie); + + /* + * PERST# signal could have been asserted by pinctrl subsystem before + * probe() callback has been called or issued explicitly by reset gpio + * function advk_pcie_issue_perst(), making the endpoint going into + * fundamental reset. As required by PCI Express spec a delay for at + * least 100ms after such a reset before link training is needed. + */ + msleep(PCI_PM_D3COLD_WAIT); + /* * Try link training at link gen specified by device tree property * 'max-link-speed'. If this fails, iteratively train at lower gen. @@ -331,31 +365,10 @@ err: dev_err(dev, "link never came up\n"); } -static void advk_pcie_issue_perst(struct advk_pcie *pcie) -{ - u32 reg; - - if (!pcie->reset_gpio) - return; - - /* PERST does not work for some cards when link training is enabled */ - reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG); - reg &= ~LINK_TRAINING_EN; - advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG); - - /* 10ms delay is needed for some cards */ - dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n"); - gpiod_set_value_cansleep(pcie->reset_gpio, 1); - usleep_range(10000, 11000); - gpiod_set_value_cansleep(pcie->reset_gpio, 0); -} - static void advk_pcie_setup_hw(struct advk_pcie *pcie) { u32 reg; - advk_pcie_issue_perst(pcie); - /* Enable TX */ reg = advk_readl(pcie, PCIE_CORE_REF_CLK_REG); reg |= PCIE_CORE_REF_CLK_TX_ENABLE; @@ -432,15 +445,6 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) reg |= PIO_CTRL_ADDR_WIN_DISABLE; advk_writel(pcie, reg, PIO_CTRL); - /* - * PERST# signal could have been asserted by pinctrl subsystem before - * probe() callback has been called or issued explicitly by reset gpio - * function advk_pcie_issue_perst(), making the endpoint going into - * fundamental reset. As required by PCI Express spec a delay for at - * least 100ms after such a reset before link training is needed. - */ - msleep(PCI_PM_D3COLD_WAIT); - advk_pcie_train_link(pcie); /* -- cgit v1.2.3 From 44c9b4cc34672e615e3b609dadff24a99957283f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 21 Jul 2020 22:28:51 -0500 Subject: PCI: rcar-gen2: Use fallthrough pseudo-keyword Replace the existing /* fall through */ comments and its variants with the new pseudo-keyword macro fallthrough[1]. [1] https://www.kernel.org/doc/html/v5.7/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Link: https://lore.kernel.org/r/20200722032851.GA4251@embeddedor Signed-off-by: Gustavo A. R. Silva Signed-off-by: Lorenzo Pieralisi Reviewed-by: Geert Uytterhoeven Reviewed-by: Yoshihiro Shimoda --- drivers/pci/controller/pci-rcar-gen2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-rcar-gen2.c b/drivers/pci/controller/pci-rcar-gen2.c index c9530038ca9a..afde4aa8f6dc 100644 --- a/drivers/pci/controller/pci-rcar-gen2.c +++ b/drivers/pci/controller/pci-rcar-gen2.c @@ -223,7 +223,7 @@ static void rcar_pci_setup(struct rcar_pci_priv *priv) pr_warn("unknown window size %ld - defaulting to 256M\n", window_size); window_size = SZ_256M; - /* fall-through */ + fallthrough; case SZ_256M: val |= RCAR_USBCTR_PCIAHB_WIN1_256M; break; -- cgit v1.2.3 From 73abd0bf89d27599a2a79a52c1e611ab892930fb Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 21 Jul 2020 22:19:03 -0500 Subject: PCI: imx6: Use fallthrough pseudo-keyword Replace the existing /* fall through */ comments and its variants with the new pseudo-keyword macro fallthrough[1]. Also, remove unnecessary fall-through markings when it is the case. [1] https://www.kernel.org/doc/html/v5.7/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Link: https://lore.kernel.org/r/20200722031903.GA3711@embeddedor Signed-off-by: Gustavo A. R. Silva Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-imx6.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 90df28c7cb0c..5fef2613b223 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -439,7 +439,7 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6SX_GPR12_PCIE_TEST_POWERDOWN, 0); break; - case IMX6QP: /* FALLTHROUGH */ + case IMX6QP: case IMX6Q: /* power up core phy and enable ref clock */ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, @@ -642,7 +642,7 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6SX_GPR12_PCIE_RX_EQ_MASK, IMX6SX_GPR12_PCIE_RX_EQ_2); - /* FALLTHROUGH */ + fallthrough; default: regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); @@ -1105,7 +1105,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) dev_err(dev, "pcie_aux clock source missing or invalid\n"); return PTR_ERR(imx6_pcie->pcie_aux); } - /* fall through */ + fallthrough; case IMX7D: if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR) imx6_pcie->controller_id = 1; -- cgit v1.2.3 From 61660dbf08e11e9f32f74fc76bd3f50f1319a15c Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 11 Aug 2020 09:29:24 +0800 Subject: PCI: imx6: Do not output error message when devm_clk_get() failed with -EPROBE_DEFER When devm_clk_get() returns -EPROBE_DEFER, i.MX6 PCI driver should NOT print error message, use dev_err_probe() to handle it. Link: https://lore.kernel.org/r/1597109364-4739-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Anson Huang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 5fef2613b223..d88d30ba6b47 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1073,38 +1073,33 @@ static int imx6_pcie_probe(struct platform_device *pdev) /* Fetch clocks */ imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy"); - if (IS_ERR(imx6_pcie->pcie_phy)) { - dev_err(dev, "pcie_phy clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie_phy); - } + if (IS_ERR(imx6_pcie->pcie_phy)) + return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy), + "pcie_phy clock source missing or invalid\n"); imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus"); - if (IS_ERR(imx6_pcie->pcie_bus)) { - dev_err(dev, "pcie_bus clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie_bus); - } + if (IS_ERR(imx6_pcie->pcie_bus)) + return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_bus), + "pcie_bus clock source missing or invalid\n"); imx6_pcie->pcie = devm_clk_get(dev, "pcie"); - if (IS_ERR(imx6_pcie->pcie)) { - dev_err(dev, "pcie clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie); - } + if (IS_ERR(imx6_pcie->pcie)) + return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie), + "pcie clock source missing or invalid\n"); switch (imx6_pcie->drvdata->variant) { case IMX6SX: imx6_pcie->pcie_inbound_axi = devm_clk_get(dev, "pcie_inbound_axi"); - if (IS_ERR(imx6_pcie->pcie_inbound_axi)) { - dev_err(dev, "pcie_inbound_axi clock missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie_inbound_axi); - } + if (IS_ERR(imx6_pcie->pcie_inbound_axi)) + return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_inbound_axi), + "pcie_inbound_axi clock missing or invalid\n"); break; case IMX8MQ: imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux"); - if (IS_ERR(imx6_pcie->pcie_aux)) { - dev_err(dev, "pcie_aux clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie_aux); - } + if (IS_ERR(imx6_pcie->pcie_aux)) + return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux), + "pcie_aux clock source missing or invalid\n"); fallthrough; case IMX7D: if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR) -- cgit v1.2.3 From c7e592a6a5413c780f846d9b053fb132fedb63b8 Mon Sep 17 00:00:00 2001 From: Flavio Suligoi Date: Tue, 23 Jun 2020 09:48:51 +0200 Subject: PCI: cadence-ep: Remove obsolete path from comment This comment still refers to the old driver pathname, when all PCI drivers were located directly under the drivers/pci directory. Anyway the function name itself is enough, so we can remove the overabundant path reference. Link: https://lore.kernel.org/r/20200623074851.7832-1-f.suligoi@asem.it Signed-off-by: Flavio Suligoi Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 254a3e1eff50..84cc58dc8512 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -328,7 +328,6 @@ static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx) cdns_pcie_ep_assert_intx(ep, fn, intx, true); /* * The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq() - * from drivers/pci/dwc/pci-dra7xx.c */ mdelay(1); cdns_pcie_ep_assert_intx(ep, fn, intx, false); -- cgit v1.2.3 From 27e7ed018113e7b96f13100787ba8c0553a63b81 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:44 -0600 Subject: PCI: dwc: Add a default pci_ops.map_bus for root port The Designware root port config space is memory mapped accesses via the DBI space by default. Add a common implementation dw_pcie_own_conf_map_bus() for platforms to use. Link: https://lore.kernel.org/r/20200821035420.380495-5-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-host.c | 12 ++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 8 ++++++++ 2 files changed, 20 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index b626cc7cd43a..feb3625f7d4d 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -602,6 +602,18 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn, return dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val); } +void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn, int where) +{ + struct pcie_port *pp = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + + if (PCI_SLOT(devfn) > 0) + return NULL; + + return pci->dbi_base + where; +} +EXPORT_SYMBOL_GPL(dw_pcie_own_conf_map_bus); + static struct pci_ops dw_pcie_ops = { .read = dw_pcie_rd_conf, .write = dw_pcie_wr_conf, diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 8b8ea5f3e7af..01345b8e4171 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -377,6 +377,8 @@ void dw_pcie_setup_rc(struct pcie_port *pp); int dw_pcie_host_init(struct pcie_port *pp); void dw_pcie_host_deinit(struct pcie_port *pp); int dw_pcie_allocate_domains(struct pcie_port *pp); +void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn, + int where); #else static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) { @@ -408,6 +410,12 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp) { return 0; } +static inline void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, + unsigned int devfn, + int where) +{ + return NULL; +} #endif #ifdef CONFIG_PCIE_DW_EP -- cgit v1.2.3 From fffbb0ba8e7504291678b5d991416f2d7adc0372 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:45 -0600 Subject: PCI: dwc: al: Use pci_ops for child config space accessors Now that DWC drivers can setup their own pci_ops for the root and child buses, convert the Amazon driver to use the standard pci_ops for child bus config accesses. Link: https://lore.kernel.org/r/20200821035420.380495-6-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jonathan Chocron Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-al.c | 63 ++++++++---------------------------- 1 file changed, 13 insertions(+), 50 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c index d57d4ee15848..59e33d3a8380 100644 --- a/drivers/pci/controller/dwc/pcie-al.c +++ b/drivers/pci/controller/dwc/pcie-al.c @@ -217,14 +217,15 @@ static inline void al_pcie_target_bus_set(struct al_pcie *pcie, reg); } -static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie, - unsigned int busnr, - unsigned int devfn) +static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus, + unsigned int devfn, int where) { + struct pcie_port *pp = bus->sysdata; + struct al_pcie *pcie = to_al_pcie(to_dw_pcie_from_pp(pp)); + unsigned int busnr = bus->number; struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg; unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask; unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask; - struct pcie_port *pp = &pcie->pci->pp; void __iomem *pci_base_addr; pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base + @@ -240,52 +241,14 @@ static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie, target_bus_cfg->reg_mask); } - return pci_base_addr; -} - -static int al_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, - u32 *val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct al_pcie *pcie = to_al_pcie(pci); - unsigned int busnr = bus->number; - void __iomem *pci_addr; - int rc; - - pci_addr = al_pcie_conf_addr_map(pcie, busnr, devfn); - - rc = dw_pcie_read(pci_addr + where, size, val); - - dev_dbg(pci->dev, "%d-byte config read from %04x:%02x:%02x.%d offset 0x%x (pci_addr: 0x%px) - val:0x%x\n", - size, pci_domain_nr(bus), bus->number, - PCI_SLOT(devfn), PCI_FUNC(devfn), where, - (pci_addr + where), *val); - - return rc; + return pci_base_addr + where; } -static int al_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, - u32 val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct al_pcie *pcie = to_al_pcie(pci); - unsigned int busnr = bus->number; - void __iomem *pci_addr; - int rc; - - pci_addr = al_pcie_conf_addr_map(pcie, busnr, devfn); - - rc = dw_pcie_write(pci_addr + where, size, val); - - dev_dbg(pci->dev, "%d-byte config write to %04x:%02x:%02x.%d offset 0x%x (pci_addr: 0x%px) - val:0x%x\n", - size, pci_domain_nr(bus), bus->number, - PCI_SLOT(devfn), PCI_FUNC(devfn), where, - (pci_addr + where), val); - - return rc; -} +static struct pci_ops al_child_pci_ops = { + .map_bus = al_pcie_conf_addr_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; static void al_pcie_config_prepare(struct al_pcie *pcie) { @@ -339,6 +302,8 @@ static int al_pcie_host_init(struct pcie_port *pp) struct al_pcie *pcie = to_al_pcie(pci); int rc; + pp->bridge->child_ops = &al_child_pci_ops; + rc = al_pcie_rev_id_get(pcie, &pcie->controller_rev_id); if (rc) return rc; @@ -353,8 +318,6 @@ static int al_pcie_host_init(struct pcie_port *pp) } static const struct dw_pcie_host_ops al_pcie_host_ops = { - .rd_other_conf = al_pcie_rd_other_conf, - .wr_other_conf = al_pcie_wr_other_conf, .host_init = al_pcie_host_init, }; -- cgit v1.2.3 From 10a797c6e54a5eb9f840e293ee3c2dbf28595bff Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:46 -0600 Subject: PCI: dwc: keystone: Use pci_ops for config space accessors Now that DWC drivers can setup their own pci_ops for the root and child buses, convert the TI Keystone driver to use the standard pci_ops for config accesses. Link: https://lore.kernel.org/r/20200821035420.380495-7-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Murali Karicheri Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-keystone.c | 40 ++++++++++++++----------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index c8c9d6a75f17..2b0906e1e0d3 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -430,10 +430,10 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) ks_pcie_app_writel(ks_pcie, CMD_STATUS, val); } -static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, - u32 *val) +static void __iomem *ks_pcie_other_map_bus(struct pci_bus *bus, + unsigned int devfn, int where) { + struct pcie_port *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); u32 reg; @@ -444,25 +444,14 @@ static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, reg |= CFG_TYPE1; ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg); - return dw_pcie_read(pp->va_cfg0_base + where, size, val); + return pp->va_cfg0_base + where; } -static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, - u32 val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u32 reg; - - reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) | - CFG_FUNC(PCI_FUNC(devfn)); - if (!pci_is_root_bus(bus->parent)) - reg |= CFG_TYPE1; - ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg); - - return dw_pcie_write(pp->va_cfg0_base + where, size, val); -} +static struct pci_ops ks_child_pcie_ops = { + .map_bus = ks_pcie_other_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; /** * ks_pcie_v3_65_scan_bus() - keystone scan_bus post initialization @@ -490,6 +479,12 @@ static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp) dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start); } +static struct pci_ops ks_pcie_ops = { + .map_bus = dw_pcie_own_conf_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; + /** * ks_pcie_link_up() - Check if link up */ @@ -807,6 +802,9 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); int ret; + pp->bridge->ops = &ks_pcie_ops; + pp->bridge->child_ops = &ks_child_pcie_ops; + ret = ks_pcie_config_legacy_irq(ks_pcie); if (ret) return ret; @@ -842,8 +840,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) } static const struct dw_pcie_host_ops ks_pcie_host_ops = { - .rd_other_conf = ks_pcie_rd_other_conf, - .wr_other_conf = ks_pcie_wr_other_conf, .host_init = ks_pcie_host_init, .msi_host_init = ks_pcie_msi_host_init, .scan_bus = ks_pcie_v3_65_scan_bus, -- cgit v1.2.3 From 692ccce7f0c57464f1ada8b7ea4a2346b5319bc6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:47 -0600 Subject: PCI: dwc: tegra: Use pci_ops for root config space accessors Now that DWC drivers can setup their own pci_ops for the root and child buses, convert the Tegra driver to use the standard pci_ops for root bus config accesses. Link: https://lore.kernel.org/r/20200821035420.380495-8-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pcie-tegra194.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 70498689d0c0..b723c9f3ece4 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -568,42 +568,44 @@ static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg) return IRQ_HANDLED; } -static int tegra_pcie_dw_rd_own_conf(struct pcie_port *pp, int where, int size, - u32 *val) +static int tegra_pcie_dw_rd_own_conf(struct pci_bus *bus, u32 devfn, int where, + int size, u32 *val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - /* * This is an endpoint mode specific register happen to appear even * when controller is operating in root port mode and system hangs * when it is accessed with link being in ASPM-L1 state. * So skip accessing it altogether */ - if (where == PORT_LOGIC_MSIX_DOORBELL) { + if (!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) { *val = 0x00000000; return PCIBIOS_SUCCESSFUL; } - return dw_pcie_read(pci->dbi_base + where, size, val); + return pci_generic_config_read(bus, devfn, where, size, val); } -static int tegra_pcie_dw_wr_own_conf(struct pcie_port *pp, int where, int size, - u32 val) +static int tegra_pcie_dw_wr_own_conf(struct pci_bus *bus, u32 devfn, int where, + int size, u32 val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - /* * This is an endpoint mode specific register happen to appear even * when controller is operating in root port mode and system hangs * when it is accessed with link being in ASPM-L1 state. * So skip accessing it altogether */ - if (where == PORT_LOGIC_MSIX_DOORBELL) + if (!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) return PCIBIOS_SUCCESSFUL; - return dw_pcie_write(pci->dbi_base + where, size, val); + return pci_generic_config_write(bus, devfn, where, size, val); } +static struct pci_ops tegra_pci_ops = { + .map_bus = dw_pcie_own_conf_map_bus, + .read = tegra_pcie_dw_rd_own_conf, + .write = tegra_pcie_dw_wr_own_conf, +}; + #if defined(CONFIG_PCIEASPM) static void disable_aspm_l11(struct tegra_pcie_dw *pcie) { @@ -970,6 +972,8 @@ static int tegra_pcie_dw_host_init(struct pcie_port *pp) struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); u32 val, tmp, offset, speed; + pp->bridge->ops = &tegra_pci_ops; + tegra_pcie_prepare_host(pp); if (dw_pcie_wait_for_link(pci)) { @@ -1057,8 +1061,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = { }; static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = { - .rd_own_conf = tegra_pcie_dw_rd_own_conf, - .wr_own_conf = tegra_pcie_dw_wr_own_conf, .host_init = tegra_pcie_dw_host_init, .set_num_vectors = tegra_pcie_set_msi_vec_num, }; -- cgit v1.2.3 From e0ceb8f90b80f88ab6f7bad058e584b305e930d0 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:48 -0600 Subject: PCI: dwc: meson: Use pci_ops for root config space accessors Now that DWC drivers can setup their own pci_ops for the root and child buses, convert the Amlogic meson driver to use the standard pci_ops for root bus config accesses. Link: https://lore.kernel.org/r/20200821035420.380495-9-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Yue Wang Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kevin Hilman Cc: linux-amlogic@lists.infradead.org --- drivers/pci/controller/dwc/pci-meson.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 4f183b96afbb..f4d822190359 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -383,13 +383,12 @@ static void meson_pcie_enable_interrupts(struct meson_pcie *mp) dw_pcie_msi_init(&mp->pci.pp); } -static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, - u32 *val) +static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn, + int where, int size, u32 *val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); int ret; - ret = dw_pcie_read(pci->dbi_base + where, size, val); + ret = pci_generic_config_read(bus, devfn, where, size, val); if (ret != PCIBIOS_SUCCESSFUL) return ret; @@ -410,13 +409,11 @@ static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, return PCIBIOS_SUCCESSFUL; } -static int meson_pcie_wr_own_conf(struct pcie_port *pp, int where, - int size, u32 val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - - return dw_pcie_write(pci->dbi_base + where, size, val); -} +static struct pci_ops meson_pci_ops = { + .map_bus = dw_pcie_own_conf_map_bus, + .read = meson_pcie_rd_own_conf, + .write = pci_generic_config_write, +}; static int meson_pcie_link_up(struct dw_pcie *pci) { @@ -463,6 +460,8 @@ static int meson_pcie_host_init(struct pcie_port *pp) struct meson_pcie *mp = to_meson_pcie(pci); int ret; + pp->bridge->ops = &meson_pci_ops; + ret = meson_pcie_establish_link(mp); if (ret) return ret; @@ -473,8 +472,6 @@ static int meson_pcie_host_init(struct pcie_port *pp) } static const struct dw_pcie_host_ops meson_pcie_host_ops = { - .rd_own_conf = meson_pcie_rd_own_conf, - .wr_own_conf = meson_pcie_wr_own_conf, .host_init = meson_pcie_host_init, }; -- cgit v1.2.3 From 6408e6a7f9eec6fbd3f75680ad3983c79ccd446d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:49 -0600 Subject: PCI: dwc: kirin: Use pci_ops for root config space accessors Now that DWC drivers can setup their own pci_ops for the root and child buses, convert the HiSilicon Kirin driver to use the standard pci_ops for root bus config accesses. Link: https://lore.kernel.org/r/20200821035420.380495-10-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Xiaowei Song Cc: Binghui Wang Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-kirin.c | 39 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index e496f51e0152..8a01ab0a4a65 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -330,34 +330,37 @@ static void kirin_pcie_sideband_dbi_r_mode(struct kirin_pcie *kirin_pcie, kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL1_ADDR); } -static int kirin_pcie_rd_own_conf(struct pcie_port *pp, +static int kirin_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci); - int ret; + struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata); - kirin_pcie_sideband_dbi_r_mode(kirin_pcie, true); - ret = dw_pcie_read(pci->dbi_base + where, size, val); - kirin_pcie_sideband_dbi_r_mode(kirin_pcie, false); + if (PCI_SLOT(devfn)) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } - return ret; + *val = dw_pcie_read_dbi(pci, where, size); + return PCIBIOS_SUCCESSFUL; } -static int kirin_pcie_wr_own_conf(struct pcie_port *pp, +static int kirin_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci); - int ret; + struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata); - kirin_pcie_sideband_dbi_w_mode(kirin_pcie, true); - ret = dw_pcie_write(pci->dbi_base + where, size, val); - kirin_pcie_sideband_dbi_w_mode(kirin_pcie, false); + if (PCI_SLOT(devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; - return ret; + dw_pcie_write_dbi(pci, where, size, val); + return PCIBIOS_SUCCESSFUL; } +static struct pci_ops kirin_pci_ops = { + .read = kirin_pcie_rd_own_conf, + .write = kirin_pcie_wr_own_conf, +}; + static u32 kirin_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size) { @@ -423,6 +426,8 @@ static int kirin_pcie_establish_link(struct pcie_port *pp) static int kirin_pcie_host_init(struct pcie_port *pp) { + pp->bridge->ops = &kirin_pci_ops; + kirin_pcie_establish_link(pp); if (IS_ENABLED(CONFIG_PCI_MSI)) @@ -438,8 +443,6 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = { }; static const struct dw_pcie_host_ops kirin_pcie_host_ops = { - .rd_own_conf = kirin_pcie_rd_own_conf, - .wr_own_conf = kirin_pcie_wr_own_conf, .host_init = kirin_pcie_host_init, }; -- cgit v1.2.3 From 08d2209e798aedde0e0be7e39ed0165a6c77c178 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:50 -0600 Subject: PCI: dwc: exynos: Use pci_ops for root config space accessors Now that DWC drivers can setup their own pci_ops for the root and child buses, convert the Samsung Exynos driver to use the standard pci_ops for root bus config accesses. Link: https://lore.kernel.org/r/20200821035420.380495-11-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: linux-samsung-soc@vger.kernel.org --- drivers/pci/controller/dwc/pci-exynos.c | 45 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 8d82c43ae299..242683cde04a 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -336,32 +336,37 @@ static void exynos_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, exynos_pcie_sideband_dbi_w_mode(ep, false); } -static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, - u32 *val) +static int exynos_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct exynos_pcie *ep = to_exynos_pcie(pci); - int ret; + struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata); - exynos_pcie_sideband_dbi_r_mode(ep, true); - ret = dw_pcie_read(pci->dbi_base + where, size, val); - exynos_pcie_sideband_dbi_r_mode(ep, false); - return ret; + if (PCI_SLOT(devfn)) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + *val = dw_pcie_read_dbi(pci, where, size); + return PCIBIOS_SUCCESSFUL; } -static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, - u32 val) +static int exynos_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct exynos_pcie *ep = to_exynos_pcie(pci); - int ret; + struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata); - exynos_pcie_sideband_dbi_w_mode(ep, true); - ret = dw_pcie_write(pci->dbi_base + where, size, val); - exynos_pcie_sideband_dbi_w_mode(ep, false); - return ret; + if (PCI_SLOT(devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + dw_pcie_write_dbi(pci, where, size, val); + return PCIBIOS_SUCCESSFUL; } +static struct pci_ops exynos_pci_ops = { + .read = exynos_pcie_rd_own_conf, + .write = exynos_pcie_wr_own_conf, +}; + static int exynos_pcie_link_up(struct dw_pcie *pci) { struct exynos_pcie *ep = to_exynos_pcie(pci); @@ -379,6 +384,8 @@ static int exynos_pcie_host_init(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct exynos_pcie *ep = to_exynos_pcie(pci); + pp->bridge->ops = &exynos_pci_ops; + exynos_pcie_establish_link(ep); exynos_pcie_enable_interrupts(ep); @@ -386,8 +393,6 @@ static int exynos_pcie_host_init(struct pcie_port *pp) } static const struct dw_pcie_host_ops exynos_pcie_host_ops = { - .rd_own_conf = exynos_pcie_rd_own_conf, - .wr_own_conf = exynos_pcie_wr_own_conf, .host_init = exynos_pcie_host_init, }; -- cgit v1.2.3 From c4a42ee9acfb682c713f610efc57766d833931ba Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:51 -0600 Subject: PCI: dwc: histb: Use pci_ops for root config space accessors Now that DWC drivers can setup their own pci_ops for the root and child buses, convert the HiSilicon histb driver to use the standard pci_ops for root bus config accesses. Link: https://lore.kernel.org/r/20200821035420.380495-12-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Shawn Guo Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-histb.c | 41 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 2a2835746077..af1deae2b15d 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -122,32 +122,37 @@ static void histb_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, histb_pcie_dbi_w_mode(&pci->pp, false); } -static int histb_pcie_rd_own_conf(struct pcie_port *pp, int where, - int size, u32 *val) +static int histb_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - int ret; + struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata); - histb_pcie_dbi_r_mode(pp, true); - ret = dw_pcie_read(pci->dbi_base + where, size, val); - histb_pcie_dbi_r_mode(pp, false); + if (PCI_SLOT(devfn)) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } - return ret; + *val = dw_pcie_read_dbi(pci, where, size); + return PCIBIOS_SUCCESSFUL; } -static int histb_pcie_wr_own_conf(struct pcie_port *pp, int where, - int size, u32 val) +static int histb_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - int ret; + struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata); - histb_pcie_dbi_w_mode(pp, true); - ret = dw_pcie_write(pci->dbi_base + where, size, val); - histb_pcie_dbi_w_mode(pp, false); + if (PCI_SLOT(devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; - return ret; + dw_pcie_write_dbi(pci, where, size, val); + return PCIBIOS_SUCCESSFUL; } +static struct pci_ops histb_pci_ops = { + .read = histb_pcie_rd_own_conf, + .write = histb_pcie_wr_own_conf, +}; + static int histb_pcie_link_up(struct dw_pcie *pci) { struct histb_pcie *hipcie = to_histb_pcie(pci); @@ -194,6 +199,8 @@ static int histb_pcie_establish_link(struct pcie_port *pp) static int histb_pcie_host_init(struct pcie_port *pp) { + pp->bridge->ops = &histb_pci_ops; + histb_pcie_establish_link(pp); if (IS_ENABLED(CONFIG_PCI_MSI)) @@ -203,8 +210,6 @@ static int histb_pcie_host_init(struct pcie_port *pp) } static const struct dw_pcie_host_ops histb_pcie_host_ops = { - .rd_own_conf = histb_pcie_rd_own_conf, - .wr_own_conf = histb_pcie_wr_own_conf, .host_init = histb_pcie_host_init, }; -- cgit v1.2.3 From 7975c8cc8ed8442973c6264b2192135748c4245b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:52 -0600 Subject: PCI: dwc: Remove dwc specific config accessor ops Now that all the drivers needing custom config accessors have been converted to define their own pci_ops, we can remove the DWC specific function callbacks {rd,wr}_{own,other}_conf. Link: https://lore.kernel.org/r/20200821035420.380495-13-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-host.c | 14 -------------- drivers/pci/controller/dwc/pcie-designware.h | 6 ------ 2 files changed, 20 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index feb3625f7d4d..09071daf41ec 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -26,9 +26,6 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, { struct dw_pcie *pci; - if (pp->ops->rd_own_conf) - return pp->ops->rd_own_conf(pp, where, size, val); - pci = to_dw_pcie_from_pp(pp); return dw_pcie_read(pci->dbi_base + where, size, val); } @@ -38,9 +35,6 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, { struct dw_pcie *pci; - if (pp->ops->wr_own_conf) - return pp->ops->wr_own_conf(pp, where, size, val); - pci = to_dw_pcie_from_pp(pp); return dw_pcie_write(pci->dbi_base + where, size, val); } @@ -537,10 +531,6 @@ static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus, static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, u32 devfn, int where, int size, u32 *val) { - if (pp->ops->rd_other_conf) - return pp->ops->rd_other_conf(pp, bus, devfn, where, - size, val); - return dw_pcie_access_other_conf(pp, bus, devfn, where, size, val, false); } @@ -548,10 +538,6 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, u32 devfn, int where, int size, u32 val) { - if (pp->ops->wr_other_conf) - return pp->ops->wr_other_conf(pp, bus, devfn, where, - size, val); - return dw_pcie_access_other_conf(pp, bus, devfn, where, size, &val, true); } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 01345b8e4171..ebcd2aefb6b1 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -160,12 +160,6 @@ enum dw_pcie_device_mode { }; struct dw_pcie_host_ops { - int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val); - int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val); - int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 *val); - int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 val); int (*host_init)(struct pcie_port *pp); void (*scan_bus)(struct pcie_port *pp); void (*set_num_vectors)(struct pcie_port *pp); -- cgit v1.2.3 From c2b0c098fbd15da06f5c6c70ecc9b156fdc0eedd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:53 -0600 Subject: PCI: dwc: Use generic config accessors Now that all the platforms with custom config access handling define their own pci_ops, let's split the default config accessors to use different pci_ops for root and child buses. With this, we can use the generic config accessors. The child bus accesses mainly require a .map_bus() hook to reconfigure the iATU on each config space access. Link: https://lore.kernel.org/r/20200821035420.380495-14-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-host.c | 119 +++++++--------------- 1 file changed, 37 insertions(+), 82 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 09071daf41ec..14ffc2cd88be 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -20,24 +20,7 @@ #include "pcie-designware.h" static struct pci_ops dw_pcie_ops; - -static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, - u32 *val) -{ - struct dw_pcie *pci; - - pci = to_dw_pcie_from_pp(pp); - return dw_pcie_read(pci->dbi_base + where, size, val); -} - -static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, - u32 val) -{ - struct dw_pcie *pci; - - pci = to_dw_pcie_from_pp(pp); - return dw_pcie_write(pci->dbi_base + where, size, val); -} +static struct pci_ops dw_child_pcie_ops; static void dw_msi_ack_irq(struct irq_data *d) { @@ -443,7 +426,7 @@ int dw_pcie_host_init(struct pcie_port *pp) /* Set default bus ops */ bridge->ops = &dw_pcie_ops; - bridge->child_ops = &dw_pcie_ops; + bridge->child_ops = &dw_child_pcie_ops; if (pp->ops->host_init) { ret = pp->ops->host_init(pp); @@ -487,14 +470,14 @@ void dw_pcie_host_deinit(struct pcie_port *pp) } EXPORT_SYMBOL_GPL(dw_pcie_host_deinit); -static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus, - u32 devfn, int where, int size, u32 *val, - bool write) +static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, + unsigned int devfn, int where) { - int ret, type; + int type; u32 busdev, cfg_size; u64 cpu_addr; void __iomem *va_cfg_base; + struct pcie_port *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | @@ -515,79 +498,50 @@ static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus, dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, type, cpu_addr, busdev, cfg_size); - if (write) - ret = dw_pcie_write(va_cfg_base + where, size, *val); - else - ret = dw_pcie_read(va_cfg_base + where, size, val); - if (pci->num_viewport <= 2) - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, pp->io_base, - pp->io_bus_addr, pp->io_size); - - return ret; -} - -static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, - u32 devfn, int where, int size, u32 *val) -{ - return dw_pcie_access_other_conf(pp, bus, devfn, where, size, val, - false); + return va_cfg_base + where; } -static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, - u32 devfn, int where, int size, u32 val) -{ - return dw_pcie_access_other_conf(pp, bus, devfn, where, size, &val, - true); -} - -static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus, - int dev) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - - /* If there is no link, then there is no device */ - if (!pci_is_root_bus(bus)) { - if (!dw_pcie_link_up(pci)) - return 0; - } else if (dev > 0) - /* Access only one slot on each root port */ - return 0; - - return 1; -} - -static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, - int size, u32 *val) +static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) { + int ret; struct pcie_port *pp = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn))) { - *val = 0xffffffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } + ret = pci_generic_config_read(bus, devfn, where, size, val); - if (pci_is_root_bus(bus)) - return dw_pcie_rd_own_conf(pp, where, size, val); + if (!ret && pci->num_viewport <= 2) + dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_IO, pp->io_base, + pp->io_bus_addr, pp->io_size); - return dw_pcie_rd_other_conf(pp, bus, devfn, where, size, val); + return ret; } -static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn, - int where, int size, u32 val) +static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) { + int ret; struct pcie_port *pp = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn))) - return PCIBIOS_DEVICE_NOT_FOUND; + ret = pci_generic_config_write(bus, devfn, where, size, val); - if (pci_is_root_bus(bus)) - return dw_pcie_wr_own_conf(pp, where, size, val); + if (!ret && pci->num_viewport <= 2) + dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_IO, pp->io_base, + pp->io_bus_addr, pp->io_size); - return dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val); + return ret; } +static struct pci_ops dw_child_pcie_ops = { + .map_bus = dw_pcie_other_conf_map_bus, + .read = dw_pcie_rd_other_conf, + .write = dw_pcie_wr_other_conf, +}; + void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn, int where) { struct pcie_port *pp = bus->sysdata; @@ -601,8 +555,9 @@ void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn, EXPORT_SYMBOL_GPL(dw_pcie_own_conf_map_bus); static struct pci_ops dw_pcie_ops = { - .read = dw_pcie_rd_conf, - .write = dw_pcie_wr_conf, + .map_bus = dw_pcie_own_conf_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; void dw_pcie_setup_rc(struct pcie_port *pp) @@ -661,7 +616,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) * the platform uses its own address translation component rather than * ATU, so we should not program the ATU here. */ - if (pp->bridge->child_ops == &dw_pcie_ops && !pp->ops->rd_other_conf) { + if (pp->bridge->child_ops == &dw_child_pcie_ops) { dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, PCIE_ATU_TYPE_MEM, pp->mem_base, pp->mem_bus_addr, pp->mem_size); -- cgit v1.2.3 From 6ab15b5e7057c5d0de7316f2264c92fb7a28b340 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:55 -0600 Subject: PCI: dwc: keystone: Convert .scan_bus() callback to use add_bus TI keystone is the only Designware driver using .scan_bus(). This function pointer is the only thing preventing the Designware driver from using pci_host_probe(). Let's use the pci_ops.add_bus hook instead. Link: https://lore.kernel.org/r/20200821035420.380495-16-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Murali Karicheri Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-keystone.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 2b0906e1e0d3..fd000384fd2a 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -454,15 +454,19 @@ static struct pci_ops ks_child_pcie_ops = { }; /** - * ks_pcie_v3_65_scan_bus() - keystone scan_bus post initialization + * ks_pcie_v3_65_add_bus() - keystone add_bus post initialization * * This sets BAR0 to enable inbound access for MSI_IRQ register */ -static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp) +static int ks_pcie_v3_65_add_bus(struct pci_bus *bus) { + struct pcie_port *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + if (!pci_is_root_bus(bus)) + return 0; + /* Configure and set up BAR0 */ ks_pcie_set_dbi_mode(ks_pcie); @@ -477,12 +481,15 @@ static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp) * be sufficient. Use physical address to avoid any conflicts. */ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start); + + return 0; } static struct pci_ops ks_pcie_ops = { .map_bus = dw_pcie_own_conf_map_bus, .read = pci_generic_config_read, .write = pci_generic_config_write, + .add_bus = ks_pcie_v3_65_add_bus, }; /** @@ -842,7 +849,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) static const struct dw_pcie_host_ops ks_pcie_host_ops = { .host_init = ks_pcie_host_init, .msi_host_init = ks_pcie_msi_host_init, - .scan_bus = ks_pcie_v3_65_scan_bus, }; static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = { -- cgit v1.2.3 From 1df793054859eaa69d878f7daffc9f1cf9253a5d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:56 -0600 Subject: PCI: dwc: Convert to use pci_host_probe() Now that there are no more .scan_bus() callbacks, we can remove it and just use pci_host_probe(). Link: https://lore.kernel.org/r/20200821035420.380495-17-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-host.c | 21 +++------------------ drivers/pci/controller/dwc/pcie-designware.h | 1 - 2 files changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 14ffc2cd88be..940edb3e2d3f 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -300,7 +300,6 @@ int dw_pcie_host_init(struct pcie_port *pp) struct device_node *np = dev->of_node; struct platform_device *pdev = to_platform_device(dev); struct resource_entry *win; - struct pci_bus *child; struct pci_host_bridge *bridge; struct resource *cfg_res; int ret; @@ -436,23 +435,9 @@ int dw_pcie_host_init(struct pcie_port *pp) bridge->sysdata = pp; - ret = pci_scan_root_bus_bridge(bridge); - if (ret) - goto err_free_msi; - - pp->root_bus = bridge->bus; - - if (pp->ops->scan_bus) - pp->ops->scan_bus(pp); - - pci_bus_size_bridges(pp->root_bus); - pci_bus_assign_resources(pp->root_bus); - - list_for_each_entry(child, &pp->root_bus->children, node) - pcie_bus_configure_settings(child); - - pci_bus_add_devices(pp->root_bus); - return 0; + ret = pci_host_probe(bridge); + if (!ret) + return 0; err_free_msi: if (pci_msi_enabled() && !pp->ops->msi_host_init) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index ebcd2aefb6b1..c018f199ca44 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -161,7 +161,6 @@ enum dw_pcie_device_mode { struct dw_pcie_host_ops { int (*host_init)(struct pcie_port *pp); - void (*scan_bus)(struct pcie_port *pp); void (*set_num_vectors)(struct pcie_port *pp); int (*msi_host_init)(struct pcie_port *pp); }; -- cgit v1.2.3 From 5808d43e7c91b285032cfeb2a5317ea6890b657f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:57 -0600 Subject: PCI: dwc: Remove root_bus pointer The pci_host_bridge struct already has a pointer to its pci_bus, so let's convert the one user to use the bridge struct and remove the private 'root_bus' pointer. Link: https://lore.kernel.org/r/20200821035420.380495-18-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pcie-designware-host.c | 4 ++-- drivers/pci/controller/dwc/pcie-designware.h | 1 - drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 940edb3e2d3f..ca9d4e407b03 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -448,8 +448,8 @@ EXPORT_SYMBOL_GPL(dw_pcie_host_init); void dw_pcie_host_deinit(struct pcie_port *pp) { - pci_stop_root_bus(pp->root_bus); - pci_remove_root_bus(pp->root_bus); + pci_stop_root_bus(pp->bridge->bus); + pci_remove_root_bus(pp->bridge->bus); if (pci_msi_enabled() && !pp->ops->msi_host_init) dw_pcie_free_msi(pp); } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index c018f199ca44..a24229d95714 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -192,7 +192,6 @@ struct pcie_port { struct irq_chip *msi_irq_chip; u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; - struct pci_bus *root_bus; struct pci_host_bridge *bridge; raw_spinlock_t lock; DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index b723c9f3ece4..a5dce56b3b7a 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1264,9 +1264,9 @@ static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) * 5.2 Link State Power Management (Page #428). */ - list_for_each_entry(child, &pp->root_bus->children, node) { + list_for_each_entry(child, &pp->bridge->bus->children, node) { /* Bring downstream devices to D0 if they are not already in */ - if (child->parent == pp->root_bus) { + if (child->parent == pp->bridge->bus) { root_bus = child; break; } -- cgit v1.2.3 From 0f71c60ffd26943fa9646aa73ad7889ace116ce2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:58 -0600 Subject: PCI: dwc: Remove storing of PCI resources The PCI bridge resources are stored in pci_host_bridge.windows, so there's no need to store them in a DWC specific struct. There's also no need to parse the resources and store them a 2nd time as they are mainly used for one time setup of iATU windows. Link: https://lore.kernel.org/r/20200821035420.380495-19-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Murali Karicheri Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Jonathan Chocron Cc: Jingoo Han Cc: Gustavo Pimentel --- drivers/pci/controller/dwc/pci-keystone.c | 8 +++++-- drivers/pci/controller/dwc/pcie-al.c | 7 +++--- drivers/pci/controller/dwc/pcie-designware-host.c | 27 ++++++++--------------- drivers/pci/controller/dwc/pcie-designware.h | 6 ----- 4 files changed, 19 insertions(+), 29 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index fd000384fd2a..d306914a1f93 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -400,10 +400,14 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) u32 num_viewport = ks_pcie->num_viewport; struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; - u64 start = pp->mem->start; - u64 end = pp->mem->end; + u64 start, end; + struct resource *mem; int i; + mem = resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM)->res; + start = mem->start; + end = mem->end; + /* Disable BARs for inbound access */ ks_pcie_set_dbi_mode(ks_pcie); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c index 59e33d3a8380..f973fbca90cf 100644 --- a/drivers/pci/controller/dwc/pcie-al.c +++ b/drivers/pci/controller/dwc/pcie-al.c @@ -260,6 +260,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie) u8 secondary_bus; u32 cfg_control; u32 reg; + struct resource *bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS)->res; target_bus_cfg = &pcie->target_bus_cfg; @@ -273,13 +274,13 @@ static void al_pcie_config_prepare(struct al_pcie *pcie) target_bus_cfg->ecam_mask = ecam_bus_mask; /* This portion is taken from the cfg_target_bus reg */ target_bus_cfg->reg_mask = ~target_bus_cfg->ecam_mask; - target_bus_cfg->reg_val = pp->busn->start & target_bus_cfg->reg_mask; + target_bus_cfg->reg_val = bus->start & target_bus_cfg->reg_mask; al_pcie_target_bus_set(pcie, target_bus_cfg->reg_val, target_bus_cfg->reg_mask); - secondary_bus = pp->busn->start + 1; - subordinate_bus = pp->busn->end; + secondary_bus = bus->start + 1; + subordinate_bus = bus->end; /* Set the valid values of secondary and subordinate buses */ cfg_control_offset = AXI_BASE_OFFSET + pcie->reg_offsets.ob_ctrl + diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index ca9d4e407b03..b40aeae78809 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -326,17 +326,9 @@ int dw_pcie_host_init(struct pcie_port *pp) resource_list_for_each_entry(win, &bridge->windows) { switch (resource_type(win->res)) { case IORESOURCE_IO: - pp->io = win->res; - pp->io->name = "I/O"; - pp->io_size = resource_size(pp->io); - pp->io_bus_addr = pp->io->start - win->offset; - pp->io_base = pci_pio_to_address(pp->io->start); - break; - case IORESOURCE_MEM: - pp->mem = win->res; - pp->mem->name = "MEM"; - pp->mem_size = resource_size(pp->mem); - pp->mem_bus_addr = pp->mem->start - win->offset; + pp->io_size = resource_size(win->res); + pp->io_bus_addr = win->res->start - win->offset; + pp->io_base = pci_pio_to_address(win->res->start); break; case 0: pp->cfg = win->res; @@ -345,9 +337,6 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->cfg0_base = pp->cfg->start; pp->cfg1_base = pp->cfg->start + pp->cfg0_size; break; - case IORESOURCE_BUS: - pp->busn = win->res; - break; } } @@ -361,8 +350,6 @@ int dw_pcie_host_init(struct pcie_port *pp) } } - pp->mem_base = pp->mem->start; - if (!pp->va_cfg0_base) { pp->va_cfg0_base = devm_pci_remap_cfgspace(dev, pp->cfg0_base, pp->cfg0_size); @@ -602,9 +589,13 @@ void dw_pcie_setup_rc(struct pcie_port *pp) * ATU, so we should not program the ATU here. */ if (pp->bridge->child_ops == &dw_child_pcie_ops) { + struct resource_entry *entry = + resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM); + dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, - PCIE_ATU_TYPE_MEM, pp->mem_base, - pp->mem_bus_addr, pp->mem_size); + PCIE_ATU_TYPE_MEM, entry->res->start, + entry->res->start - entry->offset, + resource_size(entry->res)); if (pci->num_viewport > 2) dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2, PCIE_ATU_TYPE_IO, pp->io_base, diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index a24229d95714..00f5a7257217 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -175,13 +175,7 @@ struct pcie_port { resource_size_t io_base; phys_addr_t io_bus_addr; u32 io_size; - u64 mem_base; - phys_addr_t mem_bus_addr; - u32 mem_size; struct resource *cfg; - struct resource *io; - struct resource *mem; - struct resource *busn; int irq; const struct dw_pcie_host_ops *ops; int msi_irq; -- cgit v1.2.3 From 2ef6b06a0475f69a6e396af9e1977e118a34d8ce Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:53:59 -0600 Subject: PCI: dwc: Simplify config space handling The config space is divided in half for type 0 and type 1 accesses, but this is pointless as there's only one iATU window which is reconfigured on each access. The only platform doing something custom is TI Keystone (surprise!). It does its own mapping of the config space to avoid spliting the config space and never actually uses va_cfg1_base as it has its own config space accessors. With the splitting removed, Keystone can use the default mapping of config space. Link: https://lore.kernel.org/r/20200821035420.380495-20-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Murali Karicheri Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Jingoo Han Cc: Gustavo Pimentel --- drivers/pci/controller/dwc/pci-keystone.c | 8 --- drivers/pci/controller/dwc/pcie-designware-host.c | 63 +++++++---------------- drivers/pci/controller/dwc/pcie-designware.h | 4 -- 3 files changed, 20 insertions(+), 55 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index d306914a1f93..983069a4a561 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -873,16 +873,8 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; struct device *dev = &pdev->dev; - struct resource *res; int ret; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); - pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pp->va_cfg0_base)) - return PTR_ERR(pp->va_cfg0_base); - - pp->va_cfg1_base = pp->va_cfg0_base; - ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "failed to initialize host\n"); diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index b40aeae78809..38d7c89dbb21 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -308,10 +308,8 @@ int dw_pcie_host_init(struct pcie_port *pp) cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); if (cfg_res) { - pp->cfg0_size = resource_size(cfg_res) >> 1; - pp->cfg1_size = resource_size(cfg_res) >> 1; + pp->cfg0_size = resource_size(cfg_res); pp->cfg0_base = cfg_res->start; - pp->cfg1_base = cfg_res->start + pp->cfg0_size; } else if (!pp->va_cfg0_base) { dev_err(dev, "Missing *config* reg space\n"); } @@ -331,25 +329,22 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->io_base = pci_pio_to_address(win->res->start); break; case 0: - pp->cfg = win->res; - pp->cfg0_size = resource_size(pp->cfg) >> 1; - pp->cfg1_size = resource_size(pp->cfg) >> 1; - pp->cfg0_base = pp->cfg->start; - pp->cfg1_base = pp->cfg->start + pp->cfg0_size; + dev_err(dev, "Missing *config* reg space\n"); + pp->cfg0_size = resource_size(win->res); + pp->cfg0_base = win->res->start; + if (!pci->dbi_base) { + pci->dbi_base = devm_pci_remap_cfgspace(dev, + pp->cfg0_base, + pp->cfg0_size); + if (!pci->dbi_base) { + dev_err(dev, "Error with ioremap\n"); + return -ENOMEM; + } + } break; } } - if (!pci->dbi_base) { - pci->dbi_base = devm_pci_remap_cfgspace(dev, - pp->cfg->start, - resource_size(pp->cfg)); - if (!pci->dbi_base) { - dev_err(dev, "Error with ioremap\n"); - return -ENOMEM; - } - } - if (!pp->va_cfg0_base) { pp->va_cfg0_base = devm_pci_remap_cfgspace(dev, pp->cfg0_base, pp->cfg0_size); @@ -359,16 +354,6 @@ int dw_pcie_host_init(struct pcie_port *pp) } } - if (!pp->va_cfg1_base) { - pp->va_cfg1_base = devm_pci_remap_cfgspace(dev, - pp->cfg1_base, - pp->cfg1_size); - if (!pp->va_cfg1_base) { - dev_err(dev, "Error with ioremap\n"); - return -ENOMEM; - } - } - ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport); if (ret) pci->num_viewport = 2; @@ -446,32 +431,24 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, unsigned int devfn, int where) { int type; - u32 busdev, cfg_size; - u64 cpu_addr; - void __iomem *va_cfg_base; + u32 busdev; struct pcie_port *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | PCIE_ATU_FUNC(PCI_FUNC(devfn)); - if (pci_is_root_bus(bus->parent)) { + if (pci_is_root_bus(bus->parent)) type = PCIE_ATU_TYPE_CFG0; - cpu_addr = pp->cfg0_base; - cfg_size = pp->cfg0_size; - va_cfg_base = pp->va_cfg0_base; - } else { + else type = PCIE_ATU_TYPE_CFG1; - cpu_addr = pp->cfg1_base; - cfg_size = pp->cfg1_size; - va_cfg_base = pp->va_cfg1_base; - } + dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, - type, cpu_addr, - busdev, cfg_size); + type, pp->cfg0_base, + busdev, pp->cfg0_size); - return va_cfg_base + where; + return pp->va_cfg0_base + where; } static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn, diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 00f5a7257217..48f45f810551 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -169,13 +169,9 @@ struct pcie_port { u64 cfg0_base; void __iomem *va_cfg0_base; u32 cfg0_size; - u64 cfg1_base; - void __iomem *va_cfg1_base; - u32 cfg1_size; resource_size_t io_base; phys_addr_t io_bus_addr; u32 io_size; - struct resource *cfg; int irq; const struct dw_pcie_host_ops *ops; int msi_irq; -- cgit v1.2.3 From 421063efaf1e8f2ac6248cca0064e5877e375f87 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:00 -0600 Subject: PCI: dwc/keystone: Drop duplicated 'num-viewport' The DWC core driver already parses and stores the 'num-viewport' DT property, so there is no need for the Keystone driver to store it. Link: https://lore.kernel.org/r/20200821035420.380495-21-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Murali Karicheri Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-keystone.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 983069a4a561..0fe792f6c253 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -123,7 +123,6 @@ struct keystone_pcie { int msi_host_irq; int num_lanes; - u32 num_viewport; struct phy **phy; struct device_link **link; struct device_node *msi_intc_np; @@ -397,9 +396,9 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) { u32 val; - u32 num_viewport = ks_pcie->num_viewport; struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; + u32 num_viewport = pci->num_viewport; u64 start, end; struct resource *mem; int i; @@ -1199,7 +1198,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct resource *res; unsigned int version; void __iomem *base; - u32 num_viewport; struct phy **phy; int link_speed; u32 num_lanes; @@ -1349,12 +1347,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - ret = of_property_read_u32(np, "num-viewport", &num_viewport); - if (ret < 0) { - dev_err(dev, "unable to read *num-viewport* property\n"); - goto err_get_sync; - } - /* * "Power Sequencing and Reset Signal Timings" table in * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 @@ -1368,7 +1360,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) gpiod_set_value_cansleep(gpiod, 1); } - ks_pcie->num_viewport = num_viewport; pci->pp.ops = host_ops; ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) -- cgit v1.2.3 From cf627713e3c08920cfc3ad401354109b5273409e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:01 -0600 Subject: PCI: dwc: Check CONFIG_PCI_MSI inside dw_pcie_msi_init() Move the IS_ENABLED(CONFIG_PCI_MSI) check into dw_pcie_msi_init() instead of duplicating it in all the drivers. Link: https://lore.kernel.org/r/20200821035420.380495-22-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Richard Zhu Cc: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Cc: Yue Wang Cc: Kevin Hilman Cc: Jesper Nilsson Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Xiaowei Song Cc: Binghui Wang Cc: Stanimir Varbanov Cc: Andy Gross Cc: Bjorn Andersson Cc: Kunihiko Hayashi Cc: Masahiro Yamada Cc: linux-amlogic@lists.infradead.org Cc: linux-arm-kernel@axis.com Cc: linux-arm-msm@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 4 +--- drivers/pci/controller/dwc/pci-meson.c | 8 +------- drivers/pci/controller/dwc/pcie-artpec6.c | 11 +---------- drivers/pci/controller/dwc/pcie-designware-host.c | 3 +++ drivers/pci/controller/dwc/pcie-designware-plat.c | 4 +--- drivers/pci/controller/dwc/pcie-histb.c | 4 +--- drivers/pci/controller/dwc/pcie-kirin.c | 4 +--- drivers/pci/controller/dwc/pcie-qcom.c | 4 +--- drivers/pci/controller/dwc/pcie-uniphier.c | 3 +-- 9 files changed, 11 insertions(+), 34 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 90df28c7cb0c..68a09680e728 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -847,9 +847,7 @@ static int imx6_pcie_host_init(struct pcie_port *pp) imx6_setup_phy_mpll(imx6_pcie); dw_pcie_setup_rc(pp); imx6_pcie_establish_link(imx6_pcie); - - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_init(pp); + dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index f4d822190359..67ca73528aad 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -377,12 +377,6 @@ static int meson_pcie_establish_link(struct meson_pcie *mp) return dw_pcie_wait_for_link(pci); } -static void meson_pcie_enable_interrupts(struct meson_pcie *mp) -{ - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_init(&mp->pci.pp); -} - static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 *val) { @@ -466,7 +460,7 @@ static int meson_pcie_host_init(struct pcie_port *pp) if (ret) return ret; - meson_pcie_enable_interrupts(mp); + dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 97d50bb50f06..86f4d66d8587 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -346,15 +346,6 @@ static void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie) usleep_range(100, 200); } -static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie) -{ - struct dw_pcie *pci = artpec6_pcie->pci; - struct pcie_port *pp = &pci->pp; - - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_init(pp); -} - static int artpec6_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -368,7 +359,7 @@ static int artpec6_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); artpec6_pcie_establish_link(pci); dw_pcie_wait_for_link(pci); - artpec6_pcie_enable_interrupts(artpec6_pcie); + dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 38d7c89dbb21..4f21d95b4077 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -276,6 +276,9 @@ void dw_pcie_msi_init(struct pcie_port *pp) struct device *dev = pci->dev; u64 msi_target; + if (!IS_ENABLED(CONFIG_PCI_MSI)) + return; + pp->msi_page = alloc_page(GFP_KERNEL); pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE, DMA_FROM_DEVICE); diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 712456f6ce36..e3e300669ed5 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -39,9 +39,7 @@ static int dw_plat_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); dw_pcie_wait_for_link(pci); - - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_init(pp); + dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index af1deae2b15d..afc1abbe49aa 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -202,9 +202,7 @@ static int histb_pcie_host_init(struct pcie_port *pp) pp->bridge->ops = &histb_pci_ops; histb_pcie_establish_link(pp); - - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_init(pp); + dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index 8a01ab0a4a65..6f01ae013326 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -429,9 +429,7 @@ static int kirin_pcie_host_init(struct pcie_port *pp) pp->bridge->ops = &kirin_pci_ops; kirin_pcie_establish_link(pp); - - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_init(pp); + dw_pcie_msi_init(pp); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 3aac77a295ba..fe7fc2ccd76d 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1280,9 +1280,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp) } dw_pcie_setup_rc(pp); - - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_init(pp); + dw_pcie_msi_init(pp); qcom_ep_reset_deassert(pcie); diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index 3a7f403b57b8..48176265c867 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -322,8 +322,7 @@ static int uniphier_pcie_host_init(struct pcie_port *pp) if (ret) return ret; - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_init(pp); + dw_pcie_msi_init(pp); return 0; } -- cgit v1.2.3 From 574523dcfc63a5071c15f851e1cb4277e957580d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:02 -0600 Subject: PCI: dwc/imx6: Remove duplicate define PCIE_LINK_WIDTH_SPEED_CONTROL PCIE_LINK_WIDTH_SPEED_CONTROL is already defined in pcie-designware.h, so remove it from the i.MX6 driver. Link: https://lore.kernel.org/r/20200821035420.380495-23-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Richard Zhu Cc: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team --- drivers/pci/controller/dwc/pci-imx6.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 68a09680e728..2b075a468104 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -116,8 +116,6 @@ struct imx6_pcie { #define PCIE_PHY_STAT (PL_OFFSET + 0x110) #define PCIE_PHY_STAT_ACK BIT(16) -#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C - /* PHY registers (not memory-mapped) */ #define PCIE_PHY_ATEOVRD 0x10 #define PCIE_PHY_ATEOVRD_EN BIT(2) -- cgit v1.2.3 From 6ffc02d236315783bf3639bf5aff4da047ee14bb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:03 -0600 Subject: PCI: dwc: Add a 'num_lanes' field to struct dw_pcie Add a 'num_lanes' field to allow drivers to provide a the number of lanes if not in DT or using a custom DT property. A driver can provide a non-zero value which is used if the DT doesn't have a 'num-lanes' property. Link: https://lore.kernel.org/r/20200821035420.380495-24-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware.c | 14 ++++++-------- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index b723e0cc41fb..e957a726be85 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -546,9 +546,7 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) void dw_pcie_setup(struct dw_pcie *pci) { - int ret; u32 val; - u32 lanes; struct device *dev = pci->dev; struct device_node *np = dev->of_node; @@ -562,16 +560,16 @@ void dw_pcie_setup(struct dw_pcie *pci) "enabled" : "disabled"); - ret = of_property_read_u32(np, "num-lanes", &lanes); - if (ret) { - dev_dbg(pci->dev, "property num-lanes isn't found\n"); + of_property_read_u32(np, "num-lanes", &pci->num_lanes); + if (!pci->num_lanes) { + dev_dbg(pci->dev, "Using h/w default number of lanes\n"); return; } /* Set the number of lanes */ val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); val &= ~PORT_LINK_MODE_MASK; - switch (lanes) { + switch (pci->num_lanes) { case 1: val |= PORT_LINK_MODE_1_LANES; break; @@ -585,7 +583,7 @@ void dw_pcie_setup(struct dw_pcie *pci) val |= PORT_LINK_MODE_8_LANES; break; default: - dev_err(pci->dev, "num-lanes %u: invalid value\n", lanes); + dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->num_lanes); return; } dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); @@ -593,7 +591,7 @@ void dw_pcie_setup(struct dw_pcie *pci) /* Set link width speed control register */ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); val &= ~PORT_LOGIC_LINK_WIDTH_MASK; - switch (lanes) { + switch (pci->num_lanes) { case 1: val |= PORT_LOGIC_LINK_WIDTH_1_LANES; break; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 48f45f810551..6d3bec33de98 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -246,6 +246,7 @@ struct dw_pcie { struct dw_pcie_ep ep; const struct dw_pcie_ops *ops; unsigned int version; + int num_lanes; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) -- cgit v1.2.3 From cff9244432e833710a14ed597d33615d77934a9d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:04 -0600 Subject: PCI: dwc: Ensure FAST_LINK_MODE is cleared "Fast Link Mode" is a simulation environment speed up setting which should never be set and the default is not set. However some Amlogic platforms have it set (by firmware presumably). See commit 87dccf09323f ("PCI: amlogic: meson: Don't use FAST_LINK_MODE to set up link") for more information. Let's clear it in core DWC code so we can drop some vendor specific code. Link: https://lore.kernel.org/r/20200821035420.380495-25-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware.c | 5 ++++- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index e957a726be85..90dc1674aae5 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -559,6 +559,9 @@ void dw_pcie_setup(struct dw_pcie *pci) dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? "enabled" : "disabled"); + val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); + val &= ~PORT_LINK_FAST_LINK_MODE; + dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); of_property_read_u32(np, "num-lanes", &pci->num_lanes); if (!pci->num_lanes) { @@ -567,7 +570,7 @@ void dw_pcie_setup(struct dw_pcie *pci) } /* Set the number of lanes */ - val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); + val &= ~PORT_LINK_FAST_LINK_MODE; val &= ~PORT_LINK_MODE_MASK; switch (pci->num_lanes) { case 1: diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 6d3bec33de98..66815581b498 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -36,6 +36,7 @@ #define PCIE_PORT_LINK_CONTROL 0x710 #define PORT_LINK_DLL_LINK_EN BIT(5) +#define PORT_LINK_FAST_LINK_MODE BIT(7) #define PORT_LINK_MODE_MASK GENMASK(21, 16) #define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n) #define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1) -- cgit v1.2.3 From 244c40cc28b116b6530a6d9b24ac290e0f89607c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:05 -0600 Subject: PCI: dwc/meson: Drop the duplicate number of lanes setup The meson lanes initialization is the same DWC port logic registers as in dw_pcie_setup(). We just need to initialize 'num_lanes' to 1 to do the same init. dw_pcie_setup_rc() sets the PORT_LOGIC_SPEED_CHANGE bit, so setting it can be dropped. Link: https://lore.kernel.org/r/20200821035420.380495-26-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Yue Wang Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kevin Hilman Cc: Neil Armstrong Cc: Jerome Brunet Cc: Martin Blumenstingl Cc: linux-amlogic@lists.infradead.org --- drivers/pci/controller/dwc/pci-meson.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 67ca73528aad..96308743faf4 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -22,18 +22,6 @@ #define to_meson_pcie(x) dev_get_drvdata((x)->dev) -/* External local bus interface registers */ -#define PLR_OFFSET 0x700 -#define PCIE_PORT_LINK_CTRL_OFF (PLR_OFFSET + 0x10) -#define FAST_LINK_MODE BIT(7) -#define LINK_CAPABLE_MASK GENMASK(21, 16) -#define LINK_CAPABLE_X1 BIT(16) - -#define PCIE_GEN2_CTRL_OFF (PLR_OFFSET + 0x10c) -#define NUM_OF_LANES_MASK GENMASK(12, 8) -#define NUM_OF_LANES_X1 BIT(8) -#define DIRECT_SPEED_CHANGE BIT(17) - #define TYPE1_HDR_OFFSET 0x0 #define PCIE_STATUS_COMMAND (TYPE1_HDR_OFFSET + 0x04) #define PCI_IO_EN BIT(0) @@ -288,22 +276,6 @@ static void meson_pcie_init_dw(struct meson_pcie *mp) val |= APP_LTSSM_ENABLE; meson_cfg_writel(mp, val, PCIE_CFG0); - val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF); - val &= ~(LINK_CAPABLE_MASK | FAST_LINK_MODE); - meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF); - - val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF); - val |= LINK_CAPABLE_X1; - meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF); - - val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF); - val &= ~NUM_OF_LANES_MASK; - meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF); - - val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF); - val |= NUM_OF_LANES_X1 | DIRECT_SPEED_CHANGE; - meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF); - meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0); meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1); } @@ -513,6 +485,7 @@ static int meson_pcie_probe(struct platform_device *pdev) pci = &mp->pci; pci->dev = dev; pci->ops = &dw_pcie_ops; + pci->num_lanes = 1; mp->phy = devm_phy_get(dev, "pcie"); if (IS_ERR(mp->phy)) { -- cgit v1.2.3 From 15efab2b8934f9950eff083c23c7f03c382a5f86 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:06 -0600 Subject: PCI: dwc/meson: Drop unnecessary RC config space initialization The common Designware init already initializes the RC PCI_COMMAND, BAR0 and BAR1 registers. The only difference here is the common code sets SERR. If clearing SERR is what's desired, then the Meson driver should do that instead. Link: https://lore.kernel.org/r/20200821035420.380495-27-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Yue Wang Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kevin Hilman Cc: linux-amlogic@lists.infradead.org --- drivers/pci/controller/dwc/pci-meson.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 96308743faf4..cca423e834e8 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -22,15 +22,6 @@ #define to_meson_pcie(x) dev_get_drvdata((x)->dev) -#define TYPE1_HDR_OFFSET 0x0 -#define PCIE_STATUS_COMMAND (TYPE1_HDR_OFFSET + 0x04) -#define PCI_IO_EN BIT(0) -#define PCI_MEM_SPACE_EN BIT(1) -#define PCI_BUS_MASTER_EN BIT(2) - -#define PCIE_BASE_ADDR0 (TYPE1_HDR_OFFSET + 0x10) -#define PCIE_BASE_ADDR1 (TYPE1_HDR_OFFSET + 0x14) - #define PCIE_CAP_OFFSET 0x70 #define PCIE_DEV_CTRL_DEV_STUS (PCIE_CAP_OFFSET + 0x08) #define PCIE_CAP_MAX_PAYLOAD_MASK GENMASK(7, 5) @@ -275,9 +266,6 @@ static void meson_pcie_init_dw(struct meson_pcie *mp) val = meson_cfg_readl(mp, PCIE_CFG0); val |= APP_LTSSM_ENABLE; meson_cfg_writel(mp, val, PCIE_CFG0); - - meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0); - meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1); } static int meson_size_to_payload(struct meson_pcie *mp, int size) @@ -325,13 +313,6 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size) meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); } -static inline void meson_enable_memory_space(struct meson_pcie *mp) -{ - /* Set the RC Bus Master, Memory Space and I/O Space enables */ - meson_elb_writel(mp, PCI_IO_EN | PCI_MEM_SPACE_EN | PCI_BUS_MASTER_EN, - PCIE_STATUS_COMMAND); -} - static int meson_pcie_establish_link(struct meson_pcie *mp) { struct dw_pcie *pci = &mp->pci; @@ -342,7 +323,6 @@ static int meson_pcie_establish_link(struct meson_pcie *mp) meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE); dw_pcie_setup_rc(pp); - meson_enable_memory_space(mp); meson_pcie_assert_reset(mp); -- cgit v1.2.3 From 2f2cea1ea70ac25096bd63039b38bb8ec6a887b6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:07 -0600 Subject: PCI: dwc/meson: Rework PCI config and DW port logic register accesses The meson 'elbi' registers are just the Designware 'dbi' space and all the registers accessed are either standard PCI config space or DWC port logic registers. Convert the accesses to use the common defines and register accessors. Link: https://lore.kernel.org/r/20200821035420.380495-28-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Yue Wang Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Kevin Hilman Cc: Jingoo Han Cc: Gustavo Pimentel Cc: linux-amlogic@lists.infradead.org --- drivers/pci/controller/dwc/pci-meson.c | 76 +++++++++++----------------------- 1 file changed, 25 insertions(+), 51 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index cca423e834e8..33deb290c4e7 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -22,11 +22,7 @@ #define to_meson_pcie(x) dev_get_drvdata((x)->dev) -#define PCIE_CAP_OFFSET 0x70 -#define PCIE_DEV_CTRL_DEV_STUS (PCIE_CAP_OFFSET + 0x08) -#define PCIE_CAP_MAX_PAYLOAD_MASK GENMASK(7, 5) #define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5) -#define PCIE_CAP_MAX_READ_REQ_MASK GENMASK(14, 12) #define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12) /* PCIe specific config registers */ @@ -56,11 +52,6 @@ enum pcie_data_rate { PCIE_GEN4 }; -struct meson_pcie_mem_res { - void __iomem *elbi_base; - void __iomem *cfg_base; -}; - struct meson_pcie_clk_res { struct clk *clk; struct clk *port_clk; @@ -74,7 +65,7 @@ struct meson_pcie_rc_reset { struct meson_pcie { struct dw_pcie pci; - struct meson_pcie_mem_res mem_res; + void __iomem *cfg_base; struct meson_pcie_clk_res clk_res; struct meson_pcie_rc_reset mrst; struct gpio_desc *reset_gpio; @@ -113,28 +104,18 @@ static int meson_pcie_get_resets(struct meson_pcie *mp) return 0; } -static void __iomem *meson_pcie_get_mem(struct platform_device *pdev, - struct meson_pcie *mp, - const char *id) -{ - struct device *dev = mp->pci.dev; - struct resource *res; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id); - - return devm_ioremap_resource(dev, res); -} - static int meson_pcie_get_mems(struct platform_device *pdev, struct meson_pcie *mp) { - mp->mem_res.elbi_base = meson_pcie_get_mem(pdev, mp, "elbi"); - if (IS_ERR(mp->mem_res.elbi_base)) - return PTR_ERR(mp->mem_res.elbi_base); + struct dw_pcie *pci = &mp->pci; + + pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi"); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); - mp->mem_res.cfg_base = meson_pcie_get_mem(pdev, mp, "cfg"); - if (IS_ERR(mp->mem_res.cfg_base)) - return PTR_ERR(mp->mem_res.cfg_base); + mp->cfg_base = devm_platform_ioremap_resource_byname(pdev, "cfg"); + if (IS_ERR(mp->cfg_base)) + return PTR_ERR(mp->cfg_base); return 0; } @@ -232,24 +213,14 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp) return 0; } -static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg) -{ - writel(val, mp->mem_res.elbi_base + reg); -} - -static inline u32 meson_elb_readl(struct meson_pcie *mp, u32 reg) -{ - return readl(mp->mem_res.elbi_base + reg); -} - static inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg) { - return readl(mp->mem_res.cfg_base + reg); + return readl(mp->cfg_base + reg); } static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg) { - writel(val, mp->mem_res.cfg_base + reg); + writel(val, mp->cfg_base + reg); } static void meson_pcie_assert_reset(struct meson_pcie *mp) @@ -287,30 +258,34 @@ static int meson_size_to_payload(struct meson_pcie *mp, int size) static void meson_set_max_payload(struct meson_pcie *mp, int size) { + struct dw_pcie *pci = &mp->pci; u32 val; + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); int max_payload_size = meson_size_to_payload(mp, size); - val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS); - val &= ~PCIE_CAP_MAX_PAYLOAD_MASK; - meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL); + val &= ~PCI_EXP_DEVCTL_PAYLOAD; + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val); - val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS); + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL); val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size); - meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val); } static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size) { + struct dw_pcie *pci = &mp->pci; u32 val; + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); int max_rd_req_size = meson_size_to_payload(mp, size); - val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS); - val &= ~PCIE_CAP_MAX_READ_REQ_MASK; - meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL); + val &= ~PCI_EXP_DEVCTL_READRQ; + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val); - val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS); + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL); val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size); - meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS); + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val); } static int meson_pcie_establish_link(struct meson_pcie *mp) @@ -436,7 +411,6 @@ static int meson_add_pcie_port(struct meson_pcie *mp, } pp->ops = &meson_pcie_host_ops; - pci->dbi_base = mp->mem_res.elbi_base; ret = dw_pcie_host_init(pp); if (ret) { -- cgit v1.2.3 From 201a8df899525bfad0b7493b97280e8127ac790b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:08 -0600 Subject: PCI: dwc/imx6: Use common PCI register definitions The i.MX6 driver has its own defines for common PCI config space registers. It also hard codes the capability register offsets which are discoverable. Convert it to use the standard register definitions. Link: https://lore.kernel.org/r/20200821035420.380495-29-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Richard Zhu Cc: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team --- drivers/pci/controller/dwc/pci-imx6.c | 37 +++++++++++++---------------------- 1 file changed, 14 insertions(+), 23 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 2b075a468104..9f6018d3d338 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -94,15 +94,6 @@ struct imx6_pcie { #define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 #define PHY_PLL_LOCK_WAIT_TIMEOUT (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX) -/* PCIe Root Complex registers (memory-mapped) */ -#define PCIE_RC_IMX6_MSI_CAP 0x50 -#define PCIE_RC_LCR 0x7c -#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 -#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 -#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf - -#define PCIE_RC_LCSR 0x80 - /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 @@ -759,6 +750,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; struct device *dev = pci->dev; + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); u32 tmp; int ret; @@ -767,10 +759,10 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) * started in Gen2 mode, there is a possibility the devices on the * bus will not be detected at all. This happens with PCIe switches. */ - tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR); - tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; - tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1; - dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); + tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); + tmp &= ~PCI_EXP_LNKCAP_SLS; + tmp |= PCI_EXP_LNKCAP_SLS_2_5GB; + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp); /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); @@ -781,10 +773,10 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) if (imx6_pcie->link_gen == 2) { /* Allow Gen2 mode after the link is up. */ - tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR); - tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; - tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2; - dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); + tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); + tmp &= ~PCI_EXP_LNKCAP_SLS; + tmp |= PCI_EXP_LNKCAP_SLS_5_0GB; + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp); /* * Start Directed Speed Change so the best possible @@ -822,8 +814,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) dev_info(dev, "Link: Gen2 disabled\n"); } - tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR); - dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf); + tmp = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA); + dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS); return 0; err_reset_phy: @@ -1184,11 +1176,10 @@ static int imx6_pcie_probe(struct platform_device *pdev) return ret; if (pci_msi_enabled()) { - val = dw_pcie_readw_dbi(pci, PCIE_RC_IMX6_MSI_CAP + - PCI_MSI_FLAGS); + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); + val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS); val |= PCI_MSI_FLAGS_ENABLE; - dw_pcie_writew_dbi(pci, PCIE_RC_IMX6_MSI_CAP + PCI_MSI_FLAGS, - val); + dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val); } return 0; -- cgit v1.2.3 From 7b87ddc04b364b94142d3b1295d92f1fe1145781 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:09 -0600 Subject: PCI: dwc/qcom: Use common PCI register definitions The QCom driver has its own defines for common PCI config space registers. It also hard codes the capability register offsets which are discoverable. Convert it to use the standard register definitions. Link: https://lore.kernel.org/r/20200821035420.380495-30-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Stanimir Varbanov Cc: Andy Gross Cc: Bjorn Andersson Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: linux-arm-msm@vger.kernel.org --- drivers/pci/controller/dwc/pcie-qcom.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index fe7fc2ccd76d..d8d1fb7e0b8f 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -67,10 +67,6 @@ #define PCIE20_AXI_MSTR_RESP_COMP_CTRL1 0x81c #define CFG_BRIDGE_SB_INIT BIT(0) -#define PCIE20_CAP 0x70 -#define PCIE20_DEVICE_CONTROL2_STATUS2 (PCIE20_CAP + PCI_EXP_DEVCTL2) -#define PCIE20_CAP_LINK_CAPABILITIES (PCIE20_CAP + PCI_EXP_LNKCAP) -#define PCIE20_CAP_LINK_1 (PCIE20_CAP + 0x14) #define PCIE_CAP_LINK1_VAL 0x2FD7F #define PCIE20_PARF_Q2A_FLUSH 0x1AC @@ -1017,6 +1013,7 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie) struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3; struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); int i, ret; u32 val; @@ -1092,14 +1089,14 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie) writel(PCI_COMMAND_MASTER, pci->dbi_base + PCI_COMMAND); writel(DBI_RO_WR_EN, pci->dbi_base + PCIE20_MISC_CONTROL_1_REG); - writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + PCIE20_CAP_LINK_1); + writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP); - val = readl(pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES); + val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP); val &= ~PCI_EXP_LNKCAP_ASPMS; - writel(val, pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES); + writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP); - writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + - PCIE20_DEVICE_CONTROL2_STATUS2); + writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset + + PCI_EXP_DEVCTL2); return 0; @@ -1252,7 +1249,8 @@ static void qcom_pcie_post_deinit_2_7_0(struct qcom_pcie *pcie) static int qcom_pcie_link_up(struct dw_pcie *pci) { - u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA); + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA); return !!(val & PCI_EXP_LNKSTA_DLLLA); } -- cgit v1.2.3 From fb7652327101cdcaceae472c3b87fc5c8de28abe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:10 -0600 Subject: PCI: dwc: Remove hardcoded PCI_CAP_ID_EXP offset While the Designware controller appears to hard code the PCI_CAP_ID_EXP capability register at 0x70, there's no need to hard code this in the driver as it is discoverable. Link: https://lore.kernel.org/r/20200821035420.380495-31-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Murali Karicheri Cc: Pratyush Anand Cc: linux-omap@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 4 +--- drivers/pci/controller/dwc/pci-keystone.c | 11 +++++------ drivers/pci/controller/dwc/pcie-spear13xx.c | 4 +--- 3 files changed, 7 insertions(+), 12 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 dc387724cf08..d42e0664f378 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -73,8 +73,6 @@ #define LINK_UP BIT(16) #define DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF -#define EXP_CAP_ID_OFFSET 0x70 - #define PCIECTRL_TI_CONF_INTX_ASSERT 0x0124 #define PCIECTRL_TI_CONF_INTX_DEASSERT 0x0128 @@ -142,7 +140,7 @@ static int dra7xx_pcie_establish_link(struct dw_pcie *pci) struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); struct device *dev = pci->dev; u32 reg; - u32 exp_cap_off = EXP_CAP_ID_OFFSET; + u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); if (dw_pcie_link_up(pci)) { dev_err(dev, "link is already up\n"); diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 0fe792f6c253..39a5a72de340 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -96,8 +96,6 @@ #define LEG_EP 0x1 #define RC 0x2 -#define EXP_CAP_ID_OFFSET 0x70 - #define KS_PCIE_SYSCLOCKOUTEN BIT(0) #define AM654_PCIE_DEV_TYPE_MASK 0x3 @@ -1125,22 +1123,23 @@ static int ks_pcie_am654_set_mode(struct device *dev, static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed) { u32 val; + u32 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); dw_pcie_dbi_ro_wr_en(pci); - val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP); + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { val &= ~((u32)PCI_EXP_LNKCAP_SLS); val |= link_speed; - dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP, + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, val); } - val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2); + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2); if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { val &= ~((u32)PCI_EXP_LNKCAP_SLS); val |= link_speed; - dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2, + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, val); } diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index 62846562da0b..056c94541a22 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -65,8 +65,6 @@ struct pcie_app_reg { /* CR6 */ #define MSI_CTRL_INT (1 << 26) -#define EXP_CAP_ID_OFFSET 0x70 - #define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev) static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) @@ -75,7 +73,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) struct pcie_port *pp = &pci->pp; struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; u32 val; - u32 exp_cap_off = EXP_CAP_ID_OFFSET; + u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); if (dw_pcie_link_up(pci)) { dev_err(pci->dev, "link already up\n"); -- cgit v1.2.3 From 84667a416d42c8516468f4ef7a577296fbfd167d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:11 -0600 Subject: PCI: dwc/tegra: Use common Designware port logic register definitions The Tegra driver has its own defines for common Designware Port Logic registers. Convert it to use the standard register definitions. Link: https://lore.kernel.org/r/20200821035420.380495-32-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pcie-designware.h | 6 +++ drivers/pci/controller/dwc/pcie-tegra194.c | 56 +++++++++++----------------- 2 files changed, 28 insertions(+), 34 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 66815581b498..c56f1adb0d78 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -32,7 +32,13 @@ /* Synopsys-specific PCIe configuration registers */ #define PCIE_PORT_AFR 0x70C #define PORT_AFR_N_FTS_MASK GENMASK(15, 8) +#define PORT_AFR_N_FTS(n) FIELD_PREP(PORT_AFR_N_FTS_MASK, n) #define PORT_AFR_CC_N_FTS_MASK GENMASK(23, 16) +#define PORT_AFR_ENTER_ASPM BIT(30) +#define PORT_AFR_L0S_ENTRANCE_LAT_SHIFT 24 +#define PORT_AFR_L0S_ENTRANCE_LAT_MASK GENMASK(26, 24) +#define PORT_AFR_L1_ENTRANCE_LAT_SHIFT 27 +#define PORT_AFR_L1_ENTRANCE_LAT_MASK GENMASK(29, 27) #define PCIE_PORT_LINK_CONTROL 0x710 #define PORT_LINK_DLL_LINK_EN BIT(5) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index a5dce56b3b7a..f121ac25d418 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -183,19 +183,7 @@ #define EVENT_COUNTER_GROUP_SEL_SHIFT 24 #define EVENT_COUNTER_GROUP_5 0x5 -#define PORT_LOGIC_ACK_F_ASPM_CTRL 0x70C -#define ENTER_ASPM BIT(30) -#define L0S_ENTRANCE_LAT_SHIFT 24 -#define L0S_ENTRANCE_LAT_MASK GENMASK(26, 24) -#define L1_ENTRANCE_LAT_SHIFT 27 -#define L1_ENTRANCE_LAT_MASK GENMASK(29, 27) -#define N_FTS_SHIFT 8 -#define N_FTS_MASK GENMASK(7, 0) #define N_FTS_VAL 52 - -#define PORT_LOGIC_GEN2_CTRL 0x80C -#define PORT_LOGIC_GEN2_CTRL_DIRECT_SPEED_CHANGE BIT(17) -#define FTS_MASK GENMASK(7, 0) #define FTS_VAL 52 #define PORT_LOGIC_MSI_CTRL_INT_0_EN 0x828 @@ -401,9 +389,9 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg) val |= APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N; appl_writel(pcie, val, APPL_CAR_RESET_OVRD); - val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL); - val |= PORT_LOGIC_GEN2_CTRL_DIRECT_SPEED_CHANGE; - dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val); + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val |= PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); } } @@ -694,11 +682,11 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie) dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val); /* Program L0s and L1 entrance latencies */ - val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL); - val &= ~L0S_ENTRANCE_LAT_MASK; - val |= (pcie->aspm_l0s_enter_lat << L0S_ENTRANCE_LAT_SHIFT); - val |= ENTER_ASPM; - dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val); + val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); + val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK; + val |= (pcie->aspm_l0s_enter_lat << PORT_AFR_L0S_ENTRANCE_LAT_SHIFT); + val |= PORT_AFR_ENTER_ASPM; + dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); } static int init_debugfs(struct tegra_pcie_dw *pcie) @@ -895,15 +883,15 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp) dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); /* Configure FTS */ - val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL); - val &= ~(N_FTS_MASK << N_FTS_SHIFT); - val |= N_FTS_VAL << N_FTS_SHIFT; - dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val); + val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); + val &= ~PORT_AFR_N_FTS_MASK; + val |= PORT_AFR_N_FTS(N_FTS_VAL); + dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); - val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL); - val &= ~FTS_MASK; + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_N_FTS_MASK; val |= FTS_VAL; - dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val); + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); /* Enable as 0xFFFF0001 response for CRS */ val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT); @@ -1820,15 +1808,15 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); /* Configure N_FTS & FTS */ - val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL); - val &= ~(N_FTS_MASK << N_FTS_SHIFT); - val |= N_FTS_VAL << N_FTS_SHIFT; - dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val); + val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); + val &= ~PORT_AFR_N_FTS_MASK; + val |= PORT_AFR_N_FTS(FTS_VAL); + dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); - val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL); - val &= ~FTS_MASK; + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_N_FTS_MASK; val |= FTS_VAL; - dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val); + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); /* Configure Max Speed from DT */ if (pcie->max_speed && pcie->max_speed != -EINVAL) { -- cgit v1.2.3 From 903d69f83c6bf3bb42f98f41d9943f27880ddb67 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:12 -0600 Subject: PCI: dwc: Remove read_dbi2 code The DBI2 appears to be write-only and there's no read accesses in the code anyways, so let's remove all the read_dbi2 related code. Link: https://lore.kernel.org/r/20200821035420.380495-33-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Murali Karicheri Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Jingoo Han Cc: Gustavo Pimentel --- drivers/pci/controller/dwc/pci-keystone.c | 13 ------------- drivers/pci/controller/dwc/pcie-designware.c | 15 --------------- drivers/pci/controller/dwc/pcie-designware.h | 8 -------- 3 files changed, 36 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 39a5a72de340..5fe36da0b7c6 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -881,18 +881,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, return 0; } -static u32 ks_pcie_am654_read_dbi2(struct dw_pcie *pci, void __iomem *base, - u32 reg, size_t size) -{ - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - u32 val; - - ks_pcie_set_dbi_mode(ks_pcie); - dw_pcie_read(base + reg, size, &val); - ks_pcie_clear_dbi_mode(ks_pcie); - return val; -} - static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size, u32 val) { @@ -907,7 +895,6 @@ static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { .start_link = ks_pcie_start_link, .stop_link = ks_pcie_stop_link, .link_up = ks_pcie_link_up, - .read_dbi2 = ks_pcie_am654_read_dbi2, .write_dbi2 = ks_pcie_am654_write_dbi2, }; diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 90dc1674aae5..9e389a9be691 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -166,21 +166,6 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val) } EXPORT_SYMBOL_GPL(dw_pcie_write_dbi); -u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size) -{ - int ret; - u32 val; - - if (pci->ops->read_dbi2) - return pci->ops->read_dbi2(pci, pci->dbi_base2, reg, size); - - ret = dw_pcie_read(pci->dbi_base2 + reg, size, &val); - if (ret) - dev_err(pci->dev, "read DBI address failed\n"); - - return val; -} - void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val) { int ret; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index c56f1adb0d78..9f4db9fb9057 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -232,8 +232,6 @@ struct dw_pcie_ops { size_t size); void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg, size_t size, u32 val); - u32 (*read_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, - size_t size); void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, size_t size, u32 val); int (*link_up)(struct dw_pcie *pcie); @@ -269,7 +267,6 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val); u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size); void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val); -u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size); void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size); void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val); @@ -322,11 +319,6 @@ static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val) dw_pcie_write_dbi2(pci, reg, 0x4, val); } -static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg) -{ - return dw_pcie_read_dbi2(pci, reg, 0x4); -} - static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) { dw_pcie_write_atu(pci, reg, 0x4, val); -- cgit v1.2.3 From b04a6b9d395d4bf540a1b7534e0ed16bea084c15 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:13 -0600 Subject: PCI: dwc: Make ATU accessors private The ATU registers are only accessed in pcie-designware.c and can be private to it. Link: https://lore.kernel.org/r/20200821035420.380495-34-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware.c | 12 ++++++------ drivers/pci/controller/dwc/pcie-designware.h | 12 ------------ 2 files changed, 6 insertions(+), 18 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 9e389a9be691..8b1c10595f62 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -180,31 +180,31 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val) dev_err(pci->dev, "write DBI address failed\n"); } -u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size) +static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg) { int ret; u32 val; if (pci->ops->read_dbi) - return pci->ops->read_dbi(pci, pci->atu_base, reg, size); + return pci->ops->read_dbi(pci, pci->atu_base, reg, 4); - ret = dw_pcie_read(pci->atu_base + reg, size, &val); + ret = dw_pcie_read(pci->atu_base + reg, 4, &val); if (ret) dev_err(pci->dev, "Read ATU address failed\n"); return val; } -void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val) +static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) { int ret; if (pci->ops->write_dbi) { - pci->ops->write_dbi(pci, pci->atu_base, reg, size, val); + pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val); return; } - ret = dw_pcie_write(pci->atu_base + reg, size, val); + ret = dw_pcie_write(pci->atu_base + reg, 4, val); if (ret) dev_err(pci->dev, "Write ATU address failed\n"); } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 9f4db9fb9057..edf6143e1a99 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -268,8 +268,6 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val); u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size); void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val); void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); -u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size); -void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val); int dw_pcie_link_up(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci); void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen); @@ -319,16 +317,6 @@ static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val) dw_pcie_write_dbi2(pci, reg, 0x4, val); } -static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) -{ - dw_pcie_write_atu(pci, reg, 0x4, val); -} - -static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg) -{ - return dw_pcie_read_atu(pci, reg, 0x4); -} - static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci) { u32 reg; -- cgit v1.2.3 From d5071f086bac56288646556bbf760e13c2febffe Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Fri, 4 Sep 2020 15:21:32 +0100 Subject: PCI: mvebu: Remove useless msi_controller pointer allocation The mvebu host controller driver allocates an msi_controller structure pointer without allocating the structure and initializing its methods, which makes the pointer useless. This means that the PCI IRQ MSI layer ignores it and that after all it should not really be needed. Remove it. Link: https://lore.kernel.org/r/20200904142132.6054-1-lorenzo.pieralisi@arm.com Signed-off-by: Lorenzo Pieralisi Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Cc: Rob Herring Cc: Thomas Petazzoni --- drivers/pci/controller/pci-mvebu.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index c39978b750ec..eee82838f4ba 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -70,7 +69,6 @@ struct mvebu_pcie_port; struct mvebu_pcie { struct platform_device *pdev; struct mvebu_pcie_port *ports; - struct msi_controller *msi; struct resource io; struct resource realio; struct resource mem; @@ -1127,7 +1125,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev) bridge->sysdata = pcie; bridge->ops = &mvebu_pcie_ops; bridge->align_resource = mvebu_pcie_align_resource; - bridge->msi = pcie->msi; return mvebu_pci_host_probe(bridge); } -- cgit v1.2.3 From eb7eacaa5b9e4f665bd08d416c8f88e63d2f123c Mon Sep 17 00:00:00 2001 From: Mark Tomlinson Date: Mon, 3 Aug 2020 15:52:40 +1200 Subject: PCI: iproc: Set affinity mask on MSI interrupts The core interrupt code expects the irq_set_affinity call to update the effective affinity for the interrupt. This was not being done, so update iproc_msi_irq_set_affinity() to do so. Link: https://lore.kernel.org/r/20200803035241.7737-1-mark.tomlinson@alliedtelesis.co.nz Fixes: 3bc2b2348835 ("PCI: iproc: Add iProc PCIe MSI support") Signed-off-by: Mark Tomlinson Signed-off-by: Lorenzo Pieralisi Reviewed-by: Ray Jui --- drivers/pci/controller/pcie-iproc-msi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c index 3176ad3ab0e5..908475d27e0e 100644 --- a/drivers/pci/controller/pcie-iproc-msi.c +++ b/drivers/pci/controller/pcie-iproc-msi.c @@ -209,15 +209,20 @@ static int iproc_msi_irq_set_affinity(struct irq_data *data, struct iproc_msi *msi = irq_data_get_irq_chip_data(data); int target_cpu = cpumask_first(mask); int curr_cpu; + int ret; curr_cpu = hwirq_to_cpu(msi, data->hwirq); if (curr_cpu == target_cpu) - return IRQ_SET_MASK_OK_DONE; + ret = IRQ_SET_MASK_OK_DONE; + else { + /* steer MSI to the target CPU */ + data->hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq) + target_cpu; + ret = IRQ_SET_MASK_OK; + } - /* steer MSI to the target CPU */ - data->hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq) + target_cpu; + irq_data_update_effective_affinity(data, cpumask_of(target_cpu)); - return IRQ_SET_MASK_OK; + return ret; } static void iproc_msi_irq_compose_msi_msg(struct irq_data *data, -- cgit v1.2.3 From 39bc5006501cc31987f4fc249c5ce07286b84768 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:14 -0600 Subject: PCI: dwc: Centralize link gen setting keystone would force gen2 if no DT property. Now it relies on the PCI_EXP_LNKCAP value. Link: https://lore.kernel.org/r/20200821035420.380495-35-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Richard Zhu Cc: Lucas Stach Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Cc: Murali Karicheri Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Stanimir Varbanov Cc: Andy Gross Cc: Bjorn Andersson Cc: Pratyush Anand Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-omap@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-arm-msm@vger.kernel.org Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 26 ------------------ drivers/pci/controller/dwc/pci-imx6.c | 9 +++---- drivers/pci/controller/dwc/pci-keystone.c | 33 ----------------------- drivers/pci/controller/dwc/pcie-designware-ep.c | 11 ++++++-- drivers/pci/controller/dwc/pcie-designware-host.c | 3 +++ drivers/pci/controller/dwc/pcie-designware.c | 33 +++++++++++++---------- drivers/pci/controller/dwc/pcie-designware.h | 2 +- drivers/pci/controller/dwc/pcie-intel-gw.c | 13 +++------ drivers/pci/controller/dwc/pcie-qcom.c | 11 -------- drivers/pci/controller/dwc/pcie-spear13xx.c | 27 +------------------ drivers/pci/controller/dwc/pcie-tegra194.c | 23 ---------------- 11 files changed, 40 insertions(+), 151 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 d42e0664f378..8f0b6d644e4b 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -89,7 +89,6 @@ struct dra7xx_pcie { void __iomem *base; /* DT ti_conf */ int phy_count; /* DT phy-names count */ struct phy **phy; - int link_gen; struct irq_domain *irq_domain; enum dw_pcie_device_mode mode; }; @@ -140,33 +139,12 @@ static int dra7xx_pcie_establish_link(struct dw_pcie *pci) struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); struct device *dev = pci->dev; u32 reg; - u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); if (dw_pcie_link_up(pci)) { dev_err(dev, "link is already up\n"); return 0; } - if (dra7xx->link_gen == 1) { - dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP, - 4, ®); - if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) { - reg &= ~((u32)PCI_EXP_LNKCAP_SLS); - reg |= PCI_EXP_LNKCAP_SLS_2_5GB; - dw_pcie_write(pci->dbi_base + exp_cap_off + - PCI_EXP_LNKCAP, 4, reg); - } - - dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2, - 2, ®); - if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) { - reg &= ~((u32)PCI_EXP_LNKCAP_SLS); - reg |= PCI_EXP_LNKCAP_SLS_2_5GB; - dw_pcie_write(pci->dbi_base + exp_cap_off + - PCI_EXP_LNKCTL2, 2, reg); - } - } - reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); reg |= LTSSM_EN; dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); @@ -935,10 +913,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) reg &= ~LTSSM_EN; dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); - dra7xx->link_gen = of_pci_get_max_link_speed(np); - if (dra7xx->link_gen < 0 || dra7xx->link_gen > 2) - dra7xx->link_gen = 2; - switch (mode) { case DW_PCIE_RC_TYPE: if (!IS_ENABLED(CONFIG_PCI_DRA7XX_HOST)) { diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 9f6018d3d338..337c74cbdfdb 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -79,7 +79,6 @@ struct imx6_pcie { u32 tx_deemph_gen2_6db; u32 tx_swing_full; u32 tx_swing_low; - int link_gen; struct regulator *vpcie; void __iomem *phy_base; @@ -771,7 +770,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) if (ret) goto err_reset_phy; - if (imx6_pcie->link_gen == 2) { + if (pci->link_gen == 2) { /* Allow Gen2 mode after the link is up. */ tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); tmp &= ~PCI_EXP_LNKCAP_SLS; @@ -1153,10 +1152,8 @@ static int imx6_pcie_probe(struct platform_device *pdev) imx6_pcie->tx_swing_low = 127; /* Limit link speed */ - ret = of_property_read_u32(node, "fsl,max-link-speed", - &imx6_pcie->link_gen); - if (ret) - imx6_pcie->link_gen = 1; + pci->link_gen = 1; + ret = of_property_read_u32(node, "fsl,max-link-speed", &pci->link_gen); imx6_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie"); if (IS_ERR(imx6_pcie->vpcie)) { diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 5fe36da0b7c6..b554812dace7 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1107,32 +1107,6 @@ static int ks_pcie_am654_set_mode(struct device *dev, return 0; } -static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed) -{ - u32 val; - u32 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); - - dw_pcie_dbi_ro_wr_en(pci); - - val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); - if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { - val &= ~((u32)PCI_EXP_LNKCAP_SLS); - val |= link_speed; - dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, - val); - } - - val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2); - if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { - val &= ~((u32)PCI_EXP_LNKCAP_SLS); - val |= link_speed; - dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, - val); - } - - dw_pcie_dbi_ro_wr_dis(pci); -} - static const struct ks_pcie_of_data ks_pcie_rc_of_data = { .host_ops = &ks_pcie_host_ops, .version = 0x365A, @@ -1185,7 +1159,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) unsigned int version; void __iomem *base; struct phy **phy; - int link_speed; u32 num_lanes; char name[10]; int ret; @@ -1320,12 +1293,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - link_speed = of_pci_get_max_link_speed(np); - if (link_speed < 0) - link_speed = 2; - - ks_pcie_set_link_speed(pci, link_speed); - switch (mode) { case DW_PCIE_RC_TYPE: if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_HOST)) { diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 29f5c616c3bc..05415a82e9f4 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -12,6 +12,8 @@ #include #include +#include "../../pci.h" + void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) { struct pci_epc *epc = ep->epc; @@ -519,18 +521,20 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX); offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); + + dw_pcie_dbi_ro_wr_en(pci); + if (offset) { reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> PCI_REBAR_CTRL_NBAR_SHIFT; - dw_pcie_dbi_ro_wr_en(pci); for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0); - dw_pcie_dbi_ro_wr_dis(pci); } dw_pcie_setup(pci); + dw_pcie_dbi_ro_wr_dis(pci); return 0; } @@ -591,6 +595,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) return -ENOMEM; ep->outbound_addr = addr; + if (pci->link_gen < 1) + pci->link_gen = of_pci_get_max_link_speed(np); + epc = devm_pci_epc_create(dev, &epc_ops); if (IS_ERR(epc)) { dev_err(dev, "Failed to create epc device\n"); diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 4f21d95b4077..317ff512f8df 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -361,6 +361,9 @@ int dw_pcie_host_init(struct pcie_port *pp) if (ret) pci->num_viewport = 2; + if (pci->link_gen < 1) + pci->link_gen = of_pci_get_max_link_speed(np); + if (pci_msi_enabled()) { /* * If a specific SoC driver needs to change the diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 8b1c10595f62..62a6735ada9e 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -473,39 +473,41 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci) } EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup); -void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen) +static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen) { - u32 reg, val; + u32 cap, ctrl2, link_speed; u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); - reg = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2); - reg &= ~PCI_EXP_LNKCTL2_TLS; + cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); + ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2); + ctrl2 &= ~PCI_EXP_LNKCTL2_TLS; switch (pcie_link_speed[link_gen]) { case PCIE_SPEED_2_5GT: - reg |= PCI_EXP_LNKCTL2_TLS_2_5GT; + link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT; break; case PCIE_SPEED_5_0GT: - reg |= PCI_EXP_LNKCTL2_TLS_5_0GT; + link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT; break; case PCIE_SPEED_8_0GT: - reg |= PCI_EXP_LNKCTL2_TLS_8_0GT; + link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT; break; case PCIE_SPEED_16_0GT: - reg |= PCI_EXP_LNKCTL2_TLS_16_0GT; + link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT; break; default: /* Use hardware capability */ - val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); - val = FIELD_GET(PCI_EXP_LNKCAP_SLS, val); - reg &= ~PCI_EXP_LNKCTL2_HASD; - reg |= FIELD_PREP(PCI_EXP_LNKCTL2_TLS, val); + link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap); + ctrl2 &= ~PCI_EXP_LNKCTL2_HASD; break; } - dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, reg); + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed); + + cap &= ~((u32)PCI_EXP_LNKCAP_SLS); + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed); + } -EXPORT_SYMBOL_GPL(dw_pcie_link_set_max_speed); void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts) { @@ -544,6 +546,9 @@ void dw_pcie_setup(struct dw_pcie *pci) dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? "enabled" : "disabled"); + if (pci->link_gen > 0) + dw_pcie_link_set_max_speed(pci, pci->link_gen); + val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); val &= ~PORT_LINK_FAST_LINK_MODE; dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index edf6143e1a99..a814b1f17260 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -252,6 +252,7 @@ struct dw_pcie { const struct dw_pcie_ops *ops; unsigned int version; int num_lanes; + int link_gen; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) @@ -270,7 +271,6 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val); void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); int dw_pcie_link_up(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci); -void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen); void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts); int dw_pcie_wait_for_link(struct dw_pcie *pci); void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index c3b3a1d162b5..2c0d32ffb828 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -67,8 +67,6 @@ struct intel_pcie_port { void __iomem *app_base; struct gpio_desc *reset_gpio; u32 rst_intrvl; - u32 max_speed; - u32 link_gen; u32 max_width; u32 n_fts; struct clk *core_clk; @@ -137,7 +135,6 @@ static void intel_pcie_link_setup(struct intel_pcie_port *lpp) u8 offset = lpp->pcie_cap_ofst; val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCAP); - lpp->max_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, val); lpp->max_width = FIELD_GET(PCI_EXP_LNKCAP_MLW, val); val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCTL); @@ -149,8 +146,9 @@ static void intel_pcie_link_setup(struct intel_pcie_port *lpp) static void intel_pcie_port_logic_setup(struct intel_pcie_port *lpp) { u32 val, mask; + struct dw_pcie *pci = &lpp->pci; - switch (pcie_link_speed[lpp->max_speed]) { + switch (pcie_link_speed[pci->link_gen]) { case PCIE_SPEED_8_0GT: lpp->n_fts = PORT_AFR_N_FTS_GEN3; break; @@ -179,7 +177,6 @@ static void intel_pcie_rc_setup(struct intel_pcie_port *lpp) dw_pcie_setup_rc(&lpp->pci.pp); dw_pcie_upconfig_setup(&lpp->pci); intel_pcie_port_logic_setup(lpp); - dw_pcie_link_set_max_speed(&lpp->pci, lpp->link_gen); dw_pcie_link_set_n_fts(&lpp->pci, lpp->n_fts); } @@ -286,9 +283,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev) if (ret) lpp->rst_intrvl = RESET_INTERVAL_MS; - ret = of_pci_get_max_link_speed(dev->of_node); - lpp->link_gen = ret < 0 ? 0 : ret; - lpp->app_base = devm_platform_ioremap_resource_byname(pdev, "app"); if (IS_ERR(lpp->app_base)) return PTR_ERR(lpp->app_base); @@ -313,8 +307,9 @@ static int intel_pcie_wait_l2(struct intel_pcie_port *lpp) { u32 value; int ret; + struct dw_pcie *pci = &lpp->pci; - if (pcie_link_speed[lpp->max_speed] < PCIE_SPEED_8_0GT) + if (pci->link_gen < 3) return 0; /* Send PME_TURN_OFF message */ diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index d8d1fb7e0b8f..5eb28251dbee 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -189,7 +189,6 @@ struct qcom_pcie { struct phy *phy; struct gpio_desc *reset; const struct qcom_pcie_ops *ops; - int gen; }; #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) @@ -390,12 +389,6 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie) /* wait for clock acquisition */ usleep_range(1000, 1500); - if (pcie->gen == 1) { - val = readl(pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2); - val |= PCI_EXP_LNKSTA_CLS_2_5GB; - writel(val, pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2); - } - /* Set the Max TLP size to 2K, instead of using default of 4K */ writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K, pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL0); @@ -1395,10 +1388,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) goto err_pm_runtime_put; } - pcie->gen = of_pci_get_max_link_speed(pdev->dev.of_node); - if (pcie->gen < 0) - pcie->gen = 2; - pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf"); if (IS_ERR(pcie->parf)) { ret = PTR_ERR(pcie->parf); diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index 056c94541a22..0d8d0fe87f27 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -26,7 +26,6 @@ struct spear13xx_pcie { void __iomem *app_base; struct phy *phy; struct clk *clk; - bool is_gen1; }; struct pcie_app_reg { @@ -94,30 +93,6 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) dw_pcie_write(pci->dbi_base + PCI_VENDOR_ID, 2, 0x104A); dw_pcie_write(pci->dbi_base + PCI_DEVICE_ID, 2, 0xCD80); - /* - * if is_gen1 is set then handle it, so that some buggy card - * also works - */ - if (spear13xx_pcie->is_gen1) { - dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP, - 4, &val); - if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) { - val &= ~((u32)PCI_EXP_LNKCAP_SLS); - val |= PCI_EXP_LNKCAP_SLS_2_5GB; - dw_pcie_write(pci->dbi_base + exp_cap_off + - PCI_EXP_LNKCAP, 4, val); - } - - dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2, - 2, &val); - if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) { - val &= ~((u32)PCI_EXP_LNKCAP_SLS); - val |= PCI_EXP_LNKCAP_SLS_2_5GB; - dw_pcie_write(pci->dbi_base + exp_cap_off + - PCI_EXP_LNKCTL2, 2, val); - } - } - /* enable ltssm */ writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID) | (1 << APP_LTSSM_ENABLE_ID) @@ -276,7 +251,7 @@ static int spear13xx_pcie_probe(struct platform_device *pdev) spear13xx_pcie->app_base = pci->dbi_base + 0x2000; if (of_property_read_bool(np, "st,pcie-is-gen1")) - spear13xx_pcie->is_gen1 = true; + pci->link_gen = 1; platform_set_drvdata(pdev, spear13xx_pcie); diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index f121ac25d418..91ef4b3e860d 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -284,7 +284,6 @@ struct tegra_pcie_dw { u8 init_link_width; u32 msi_ctrl_int; u32 num_lanes; - u32 max_speed; u32 cid; u32 cfg_link_cap_l1sub; u32 pcie_cap_base; @@ -900,16 +899,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp) AMBA_ERROR_RESPONSE_CRS_SHIFT); dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val); - /* Configure Max Speed from DT */ - if (pcie->max_speed && pcie->max_speed != -EINVAL) { - val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + - PCI_EXP_LNKCAP); - val &= ~PCI_EXP_LNKCAP_SLS; - val |= pcie->max_speed; - dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP, - val); - } - /* Configure Max lane width from DT */ val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP); val &= ~PCI_EXP_LNKCAP_MLW; @@ -1119,8 +1108,6 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) return ret; } - pcie->max_speed = of_pci_get_max_link_speed(np); - ret = of_property_read_u32_index(np, "nvidia,bpmp", 1, &pcie->cid); if (ret) { dev_err(pcie->dev, "Failed to read Controller-ID: %d\n", ret); @@ -1818,16 +1805,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) val |= FTS_VAL; dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); - /* Configure Max Speed from DT */ - if (pcie->max_speed && pcie->max_speed != -EINVAL) { - val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + - PCI_EXP_LNKCAP); - val &= ~PCI_EXP_LNKCAP_SLS; - val |= pcie->max_speed; - dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP, - val); - } - pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP); clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ); -- cgit v1.2.3 From 441e48fdf0b403218805b320d93de5caeafdcb1d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:15 -0600 Subject: PCI: dwc: Set PORT_LINK_DLL_LINK_EN in common setup code The Intel driver is the only one to set PORT_LINK_DLL_LINK_EN. The default value is set and it seems pretty certain that enabling link initialization is always required. Maybe it could just be dropped from the Intel driver, but lets move setting it into the common code to be sure. Link: https://lore.kernel.org/r/20200821035420.380495-36-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Dilip Kota Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware.c | 1 + drivers/pci/controller/dwc/pcie-intel-gw.c | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 62a6735ada9e..5240153c15ba 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -551,6 +551,7 @@ void dw_pcie_setup(struct dw_pcie *pci) val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); val &= ~PORT_LINK_FAST_LINK_MODE; + val |= PORT_LINK_DLL_LINK_EN; dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); of_property_read_u32(np, "num-lanes", &pci->num_lanes); diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 2c0d32ffb828..d15e49b8df2a 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -164,10 +164,6 @@ static void intel_pcie_port_logic_setup(struct intel_pcie_port *lpp) val = FIELD_PREP(PORT_AFR_N_FTS_MASK, lpp->n_fts) | FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, lpp->n_fts); pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_AFR, mask, val); - - /* Port Link Control Register */ - pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_LINK_CONTROL, PORT_LINK_DLL_LINK_EN, - PORT_LINK_DLL_LINK_EN); } static void intel_pcie_rc_setup(struct intel_pcie_port *lpp) -- cgit v1.2.3 From b02b06a74b01a5e9d3fcbd76a5b748376d9e9ced Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:16 -0600 Subject: PCI: dwc/intel-gw: Drop unnecessary checking of DT 'device_type' property A driver doesn't need to check for DT 'device_type' property, so let's remove the check. Link: https://lore.kernel.org/r/20200821035420.380495-37-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Dilip Kota Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-intel-gw.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index d15e49b8df2a..6b102197a1b6 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -268,12 +268,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev) return ret; } - ret = device_property_match_string(dev, "device_type", "pci"); - if (ret) { - dev_err(dev, "Failed to find pci device type: %d\n", ret); - return ret; - } - ret = device_property_read_u32(dev, "reset-assert-ms", &lpp->rst_intrvl); if (ret) -- cgit v1.2.3 From cf854be2d9a34665cbbd40d58409fc868ed476fc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:17 -0600 Subject: PCI: dwc/intel-gw: Move getting PCI_CAP_ID_EXP offset to intel_pcie_link_setup() The PCI_CAP_ID_EXP offset is only needed by intel_pcie_link_setup(), so let's retrieve it there and avoid storing the offset. Link: https://lore.kernel.org/r/20200821035420.380495-38-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Dilip Kota Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-intel-gw.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 6b102197a1b6..807e1fa1bd6f 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -72,7 +72,6 @@ struct intel_pcie_port { struct clk *core_clk; struct reset_control *core_rst; struct phy *phy; - u8 pcie_cap_ofst; }; static void pcie_update_bits(void __iomem *base, u32 ofs, u32 mask, u32 val) @@ -132,7 +131,7 @@ static void intel_pcie_ltssm_disable(struct intel_pcie_port *lpp) static void intel_pcie_link_setup(struct intel_pcie_port *lpp) { u32 val; - u8 offset = lpp->pcie_cap_ofst; + u8 offset = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP); val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCAP); lpp->max_width = FIELD_GET(PCI_EXP_LNKCAP_MLW, val); @@ -328,7 +327,6 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp) static int intel_pcie_host_setup(struct intel_pcie_port *lpp) { - struct device *dev = lpp->pci.dev; int ret; intel_pcie_core_rst_assert(lpp); @@ -346,17 +344,6 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp) goto clk_err; } - if (!lpp->pcie_cap_ofst) { - ret = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP); - if (!ret) { - ret = -ENXIO; - dev_err(dev, "Invalid PCIe capability offset\n"); - goto app_init_err; - } - - lpp->pcie_cap_ofst = ret; - } - intel_pcie_rc_setup(lpp); ret = intel_pcie_app_logic_setup(lpp); if (ret) -- cgit v1.2.3 From d439e7edd1343ead0150851ca78055858ee8b94e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:18 -0600 Subject: PCI: dwc/intel-gw: Drop unused max_width 'max_width' is read, but never used, so let's remove it. Link: https://lore.kernel.org/r/20200821035420.380495-39-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Dilip Kota Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-intel-gw.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 807e1fa1bd6f..333f11561807 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -67,7 +67,6 @@ struct intel_pcie_port { void __iomem *app_base; struct gpio_desc *reset_gpio; u32 rst_intrvl; - u32 max_width; u32 n_fts; struct clk *core_clk; struct reset_control *core_rst; @@ -133,9 +132,6 @@ static void intel_pcie_link_setup(struct intel_pcie_port *lpp) u32 val; u8 offset = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP); - val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCAP); - lpp->max_width = FIELD_GET(PCI_EXP_LNKCAP_MLW, val); - val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCTL); val &= ~(PCI_EXP_LNKCTL_LD | PCI_EXP_LNKCTL_ASPMC); -- cgit v1.2.3 From aeaa0bfe896547d3fb52533909a6ddef5c1191ba Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:19 -0600 Subject: PCI: dwc: Move N_FTS setup to common setup The Designware controller has common registers to set number of fast training sequence ordered sets. The Artpec6, Intel, and Tegra driver initialize these register fields. Let's move the initialization to the common setup code and drivers just have to provide the value. There's a slight change in that the common clock mode N_FTS field is now initialized. Previously only the Intel driver set this. It's not clear from the code if common clock mode is used in the Artpec6 or Tegra driver. It depends on the DWC configuration. Given the field is not initialized while the others are, it seems unlikely common clock mode is used. Link: https://lore.kernel.org/r/20200821035420.380495-40-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Jesper Nilsson Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Jingoo Han Cc: Gustavo Pimentel Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pcie-artpec6.c | 37 +++------------------------- drivers/pci/controller/dwc/pcie-designware.c | 28 ++++++++++++--------- drivers/pci/controller/dwc/pcie-designware.h | 3 ++- drivers/pci/controller/dwc/pcie-intel-gw.c | 27 +++++++------------- drivers/pci/controller/dwc/pcie-tegra194.c | 25 +++---------------- 5 files changed, 35 insertions(+), 85 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 86f4d66d8587..929448e9e0bc 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -44,13 +44,6 @@ struct artpec_pcie_of_data { static const struct of_device_id artpec6_pcie_of_match[]; -/* PCIe Port Logic registers (memory-mapped) */ -#define PL_OFFSET 0x700 - -#define ACK_F_ASPM_CTRL_OFF (PL_OFFSET + 0xc) -#define ACK_N_FTS_MASK GENMASK(15, 8) -#define ACK_N_FTS(x) (((x) << 8) & ACK_N_FTS_MASK) - /* ARTPEC-6 specific registers */ #define PCIECFG 0x18 #define PCIECFG_DBG_OEN BIT(24) @@ -289,30 +282,6 @@ static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) } } -static void artpec6_pcie_set_nfts(struct artpec6_pcie *artpec6_pcie) -{ - struct dw_pcie *pci = artpec6_pcie->pci; - u32 val; - - if (artpec6_pcie->variant != ARTPEC7) - return; - - /* - * Increase the N_FTS (Number of Fast Training Sequences) - * to be transmitted when transitioning from L0s to L0. - */ - val = dw_pcie_readl_dbi(pci, ACK_F_ASPM_CTRL_OFF); - val &= ~ACK_N_FTS_MASK; - val |= ACK_N_FTS(180); - dw_pcie_writel_dbi(pci, ACK_F_ASPM_CTRL_OFF, val); - - /* - * Set the Number of Fast Training Sequences that the core - * advertises as its N_FTS during Gen2 or Gen3 link training. - */ - dw_pcie_link_set_n_fts(pci, 180); -} - static void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie) { u32 val; @@ -351,11 +320,14 @@ static int artpec6_pcie_host_init(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); + if (artpec6_pcie->variant == ARTPEC7) { + pci->n_fts[0] = 180; + pci->n_fts[1] = 180; + } artpec6_pcie_assert_core_reset(artpec6_pcie); artpec6_pcie_init_phy(artpec6_pcie); artpec6_pcie_deassert_core_reset(artpec6_pcie); artpec6_pcie_wait_for_phy(artpec6_pcie); - artpec6_pcie_set_nfts(artpec6_pcie); dw_pcie_setup_rc(pp); artpec6_pcie_establish_link(pci); dw_pcie_wait_for_link(pci); @@ -403,7 +375,6 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) artpec6_pcie_init_phy(artpec6_pcie); artpec6_pcie_deassert_core_reset(artpec6_pcie); artpec6_pcie_wait_for_phy(artpec6_pcie); - artpec6_pcie_set_nfts(artpec6_pcie); for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) dw_pcie_ep_reset_bar(pci, bar); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 5240153c15ba..3c3a4d1dbc0b 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -509,17 +509,6 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen) } -void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts) -{ - u32 val; - - val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); - val &= ~PORT_LOGIC_N_FTS_MASK; - val |= n_fts & PORT_LOGIC_N_FTS_MASK; - dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); -} -EXPORT_SYMBOL_GPL(dw_pcie_link_set_n_fts); - static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) { u32 val; @@ -549,6 +538,23 @@ void dw_pcie_setup(struct dw_pcie *pci) if (pci->link_gen > 0) dw_pcie_link_set_max_speed(pci, pci->link_gen); + /* Configure Gen1 N_FTS */ + if (pci->n_fts[0]) { + val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); + val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK); + val |= PORT_AFR_N_FTS(pci->n_fts[0]); + val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]); + dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); + } + + /* Configure Gen2+ N_FTS */ + if (pci->n_fts[1]) { + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_N_FTS_MASK; + val |= pci->n_fts[pci->link_gen - 1]; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); + } + val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); val &= ~PORT_LINK_FAST_LINK_MODE; val |= PORT_LINK_DLL_LINK_EN; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index a814b1f17260..8cbc902a311a 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -34,6 +34,7 @@ #define PORT_AFR_N_FTS_MASK GENMASK(15, 8) #define PORT_AFR_N_FTS(n) FIELD_PREP(PORT_AFR_N_FTS_MASK, n) #define PORT_AFR_CC_N_FTS_MASK GENMASK(23, 16) +#define PORT_AFR_CC_N_FTS(n) FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, n) #define PORT_AFR_ENTER_ASPM BIT(30) #define PORT_AFR_L0S_ENTRANCE_LAT_SHIFT 24 #define PORT_AFR_L0S_ENTRANCE_LAT_MASK GENMASK(26, 24) @@ -253,6 +254,7 @@ struct dw_pcie { unsigned int version; int num_lanes; int link_gen; + u8 n_fts[2]; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) @@ -271,7 +273,6 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val); void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); int dw_pcie_link_up(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci); -void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts); int dw_pcie_wait_for_link(struct dw_pcie *pci); void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, u64 cpu_addr, u64 pci_addr, diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 333f11561807..5650cb78acba 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -67,7 +67,6 @@ struct intel_pcie_port { void __iomem *app_base; struct gpio_desc *reset_gpio; u32 rst_intrvl; - u32 n_fts; struct clk *core_clk; struct reset_control *core_rst; struct phy *phy; @@ -138,37 +137,29 @@ static void intel_pcie_link_setup(struct intel_pcie_port *lpp) pcie_rc_cfg_wr(lpp, offset + PCI_EXP_LNKCTL, val); } -static void intel_pcie_port_logic_setup(struct intel_pcie_port *lpp) +static void intel_pcie_init_n_fts(struct dw_pcie *pci) { - u32 val, mask; - struct dw_pcie *pci = &lpp->pci; - - switch (pcie_link_speed[pci->link_gen]) { - case PCIE_SPEED_8_0GT: - lpp->n_fts = PORT_AFR_N_FTS_GEN3; + switch (pci->link_gen) { + case 3: + pci->n_fts[1] = PORT_AFR_N_FTS_GEN3; break; - case PCIE_SPEED_16_0GT: - lpp->n_fts = PORT_AFR_N_FTS_GEN4; + case 4: + pci->n_fts[1] = PORT_AFR_N_FTS_GEN4; break; default: - lpp->n_fts = PORT_AFR_N_FTS_GEN12_DFT; + pci->n_fts[1] = PORT_AFR_N_FTS_GEN12_DFT; break; } - - mask = PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK; - val = FIELD_PREP(PORT_AFR_N_FTS_MASK, lpp->n_fts) | - FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, lpp->n_fts); - pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_AFR, mask, val); + pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT; } static void intel_pcie_rc_setup(struct intel_pcie_port *lpp) { intel_pcie_ltssm_disable(lpp); intel_pcie_link_setup(lpp); + intel_pcie_init_n_fts(&lpp->pci); dw_pcie_setup_rc(&lpp->pci.pp); dw_pcie_upconfig_setup(&lpp->pci); - intel_pcie_port_logic_setup(lpp); - dw_pcie_link_set_n_fts(&lpp->pci, lpp->n_fts); } static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 91ef4b3e860d..1560c449757d 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -881,17 +881,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp) dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); - /* Configure FTS */ - val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); - val &= ~PORT_AFR_N_FTS_MASK; - val |= PORT_AFR_N_FTS(N_FTS_VAL); - dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); - - val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); - val &= ~PORT_LOGIC_N_FTS_MASK; - val |= FTS_VAL; - dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); - /* Enable as 0xFFFF0001 response for CRS */ val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT); val &= ~(AMBA_ERROR_RESPONSE_CRS_MASK << AMBA_ERROR_RESPONSE_CRS_SHIFT); @@ -1794,17 +1783,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); - /* Configure N_FTS & FTS */ - val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); - val &= ~PORT_AFR_N_FTS_MASK; - val |= PORT_AFR_N_FTS(FTS_VAL); - dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); - - val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); - val &= ~PORT_LOGIC_N_FTS_MASK; - val |= FTS_VAL; - dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); - pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP); clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ); @@ -2033,6 +2011,9 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) pci = &pcie->pci; pci->dev = &pdev->dev; pci->ops = &tegra_dw_pcie_ops; + pci->n_fts[0] = N_FTS_VAL; + pci->n_fts[1] = FTS_VAL; + pp = &pci->pp; pcie->dev = &pdev->dev; pcie->mode = (enum dw_pcie_device_mode)data->mode; -- cgit v1.2.3 From fdd056ff7af4111eb8cee1da0b2912c0d4b24fac Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Aug 2020 21:54:20 -0600 Subject: PCI: dwc: Use DBI accessors Convert the remaining cases of register accesses using dbi_base rather than dw_pcie_(read|write)[bwl]_dbi accessors. Link: https://lore.kernel.org/r/20200821035420.380495-41-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Lorenzo Pieralisi Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Pratyush Anand Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-tegra@vger.kernel.org --- drivers/pci/controller/dwc/pcie-spear13xx.c | 8 ++++---- drivers/pci/controller/dwc/pcie-tegra194.c | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index 0d8d0fe87f27..e348225f651f 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -86,12 +86,12 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) * default value in capability register is 512 bytes. So force * it to 128 here. */ - dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val); + val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL); val &= ~PCI_EXP_DEVCTL_READRQ; - dw_pcie_write(pci->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val); + dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val); - dw_pcie_write(pci->dbi_base + PCI_VENDOR_ID, 2, 0x104A); - dw_pcie_write(pci->dbi_base + PCI_DEVICE_ID, 2, 0xCD80); + dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A); + dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80); /* enable ltssm */ writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 1560c449757d..aa511ec0d800 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -816,26 +816,24 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie) /* Program init preset */ for (i = 0; i < pcie->num_lanes; i++) { - dw_pcie_read(pci->dbi_base + CAP_SPCIE_CAP_OFF - + (i * 2), 2, &val); + val = dw_pcie_readw_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2)); val &= ~CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK; val |= GEN3_GEN4_EQ_PRESET_INIT; val &= ~CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK; val |= (GEN3_GEN4_EQ_PRESET_INIT << CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT); - dw_pcie_write(pci->dbi_base + CAP_SPCIE_CAP_OFF - + (i * 2), 2, val); + dw_pcie_writew_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2), val); offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PL_16GT) + PCI_PL_16GT_LE_CTRL; - dw_pcie_read(pci->dbi_base + offset + i, 1, &val); + val = dw_pcie_readb_dbi(pci, offset + i); val &= ~PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK; val |= GEN3_GEN4_EQ_PRESET_INIT; val &= ~PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK; val |= (GEN3_GEN4_EQ_PRESET_INIT << PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT); - dw_pcie_write(pci->dbi_base + offset + i, 1, val); + dw_pcie_writeb_dbi(pci, offset + i, val); } val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); -- cgit v1.2.3 From acb52897cc842fae917c4441e0fefbc18133a08c Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Thu, 3 Sep 2020 13:34:56 +0100 Subject: PCI: hip: Add handling of HiSilicon HIP PCIe controller errors The HiSilicon HIP PCIe controller is capable of handling errors on root port and performing port reset separately at each root port. Add error handling driver for HIP PCIe controller to log and report recoverable errors. Perform root port reset and restore link status after the recovery. Following are some of the PCIe controller's recoverable errors 1. completion transmission timeout error. 2. CRS retry counter over the threshold error. 3. ECC 2 bit errors 4. AXI bresponse/rresponse errors etc. The driver placed in the drivers/pci/controller/ because the HIP PCIe controller does not use DWC IP. Link: https://lore.kernel.org/r/20200903123456.1823-3-shiju.jose@huawei.com Signed-off-by: Yicong Yang Signed-off-by: Shiju Jose Signed-off-by: Lorenzo Pieralisi Acked-by: Bjorn Helgaas --- drivers/pci/controller/Kconfig | 7 + drivers/pci/controller/Makefile | 1 + drivers/pci/controller/pcie-hisi-error.c | 327 +++++++++++++++++++++++++++++++ 3 files changed, 335 insertions(+) create mode 100644 drivers/pci/controller/pcie-hisi-error.c (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index f18c3725ef80..42dbc167765c 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -294,6 +294,13 @@ config PCI_LOONGSON Say Y here if you want to enable PCI controller support on Loongson systems. +config PCIE_HISI_ERR + depends on ACPI_APEI_GHES && (ARM64 || COMPILE_TEST) + bool "HiSilicon HIP PCIe controller error handling driver" + help + Say Y here if you want error handling support + for the PCIe controller's errors on HiSilicon HIP SoCs + source "drivers/pci/controller/dwc/Kconfig" source "drivers/pci/controller/mobiveil/Kconfig" source "drivers/pci/controller/cadence/Kconfig" diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index bcdbf49ab1e4..04c6edc285c5 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o obj-$(CONFIG_VMD) += vmd.o obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o +obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW obj-y += dwc/ obj-y += mobiveil/ diff --git a/drivers/pci/controller/pcie-hisi-error.c b/drivers/pci/controller/pcie-hisi-error.c new file mode 100644 index 000000000000..7959c9c8d2bc --- /dev/null +++ b/drivers/pci/controller/pcie-hisi-error.c @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for handling the PCIe controller errors on + * HiSilicon HIP SoCs. + * + * Copyright (c) 2020 HiSilicon Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* HISI PCIe controller error definitions */ +#define HISI_PCIE_ERR_MISC_REGS 33 + +#define HISI_PCIE_LOCAL_VALID_VERSION BIT(0) +#define HISI_PCIE_LOCAL_VALID_SOC_ID BIT(1) +#define HISI_PCIE_LOCAL_VALID_SOCKET_ID BIT(2) +#define HISI_PCIE_LOCAL_VALID_NIMBUS_ID BIT(3) +#define HISI_PCIE_LOCAL_VALID_SUB_MODULE_ID BIT(4) +#define HISI_PCIE_LOCAL_VALID_CORE_ID BIT(5) +#define HISI_PCIE_LOCAL_VALID_PORT_ID BIT(6) +#define HISI_PCIE_LOCAL_VALID_ERR_TYPE BIT(7) +#define HISI_PCIE_LOCAL_VALID_ERR_SEVERITY BIT(8) +#define HISI_PCIE_LOCAL_VALID_ERR_MISC 9 + +static guid_t hisi_pcie_sec_guid = + GUID_INIT(0xB2889FC9, 0xE7D7, 0x4F9D, + 0xA8, 0x67, 0xAF, 0x42, 0xE9, 0x8B, 0xE7, 0x72); + +/* + * Firmware reports the socket port ID where the error occurred. These + * macros convert that to the core ID and core port ID required by the + * ACPI reset method. + */ +#define HISI_PCIE_PORT_ID(core, v) (((v) >> 1) + ((core) << 3)) +#define HISI_PCIE_CORE_ID(v) ((v) >> 3) +#define HISI_PCIE_CORE_PORT_ID(v) (((v) & 7) << 1) + +struct hisi_pcie_error_data { + u64 val_bits; + u8 version; + u8 soc_id; + u8 socket_id; + u8 nimbus_id; + u8 sub_module_id; + u8 core_id; + u8 port_id; + u8 err_severity; + u16 err_type; + u8 reserv[2]; + u32 err_misc[HISI_PCIE_ERR_MISC_REGS]; +}; + +struct hisi_pcie_error_private { + struct notifier_block nb; + struct device *dev; +}; + +enum hisi_pcie_submodule_id { + HISI_PCIE_SUB_MODULE_ID_AP, + HISI_PCIE_SUB_MODULE_ID_TL, + HISI_PCIE_SUB_MODULE_ID_MAC, + HISI_PCIE_SUB_MODULE_ID_DL, + HISI_PCIE_SUB_MODULE_ID_SDI, +}; + +static const char * const hisi_pcie_sub_module[] = { + [HISI_PCIE_SUB_MODULE_ID_AP] = "AP Layer", + [HISI_PCIE_SUB_MODULE_ID_TL] = "TL Layer", + [HISI_PCIE_SUB_MODULE_ID_MAC] = "MAC Layer", + [HISI_PCIE_SUB_MODULE_ID_DL] = "DL Layer", + [HISI_PCIE_SUB_MODULE_ID_SDI] = "SDI Layer", +}; + +enum hisi_pcie_err_severity { + HISI_PCIE_ERR_SEV_RECOVERABLE, + HISI_PCIE_ERR_SEV_FATAL, + HISI_PCIE_ERR_SEV_CORRECTED, + HISI_PCIE_ERR_SEV_NONE, +}; + +static const char * const hisi_pcie_error_sev[] = { + [HISI_PCIE_ERR_SEV_RECOVERABLE] = "recoverable", + [HISI_PCIE_ERR_SEV_FATAL] = "fatal", + [HISI_PCIE_ERR_SEV_CORRECTED] = "corrected", + [HISI_PCIE_ERR_SEV_NONE] = "none", +}; + +static const char *hisi_pcie_get_string(const char * const *array, + size_t n, u32 id) +{ + u32 index; + + for (index = 0; index < n; index++) { + if (index == id && array[index]) + return array[index]; + } + + return "unknown"; +} + +static int hisi_pcie_port_reset(struct platform_device *pdev, + u32 chip_id, u32 port_id) +{ + struct device *dev = &pdev->dev; + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object arg[3]; + struct acpi_object_list arg_list; + acpi_status s; + unsigned long long data = 0; + + arg[0].type = ACPI_TYPE_INTEGER; + arg[0].integer.value = chip_id; + arg[1].type = ACPI_TYPE_INTEGER; + arg[1].integer.value = HISI_PCIE_CORE_ID(port_id); + arg[2].type = ACPI_TYPE_INTEGER; + arg[2].integer.value = HISI_PCIE_CORE_PORT_ID(port_id); + + arg_list.count = 3; + arg_list.pointer = arg; + + s = acpi_evaluate_integer(handle, "RST", &arg_list, &data); + if (ACPI_FAILURE(s)) { + dev_err(dev, "No RST method\n"); + return -EIO; + } + + if (data) { + dev_err(dev, "Failed to Reset\n"); + return -EIO; + } + + return 0; +} + +static int hisi_pcie_port_do_recovery(struct platform_device *dev, + u32 chip_id, u32 port_id) +{ + acpi_status s; + struct device *device = &dev->dev; + acpi_handle root_handle = ACPI_HANDLE(device); + struct acpi_pci_root *pci_root; + struct pci_bus *root_bus; + struct pci_dev *pdev; + u32 domain, busnr, devfn; + + s = acpi_get_parent(root_handle, &root_handle); + if (ACPI_FAILURE(s)) + return -ENODEV; + pci_root = acpi_pci_find_root(root_handle); + if (!pci_root) + return -ENODEV; + root_bus = pci_root->bus; + domain = pci_root->segment; + + busnr = root_bus->number; + devfn = PCI_DEVFN(port_id, 0); + pdev = pci_get_domain_bus_and_slot(domain, busnr, devfn); + if (!pdev) { + dev_info(device, "Fail to get root port %04x:%02x:%02x.%d device\n", + domain, busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); + return -ENODEV; + } + + pci_stop_and_remove_bus_device_locked(pdev); + pci_dev_put(pdev); + + if (hisi_pcie_port_reset(dev, chip_id, port_id)) + return -EIO; + + /* + * The initialization time of subordinate devices after + * hot reset is no more than 1s, which is required by + * the PCI spec v5.0 sec 6.6.1. The time will shorten + * if Readiness Notifications mechanisms are used. But + * wait 1s here to adapt any conditions. + */ + ssleep(1UL); + + /* add root port and downstream devices */ + pci_lock_rescan_remove(); + pci_rescan_bus(root_bus); + pci_unlock_rescan_remove(); + + return 0; +} + +static void hisi_pcie_handle_error(struct platform_device *pdev, + const struct hisi_pcie_error_data *edata) +{ + struct device *dev = &pdev->dev; + int idx, rc; + const unsigned long valid_bits[] = {BITMAP_FROM_U64(edata->val_bits)}; + + if (edata->val_bits == 0) { + dev_warn(dev, "%s: no valid error information\n", __func__); + return; + } + + dev_info(dev, "\nHISI : HIP : PCIe controller error\n"); + if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SOC_ID) + dev_info(dev, "Table version = %d\n", edata->version); + if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SOCKET_ID) + dev_info(dev, "Socket ID = %d\n", edata->socket_id); + if (edata->val_bits & HISI_PCIE_LOCAL_VALID_NIMBUS_ID) + dev_info(dev, "Nimbus ID = %d\n", edata->nimbus_id); + if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SUB_MODULE_ID) + dev_info(dev, "Sub Module = %s\n", + hisi_pcie_get_string(hisi_pcie_sub_module, + ARRAY_SIZE(hisi_pcie_sub_module), + edata->sub_module_id)); + if (edata->val_bits & HISI_PCIE_LOCAL_VALID_CORE_ID) + dev_info(dev, "Core ID = core%d\n", edata->core_id); + if (edata->val_bits & HISI_PCIE_LOCAL_VALID_PORT_ID) + dev_info(dev, "Port ID = port%d\n", edata->port_id); + if (edata->val_bits & HISI_PCIE_LOCAL_VALID_ERR_SEVERITY) + dev_info(dev, "Error severity = %s\n", + hisi_pcie_get_string(hisi_pcie_error_sev, + ARRAY_SIZE(hisi_pcie_error_sev), + edata->err_severity)); + if (edata->val_bits & HISI_PCIE_LOCAL_VALID_ERR_TYPE) + dev_info(dev, "Error type = 0x%x\n", edata->err_type); + + dev_info(dev, "Reg Dump:\n"); + idx = HISI_PCIE_LOCAL_VALID_ERR_MISC; + for_each_set_bit_from(idx, valid_bits, + HISI_PCIE_LOCAL_VALID_ERR_MISC + HISI_PCIE_ERR_MISC_REGS) + dev_info(dev, "ERR_MISC_%d = 0x%x\n", idx - HISI_PCIE_LOCAL_VALID_ERR_MISC, + edata->err_misc[idx - HISI_PCIE_LOCAL_VALID_ERR_MISC]); + + if (edata->err_severity != HISI_PCIE_ERR_SEV_RECOVERABLE) + return; + + /* Recovery for the PCIe controller errors, try reset + * PCI port for the error recovery + */ + rc = hisi_pcie_port_do_recovery(pdev, edata->socket_id, + HISI_PCIE_PORT_ID(edata->core_id, edata->port_id)); + if (rc) + dev_info(dev, "fail to do hisi pcie port reset\n"); +} + +static int hisi_pcie_notify_error(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct acpi_hest_generic_data *gdata = data; + const struct hisi_pcie_error_data *error_data = acpi_hest_get_payload(gdata); + struct hisi_pcie_error_private *priv; + struct device *dev; + struct platform_device *pdev; + guid_t err_sec_guid; + u8 socket; + + import_guid(&err_sec_guid, gdata->section_type); + if (!guid_equal(&err_sec_guid, &hisi_pcie_sec_guid)) + return NOTIFY_DONE; + + priv = container_of(nb, struct hisi_pcie_error_private, nb); + dev = priv->dev; + + if (device_property_read_u8(dev, "socket", &socket)) + return NOTIFY_DONE; + + if (error_data->socket_id != socket) + return NOTIFY_DONE; + + pdev = container_of(dev, struct platform_device, dev); + hisi_pcie_handle_error(pdev, error_data); + + return NOTIFY_OK; +} + +static int hisi_pcie_error_handler_probe(struct platform_device *pdev) +{ + struct hisi_pcie_error_private *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->nb.notifier_call = hisi_pcie_notify_error; + priv->dev = &pdev->dev; + ret = ghes_register_vendor_record_notifier(&priv->nb); + if (ret) { + dev_err(&pdev->dev, + "Failed to register hisi pcie controller error handler with apei\n"); + return ret; + } + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int hisi_pcie_error_handler_remove(struct platform_device *pdev) +{ + struct hisi_pcie_error_private *priv = platform_get_drvdata(pdev); + + ghes_unregister_vendor_record_notifier(&priv->nb); + + return 0; +} + +static const struct acpi_device_id hisi_pcie_acpi_match[] = { + { "HISI0361", 0 }, + { } +}; + +static struct platform_driver hisi_pcie_error_handler_driver = { + .driver = { + .name = "hisi-pcie-error-handler", + .acpi_match_table = hisi_pcie_acpi_match, + }, + .probe = hisi_pcie_error_handler_probe, + .remove = hisi_pcie_error_handler_remove, +}; +module_platform_driver(hisi_pcie_error_handler_driver); + +MODULE_DESCRIPTION("HiSilicon HIP PCIe controller error handling driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b927ad3405f96058014f97a610905b689cfbc563 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:21 -0400 Subject: PCI: brcmstb: PCIE_BRCMSTB depends on ARCH_BRCMSTB Have PCIE_BRCMSTB depend on ARCH_BRCMSTB. Also set the default value to ARCH_BRCMSTB. Link: https://lore.kernel.org/r/20200911175232.19016-2-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Florian Fainelli --- drivers/pci/controller/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index f18c3725ef80..624ab986ecb2 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -270,9 +270,10 @@ config VMD config PCIE_BRCMSTB tristate "Broadcom Brcmstb PCIe host controller" - depends on ARCH_BCM2835 || COMPILE_TEST + depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST depends on OF depends on PCI_MSI_IRQ_DOMAIN + default ARCH_BRCMSTB help Say Y here to enable PCIe host controller support for Broadcom STB based SoCs, like the Raspberry Pi 4. -- cgit v1.2.3 From 1cf1b0a6dd95250e30a7706c962044c51c5e06bd Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:23 -0400 Subject: PCI: brcmstb: Add bcm7278 register info Add in compatibility strings and code for three Broadcom STB chips. Some of the register locations, shifts, and masks are different for certain chips, requiring the use of different constants based on of_id. We would like to add the following at this time to the match list but we need to wait until the end of this patchset so that everything works. { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg }, { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg }, { .compatible = "brcm,bcm7216-pcie", .data = &bcm7278_cfg }, { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg }, Link: https://lore.kernel.org/r/20200911175232.19016-4-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Acked-by: Florian Fainelli Acked-by: Rob Herring --- drivers/pci/controller/pcie-brcmstb.c | 105 ++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 12 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 85fa7d54f11f..c2b3d2946a36 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -122,9 +122,8 @@ #define PCIE_EXT_SLOT_SHIFT 15 #define PCIE_EXT_FUNC_SHIFT 12 -#define PCIE_RGR1_SW_INIT_1 0x9210 #define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 -#define PCIE_RGR1_SW_INIT_1_INIT_MASK 0x2 +#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0 /* PCIe parameters */ #define BRCM_NUM_PCIE_OUT_WINS 0x4 @@ -154,6 +153,73 @@ #define SSC_STATUS_SSC_MASK 0x400 #define SSC_STATUS_PLL_LOCK_MASK 0x800 +#define IDX_ADDR(pcie) (pcie->reg_offsets[EXT_CFG_INDEX]) +#define DATA_ADDR(pcie) (pcie->reg_offsets[EXT_CFG_DATA]) +#define PCIE_RGR1_SW_INIT_1(pcie) (pcie->reg_offsets[RGR1_SW_INIT_1]) + +enum { + RGR1_SW_INIT_1, + EXT_CFG_INDEX, + EXT_CFG_DATA, +}; + +enum { + RGR1_SW_INIT_1_INIT_MASK, + RGR1_SW_INIT_1_INIT_SHIFT, +}; + +enum pcie_type { + GENERIC, + BCM7278, + BCM2711, +}; + +struct pcie_cfg_data { + const int *reg_field_info; + const int *offsets; + const enum pcie_type type; +}; + +static const int pcie_reg_field_info[] = { + [RGR1_SW_INIT_1_INIT_MASK] = 0x2, + [RGR1_SW_INIT_1_INIT_SHIFT] = 0x1, +}; + +static const int pcie_reg_field_info_bcm7278[] = { + [RGR1_SW_INIT_1_INIT_MASK] = 0x1, + [RGR1_SW_INIT_1_INIT_SHIFT] = 0x0, +}; + +static const int pcie_offsets[] = { + [RGR1_SW_INIT_1] = 0x9210, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x9004, +}; + +static const struct pcie_cfg_data generic_cfg = { + .reg_field_info = pcie_reg_field_info, + .offsets = pcie_offsets, + .type = GENERIC, +}; + +static const int pcie_offset_bcm7278[] = { + [RGR1_SW_INIT_1] = 0xc010, + [EXT_CFG_INDEX] = 0x9000, + [EXT_CFG_DATA] = 0x9004, +}; + +static const struct pcie_cfg_data bcm7278_cfg = { + .reg_field_info = pcie_reg_field_info_bcm7278, + .offsets = pcie_offset_bcm7278, + .type = BCM7278, +}; + +static const struct pcie_cfg_data bcm2711_cfg = { + .reg_field_info = pcie_reg_field_info, + .offsets = pcie_offsets, + .type = BCM2711, +}; + struct brcm_msi { struct device *dev; void __iomem *base; @@ -177,6 +243,9 @@ struct brcm_pcie { int gen; u64 msi_target_addr; struct brcm_msi *msi; + const int *reg_offsets; + const int *reg_field_info; + enum pcie_type type; }; /* @@ -603,20 +672,21 @@ static struct pci_ops brcm_pcie_ops = { static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) { - u32 tmp; + u32 tmp, mask = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_MASK]; + u32 shift = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_SHIFT]; - tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); - u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK); - writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); + tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); + tmp = (tmp & ~mask) | ((val << shift) & mask); + writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); } static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val) { u32 tmp; - tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); + tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK); - writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); + writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); } static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, @@ -927,11 +997,17 @@ static int brcm_pcie_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id brcm_pcie_match[] = { + { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg }, + {}, +}; + static int brcm_pcie_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node, *msi_np; struct pci_host_bridge *bridge; struct device_node *fw_np; + const struct pcie_cfg_data *data; struct brcm_pcie *pcie; int ret; @@ -953,9 +1029,18 @@ static int brcm_pcie_probe(struct platform_device *pdev) if (!bridge) return -ENOMEM; + data = of_device_get_match_data(&pdev->dev); + if (!data) { + pr_err("failed to look up compatible string\n"); + return -EINVAL; + } + pcie = pci_host_bridge_priv(bridge); pcie->dev = &pdev->dev; pcie->np = np; + pcie->reg_offsets = data->offsets; + pcie->reg_field_info = data->reg_field_info; + pcie->type = data->type; pcie->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pcie->base)) @@ -1000,10 +1085,6 @@ fail: return ret; } -static const struct of_device_id brcm_pcie_match[] = { - { .compatible = "brcm,bcm2711-pcie" }, - {}, -}; MODULE_DEVICE_TABLE(of, brcm_pcie_match); static struct platform_driver brcm_pcie_driver = { -- cgit v1.2.3 From 8195b7417018c24b793e2881e9e8bb1d50ace397 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:24 -0400 Subject: PCI: brcmstb: Add suspend and resume pm_ops Broadcom Set-top (BrcmSTB) boards typically support S2, S3, and S5 suspend and resume. Now the PCIe driver may do so as well. Link: https://lore.kernel.org/r/20200911175232.19016-5-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Florian Fainelli --- drivers/pci/controller/pcie-brcmstb.c | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index c2b3d2946a36..7f5e7848df47 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -978,6 +978,47 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie) brcm_pcie_bridge_sw_init_set(pcie, 1); } +static int brcm_pcie_suspend(struct device *dev) +{ + struct brcm_pcie *pcie = dev_get_drvdata(dev); + + brcm_pcie_turn_off(pcie); + clk_disable_unprepare(pcie->clk); + + return 0; +} + +static int brcm_pcie_resume(struct device *dev) +{ + struct brcm_pcie *pcie = dev_get_drvdata(dev); + void __iomem *base; + u32 tmp; + int ret; + + base = pcie->base; + clk_prepare_enable(pcie->clk); + + /* Take bridge out of reset so we can access the SERDES reg */ + brcm_pcie_bridge_sw_init_set(pcie, 0); + + /* SERDES_IDDQ = 0 */ + tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); + u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); + writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); + + /* wait for serdes to be stable */ + udelay(100); + + ret = brcm_pcie_setup(pcie); + if (ret) + return ret; + + if (pcie->msi) + brcm_msi_set_regs(pcie->msi); + + return 0; +} + static void __brcm_pcie_remove(struct brcm_pcie *pcie) { brcm_msi_remove(pcie); @@ -1087,12 +1128,18 @@ fail: MODULE_DEVICE_TABLE(of, brcm_pcie_match); +static const struct dev_pm_ops brcm_pcie_pm_ops = { + .suspend = brcm_pcie_suspend, + .resume = brcm_pcie_resume, +}; + static struct platform_driver brcm_pcie_driver = { .probe = brcm_pcie_probe, .remove = brcm_pcie_remove, .driver = { .name = "brcm-pcie", .of_match_table = brcm_pcie_match, + .pm = &brcm_pcie_pm_ops, }, }; module_platform_driver(brcm_pcie_driver); -- cgit v1.2.3 From 04356ac30771091f60e0a45d91bd8027d45c2427 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:25 -0400 Subject: PCI: brcmstb: Add bcm7278 PERST# support The PERST# bit was moved to a different register in 7278-type STB chips. In addition, the polarity of the bit was also changed; for other chips writing a 1 specified assert; for 7278-type chips, writing a 0 specifies assert. Of course, PERST# is a PCIe asserted-low signal. While we are here, also change the bridge_sw_init_set() functions so like the perst_set() functions they are chip specific and we no longer rely on data wrt chip specific field mask and shift values. Link: https://lore.kernel.org/r/20200911175232.19016-6-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Florian Fainelli --- drivers/pci/controller/pcie-brcmstb.c | 97 +++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 28 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 7f5e7848df47..947cf3115eb0 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -83,6 +83,7 @@ #define PCIE_MISC_PCIE_CTRL 0x4064 #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 +#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4 #define PCIE_MISC_PCIE_STATUS 0x4068 #define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80 @@ -125,6 +126,11 @@ #define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 #define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0 +#define RGR1_SW_INIT_1_INIT_GENERIC_MASK 0x2 +#define RGR1_SW_INIT_1_INIT_GENERIC_SHIFT 0x1 +#define RGR1_SW_INIT_1_INIT_7278_MASK 0x1 +#define RGR1_SW_INIT_1_INIT_7278_SHIFT 0x0 + /* PCIe parameters */ #define BRCM_NUM_PCIE_OUT_WINS 0x4 #define BRCM_INT_PCI_MSI_NR 32 @@ -157,6 +163,23 @@ #define DATA_ADDR(pcie) (pcie->reg_offsets[EXT_CFG_DATA]) #define PCIE_RGR1_SW_INIT_1(pcie) (pcie->reg_offsets[RGR1_SW_INIT_1]) +/* Rescal registers */ +#define PCIE_DVT_PMU_PCIE_PHY_CTRL 0xc700 +#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS 0x3 +#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_MASK 0x4 +#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_SHIFT 0x2 +#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_MASK 0x2 +#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT 0x1 +#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_MASK 0x1 +#define PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT 0x0 + +/* Forward declarations */ +struct brcm_pcie; +static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val); +static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val); +static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val); +static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val); + enum { RGR1_SW_INIT_1, EXT_CFG_INDEX, @@ -175,19 +198,10 @@ enum pcie_type { }; struct pcie_cfg_data { - const int *reg_field_info; const int *offsets; const enum pcie_type type; -}; - -static const int pcie_reg_field_info[] = { - [RGR1_SW_INIT_1_INIT_MASK] = 0x2, - [RGR1_SW_INIT_1_INIT_SHIFT] = 0x1, -}; - -static const int pcie_reg_field_info_bcm7278[] = { - [RGR1_SW_INIT_1_INIT_MASK] = 0x1, - [RGR1_SW_INIT_1_INIT_SHIFT] = 0x0, + void (*perst_set)(struct brcm_pcie *pcie, u32 val); + void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); }; static const int pcie_offsets[] = { @@ -197,9 +211,10 @@ static const int pcie_offsets[] = { }; static const struct pcie_cfg_data generic_cfg = { - .reg_field_info = pcie_reg_field_info, .offsets = pcie_offsets, .type = GENERIC, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, }; static const int pcie_offset_bcm7278[] = { @@ -209,15 +224,17 @@ static const int pcie_offset_bcm7278[] = { }; static const struct pcie_cfg_data bcm7278_cfg = { - .reg_field_info = pcie_reg_field_info_bcm7278, .offsets = pcie_offset_bcm7278, .type = BCM7278, + .perst_set = brcm_pcie_perst_set_7278, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278, }; static const struct pcie_cfg_data bcm2711_cfg = { - .reg_field_info = pcie_reg_field_info, .offsets = pcie_offsets, .type = BCM2711, + .perst_set = brcm_pcie_perst_set_generic, + .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, }; struct brcm_msi { @@ -244,8 +261,13 @@ struct brcm_pcie { u64 msi_target_addr; struct brcm_msi *msi; const int *reg_offsets; - const int *reg_field_info; enum pcie_type type; + struct reset_control *rescal; + int num_memc; + u64 memc_size[PCIE_BRCM_MAX_MEMC]; + u32 hw_rev; + void (*perst_set)(struct brcm_pcie *pcie, u32 val); + void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); }; /* @@ -670,17 +692,37 @@ static struct pci_ops brcm_pcie_ops = { .write = pci_generic_config_write, }; -static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) +static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val) { - u32 tmp, mask = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_MASK]; - u32 shift = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_SHIFT]; + u32 tmp, mask = RGR1_SW_INIT_1_INIT_GENERIC_MASK; + u32 shift = RGR1_SW_INIT_1_INIT_GENERIC_SHIFT; tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); tmp = (tmp & ~mask) | ((val << shift) & mask); writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); } -static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val) +static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val) +{ + u32 tmp, mask = RGR1_SW_INIT_1_INIT_7278_MASK; + u32 shift = RGR1_SW_INIT_1_INIT_7278_SHIFT; + + tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); + tmp = (tmp & ~mask) | ((val << shift) & mask); + writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); +} + +static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val) +{ + u32 tmp; + + /* Perst bit has moved and assert value is 0 */ + tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL); + u32p_replace_bits(&tmp, !val, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK); + writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); +} + +static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val) { u32 tmp; @@ -770,13 +812,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) u32 tmp, aspm_support; /* Reset the bridge */ - brcm_pcie_bridge_sw_init_set(pcie, 1); - brcm_pcie_perst_set(pcie, 1); - + pcie->bridge_sw_init_set(pcie, 1); usleep_range(100, 200); /* Take the bridge out of reset */ - brcm_pcie_bridge_sw_init_set(pcie, 0); + pcie->bridge_sw_init_set(pcie, 0); tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK; @@ -842,7 +882,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) brcm_pcie_set_gen(pcie, pcie->gen); /* Unassert the fundamental reset */ - brcm_pcie_perst_set(pcie, 0); + pcie->perst_set(pcie, 0); /* * Give the RC/EP time to wake up, before trying to configure RC. @@ -962,7 +1002,7 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie) if (brcm_pcie_link_up(pcie)) brcm_pcie_enter_l23(pcie); /* Assert fundamental reset */ - brcm_pcie_perst_set(pcie, 1); + pcie->perst_set(pcie, 1); /* Deassert request for L23 in case it was asserted */ tmp = readl(base + PCIE_MISC_PCIE_CTRL); @@ -975,7 +1015,7 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie) writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); /* Shutdown PCIe bridge */ - brcm_pcie_bridge_sw_init_set(pcie, 1); + pcie->bridge_sw_init_set(pcie, 1); } static int brcm_pcie_suspend(struct device *dev) @@ -999,7 +1039,7 @@ static int brcm_pcie_resume(struct device *dev) clk_prepare_enable(pcie->clk); /* Take bridge out of reset so we can access the SERDES reg */ - brcm_pcie_bridge_sw_init_set(pcie, 0); + pcie->bridge_sw_init_set(pcie, 0); /* SERDES_IDDQ = 0 */ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); @@ -1080,8 +1120,9 @@ static int brcm_pcie_probe(struct platform_device *pdev) pcie->dev = &pdev->dev; pcie->np = np; pcie->reg_offsets = data->offsets; - pcie->reg_field_info = data->reg_field_info; pcie->type = data->type; + pcie->perst_set = data->perst_set; + pcie->bridge_sw_init_set = data->bridge_sw_init_set; pcie->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pcie->base)) -- cgit v1.2.3 From 24ede430fa49d27ee4dd95ef6d234069fa034b9c Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Fri, 18 Sep 2020 16:00:13 +0800 Subject: PCI: designware-ep: Add multiple PFs support for DWC Add multiple PFs support for DWC, due to different PF have different config space, we use func_conf_select callback function to access the different PF's config space, the different chip company need to implement this callback function when use the DWC IP core and intend to support multiple PFs feature. Link: https://lore.kernel.org/r/20200918080024.13639-2-Zhiqiang.Hou@nxp.com Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-ep.c | 125 ++++++++++++++++-------- drivers/pci/controller/dwc/pcie-designware.c | 59 +++++++---- drivers/pci/controller/dwc/pcie-designware.h | 18 +++- 3 files changed, 143 insertions(+), 59 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 05415a82e9f4..500d4ca04947 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -30,12 +30,26 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); -static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar, - int flags) +static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) +{ + unsigned int func_offset = 0; + + if (ep->ops->func_conf_select) + func_offset = ep->ops->func_conf_select(ep, func_no); + + return func_offset; +} + +static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no, + enum pci_barno bar, int flags) { u32 reg; + unsigned int func_offset = 0; + struct dw_pcie_ep *ep = &pci->ep; + + func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = PCI_BASE_ADDRESS_0 + (4 * bar); + reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar); dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writel_dbi2(pci, reg, 0x0); dw_pcie_writel_dbi(pci, reg, 0x0); @@ -48,7 +62,12 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar, void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { - __dw_pcie_ep_reset_bar(pci, bar, 0); + u8 func_no, funcs; + + funcs = pci->ep.epc->max_functions; + + for (func_no = 0; func_no < funcs; func_no++) + __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); } static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, @@ -56,28 +75,31 @@ static int dw_pcie_ep_write_header(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); + unsigned int func_offset = 0; + + func_offset = dw_pcie_ep_func_select(ep, func_no); dw_pcie_dbi_ro_wr_en(pci); - dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid); - dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid); - dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid); - dw_pcie_writeb_dbi(pci, PCI_CLASS_PROG, hdr->progif_code); - dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, + dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid); + dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid); + dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid); + dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code); + dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE, hdr->subclass_code | hdr->baseclass_code << 8); - dw_pcie_writeb_dbi(pci, PCI_CACHE_LINE_SIZE, + dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE, hdr->cache_line_size); - dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_VENDOR_ID, + dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID, hdr->subsys_vendor_id); - dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id); - dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN, + dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_ID, hdr->subsys_id); + dw_pcie_writeb_dbi(pci, func_offset + PCI_INTERRUPT_PIN, hdr->interrupt_pin); dw_pcie_dbi_ro_wr_dis(pci); return 0; } -static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, - dma_addr_t cpu_addr, +static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, + enum pci_barno bar, dma_addr_t cpu_addr, enum dw_pcie_as_type as_type) { int ret; @@ -90,7 +112,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, return -EINVAL; } - ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr, + ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar, cpu_addr, as_type); if (ret < 0) { dev_err(pci->dev, "Failed to program IB window\n"); @@ -103,7 +125,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, return 0; } -static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr, +static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no, + phys_addr_t phys_addr, u64 pci_addr, size_t size) { u32 free_win; @@ -115,8 +138,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr, return -EINVAL; } - dw_pcie_prog_outbound_atu(pci, free_win, PCIE_ATU_TYPE_MEM, - phys_addr, pci_addr, size); + dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM, + phys_addr, pci_addr, size); set_bit(free_win, ep->ob_window_map); ep->outbound_addr[free_win] = phys_addr; @@ -132,7 +155,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, enum pci_barno bar = epf_bar->barno; u32 atu_index = ep->bar_to_atu[bar]; - __dw_pcie_ep_reset_bar(pci, bar, epf_bar->flags); + __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags); dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND); clear_bit(atu_index, ep->ib_window_map); @@ -149,14 +172,20 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, size_t size = epf_bar->size; int flags = epf_bar->flags; enum dw_pcie_as_type as_type; - u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar); + u32 reg; + unsigned int func_offset = 0; + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset; if (!(flags & PCI_BASE_ADDRESS_SPACE)) as_type = DW_PCIE_AS_MEM; else as_type = DW_PCIE_AS_IO; - ret = dw_pcie_ep_inbound_atu(ep, bar, epf_bar->phys_addr, as_type); + ret = dw_pcie_ep_inbound_atu(ep, func_no, bar, + epf_bar->phys_addr, as_type); if (ret) return ret; @@ -215,7 +244,7 @@ static int dw_pcie_ep_map_addr(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); - ret = dw_pcie_ep_outbound_atu(ep, addr, pci_addr, size); + ret = dw_pcie_ep_outbound_atu(ep, func_no, addr, pci_addr, size); if (ret) { dev_err(pci->dev, "Failed to enable address\n"); return ret; @@ -229,11 +258,14 @@ static int dw_pcie_ep_get_msi(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; + unsigned int func_offset = 0; if (!ep->msi_cap) return -EINVAL; - reg = ep->msi_cap + PCI_MSI_FLAGS; + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; val = dw_pcie_readw_dbi(pci, reg); if (!(val & PCI_MSI_FLAGS_ENABLE)) return -EINVAL; @@ -248,11 +280,14 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; + unsigned int func_offset = 0; if (!ep->msi_cap) return -EINVAL; - reg = ep->msi_cap + PCI_MSI_FLAGS; + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; val = dw_pcie_readw_dbi(pci, reg); val &= ~PCI_MSI_FLAGS_QMASK; val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK; @@ -268,11 +303,14 @@ 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; + unsigned int func_offset = 0; if (!ep->msix_cap) return -EINVAL; - reg = ep->msix_cap + PCI_MSIX_FLAGS; + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = ep->msix_cap + func_offset + PCI_MSIX_FLAGS; val = dw_pcie_readw_dbi(pci, reg); if (!(val & PCI_MSIX_FLAGS_ENABLE)) return -EINVAL; @@ -288,23 +326,26 @@ 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; + unsigned int func_offset = 0; if (!ep->msix_cap) return -EINVAL; dw_pcie_dbi_ro_wr_en(pci); - reg = ep->msix_cap + PCI_MSIX_FLAGS; + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = ep->msix_cap + func_offset + PCI_MSIX_FLAGS; val = dw_pcie_readw_dbi(pci, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; val |= interrupts; dw_pcie_writew_dbi(pci, reg, val); - reg = ep->msix_cap + PCI_MSIX_TABLE; + reg = ep->msix_cap + func_offset + PCI_MSIX_TABLE; val = offset | bir; dw_pcie_writel_dbi(pci, reg, val); - reg = ep->msix_cap + PCI_MSIX_PBA; + reg = ep->msix_cap + func_offset + PCI_MSIX_PBA; val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; dw_pcie_writel_dbi(pci, reg, val); @@ -389,6 +430,7 @@ 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; unsigned int aligned_offset; + unsigned int func_offset = 0; u16 msg_ctrl, msg_data; u32 msg_addr_lower, msg_addr_upper, reg; u64 msg_addr; @@ -398,20 +440,22 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, if (!ep->msi_cap) return -EINVAL; + func_offset = dw_pcie_ep_func_select(ep, func_no); + /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ - reg = ep->msi_cap + PCI_MSI_FLAGS; + reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; msg_ctrl = dw_pcie_readw_dbi(pci, reg); has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); - reg = ep->msi_cap + PCI_MSI_ADDRESS_LO; + reg = ep->msi_cap + func_offset + PCI_MSI_ADDRESS_LO; msg_addr_lower = dw_pcie_readl_dbi(pci, reg); if (has_upper) { - reg = ep->msi_cap + PCI_MSI_ADDRESS_HI; + reg = ep->msi_cap + func_offset + PCI_MSI_ADDRESS_HI; msg_addr_upper = dw_pcie_readl_dbi(pci, reg); - reg = ep->msi_cap + PCI_MSI_DATA_64; + reg = ep->msi_cap + func_offset + PCI_MSI_DATA_64; msg_data = dw_pcie_readw_dbi(pci, reg); } else { msg_addr_upper = 0; - reg = ep->msi_cap + PCI_MSI_DATA_32; + reg = ep->msi_cap + func_offset + PCI_MSI_DATA_32; msg_data = dw_pcie_readw_dbi(pci, reg); } aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1); @@ -430,11 +474,12 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, } int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, - u16 interrupt_num) + u16 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct pci_epf_msix_tbl *msix_tbl; struct pci_epc *epc = ep->epc; + unsigned int func_offset = 0; u32 reg, msg_data, vec_ctrl; unsigned int aligned_offset; u32 tbl_offset; @@ -442,7 +487,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, int ret; u8 bir; - reg = ep->msix_cap + PCI_MSIX_TABLE; + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = ep->msix_cap + func_offset + PCI_MSIX_TABLE; tbl_offset = dw_pcie_readl_dbi(pci, reg); bir = (tbl_offset & PCI_MSIX_TABLE_BIR); tbl_offset &= PCI_MSIX_TABLE_OFFSET; @@ -607,13 +654,13 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) 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; + if (ep->ops->ep_init) + ep->ops->ep_init(ep); + ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size, ep->page_size); if (ret < 0) { diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 3c3a4d1dbc0b..3fe859f3422d 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -224,9 +224,10 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, dw_pcie_writel_atu(pci, offset + reg, val); } -static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, - int type, u64 cpu_addr, - u64 pci_addr, u32 size) +static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, + int index, int type, + u64 cpu_addr, u64 pci_addr, + u32 size) { u32 retries, val; u64 limit_addr = cpu_addr + size - 1; @@ -244,7 +245,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, upper_32_bits(pci_addr)); dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, - type); + type | PCIE_ATU_FUNC_NUM(func_no)); dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_ENABLE); @@ -263,8 +264,9 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, dev_err(pci->dev, "Outbound iATU is not being enabled\n"); } -void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, - u64 cpu_addr, u64 pci_addr, u32 size) +static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, + int index, int type, u64 cpu_addr, + u64 pci_addr, u32 size) { u32 retries, val; @@ -272,8 +274,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); if (pci->iatu_unroll_enabled) { - dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr, - pci_addr, size); + dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type, + cpu_addr, pci_addr, size); return; } @@ -289,7 +291,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, lower_32_bits(pci_addr)); dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(pci_addr)); - dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | + PCIE_ATU_FUNC_NUM(func_no)); dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); /* @@ -306,6 +309,21 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, dev_err(pci->dev, "Outbound iATU is not being enabled\n"); } +void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, + u64 cpu_addr, u64 pci_addr, u32 size) +{ + __dw_pcie_prog_outbound_atu(pci, 0, index, type, + cpu_addr, pci_addr, size); +} + +void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, + int type, u64 cpu_addr, u64 pci_addr, + u32 size) +{ + __dw_pcie_prog_outbound_atu(pci, func_no, index, type, + cpu_addr, pci_addr, size); +} + static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg) { u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); @@ -321,8 +339,8 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg, dw_pcie_writel_atu(pci, offset + reg, val); } -static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, - int bar, u64 cpu_addr, +static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no, + int index, int bar, u64 cpu_addr, enum dw_pcie_as_type as_type) { int type; @@ -344,8 +362,10 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, return -EINVAL; } - dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type); + dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type | + PCIE_ATU_FUNC_NUM(func_no)); dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, + PCIE_ATU_FUNC_NUM_MATCH_EN | PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); @@ -366,14 +386,15 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, return -EBUSY; } -int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar, - u64 cpu_addr, enum dw_pcie_as_type as_type) +int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, + int bar, u64 cpu_addr, + enum dw_pcie_as_type as_type) { int type; u32 retries, val; if (pci->iatu_unroll_enabled) - return dw_pcie_prog_inbound_atu_unroll(pci, index, bar, + return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar, cpu_addr, as_type); dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | @@ -392,9 +413,11 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar, return -EINVAL; } - dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); - dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE - | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | + PCIE_ATU_FUNC_NUM(func_no)); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE | + PCIE_ATU_FUNC_NUM_MATCH_EN | + PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); /* * Make sure ATU enable takes effect before any subsequent config diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 8cbc902a311a..32102ebc5c37 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -88,9 +88,11 @@ #define PCIE_ATU_TYPE_IO 0x2 #define PCIE_ATU_TYPE_CFG0 0x4 #define PCIE_ATU_TYPE_CFG1 0x5 +#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20) #define PCIE_ATU_CR2 0x908 #define PCIE_ATU_ENABLE BIT(31) #define PCIE_ATU_BAR_MODE_ENABLE BIT(30) +#define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19) #define PCIE_ATU_LOWER_BASE 0x90C #define PCIE_ATU_UPPER_BASE 0x910 #define PCIE_ATU_LIMIT 0x914 @@ -206,6 +208,14 @@ struct dw_pcie_ep_ops { int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, enum pci_epc_irq_type type, u16 interrupt_num); const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep); + /* + * Provide a method to implement the different func config space + * access for different platform, if different func have different + * offset, return the offset of func. if use write a register way + * return a 0, and implement code in callback function of platform + * driver. + */ + unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no); }; struct dw_pcie_ep { @@ -277,8 +287,12 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci); void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, u64 cpu_addr, u64 pci_addr, u32 size); -int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar, - u64 cpu_addr, enum dw_pcie_as_type as_type); +void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, + int type, u64 cpu_addr, u64 pci_addr, + u32 size); +int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, + int bar, u64 cpu_addr, + enum dw_pcie_as_type as_type); void dw_pcie_disable_atu(struct dw_pcie *pci, int index, enum dw_pcie_region_type type); void dw_pcie_setup(struct dw_pcie *pci); -- cgit v1.2.3 From 2f7f7001d0e58f3f1c010c0ccdb049602c889b1d Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Fri, 18 Sep 2020 16:00:14 +0800 Subject: PCI: designware-ep: Add the doorbell mode of MSI-X in EP mode Add the doorbell mode of MSI-X in DWC EP driver. Link: https://lore.kernel.org/r/20200918080024.13639-3-Zhiqiang.Hou@nxp.com Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andrew Murray --- drivers/pci/controller/dwc/pcie-designware-ep.c | 19 +++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 12 ++++++++++++ 2 files changed, 31 insertions(+) (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 500d4ca04947..5ae87e8ffb85 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -473,6 +473,25 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct dw_pcie_ep_func *ep_func; + u32 msg_data; + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) + return -EINVAL; + + msg_data = (func_no << PCIE_MSIX_DOORBELL_PF_SHIFT) | + (interrupt_num - 1); + + dw_pcie_writel_dbi(pci, PCIE_MSIX_DOORBELL, msg_data); + + return 0; +} + int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, u16 interrupt_num) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 32102ebc5c37..4b75b798de98 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -105,6 +105,9 @@ #define PCIE_MISC_CONTROL_1_OFF 0x8BC #define PCIE_DBI_RO_WR_EN BIT(0) +#define PCIE_MSIX_DOORBELL 0x948 +#define PCIE_MSIX_DOORBELL_PF_SHIFT 24 + #define PCIE_PL_CHK_REG_CONTROL_STATUS 0xB20 #define PCIE_PL_CHK_REG_CHK_REG_START BIT(0) #define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS BIT(1) @@ -414,6 +417,8 @@ 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); +int dw_pcie_ep_raise_msix_irq_doorbell(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) @@ -455,6 +460,13 @@ static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +static inline int dw_pcie_ep_raise_msix_irq_doorbell(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 6bfc9c3a2c70a987e6432925769ec1376a12aed0 Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Fri, 18 Sep 2020 16:00:15 +0800 Subject: PCI: designware-ep: Move the function of getting MSI capability forward Move the function of getting MSI capability to the front of init function, because the init function of the EP platform driver will use the return value by the function of getting MSI capability. Link: https://lore.kernel.org/r/20200918080024.13639-4-Zhiqiang.Hou@nxp.com Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andrew Murray --- drivers/pci/controller/dwc/pcie-designware-ep.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 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 5ae87e8ffb85..25767a334259 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -582,10 +582,6 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) return -EIO; } - ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); - - ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX); - offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); dw_pcie_dbi_ro_wr_en(pci); @@ -677,6 +673,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ret < 0) epc->max_functions = 1; + ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); + + ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX); + if (ep->ops->ep_init) ep->ops->ep_init(ep); -- cgit v1.2.3 From 47a062609a30d820aa2fe62450f0212f7f26b223 Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Fri, 18 Sep 2020 16:00:16 +0800 Subject: PCI: designware-ep: Modify MSI and MSIX CAP way of finding Each PF of EP device should have its own MSI or MSIX capabitily struct, so create a dw_pcie_ep_func struct and move the msi_cap and msix_cap to this struct from dw_pcie_ep, and manage the PFs via a list. Link: https://lore.kernel.org/r/20200918080024.13639-5-Zhiqiang.Hou@nxp.com Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 121 ++++++++++++++++++++---- drivers/pci/controller/dwc/pcie-designware.h | 18 +++- 2 files changed, 118 insertions(+), 21 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 25767a334259..ad7da4ea43a5 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -30,6 +30,19 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); +struct dw_pcie_ep_func * +dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) +{ + struct dw_pcie_ep_func *ep_func; + + list_for_each_entry(ep_func, &ep->func_list, list) { + if (ep_func->func_no == func_no) + return ep_func; + } + + return NULL; +} + static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) { unsigned int func_offset = 0; @@ -70,6 +83,47 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); } +static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, + u8 cap_ptr, u8 cap) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + unsigned int func_offset = 0; + u8 cap_id, next_cap_ptr; + u16 reg; + + if (!cap_ptr) + return 0; + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr); + cap_id = (reg & 0x00ff); + + if (cap_id > PCI_CAP_ID_MAX) + return 0; + + if (cap_id == cap) + return cap_ptr; + + next_cap_ptr = (reg & 0xff00) >> 8; + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); +} + +static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + unsigned int func_offset = 0; + u8 next_cap_ptr; + u16 reg; + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST); + next_cap_ptr = (reg & 0x00ff); + + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); +} + static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, struct pci_epf_header *hdr) { @@ -259,13 +313,15 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; - if (!ep->msi_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msi_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; val = dw_pcie_readw_dbi(pci, reg); if (!(val & PCI_MSI_FLAGS_ENABLE)) return -EINVAL; @@ -281,13 +337,15 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; - if (!ep->msi_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msi_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; val = dw_pcie_readw_dbi(pci, reg); val &= ~PCI_MSI_FLAGS_QMASK; val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK; @@ -304,13 +362,15 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; - if (!ep->msix_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msix_cap + func_offset + PCI_MSIX_FLAGS; + reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS; val = dw_pcie_readw_dbi(pci, reg); if (!(val & PCI_MSIX_FLAGS_ENABLE)) return -EINVAL; @@ -327,25 +387,27 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts, struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; - if (!ep->msix_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) return -EINVAL; dw_pcie_dbi_ro_wr_en(pci); func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msix_cap + func_offset + PCI_MSIX_FLAGS; + reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS; val = dw_pcie_readw_dbi(pci, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; val |= interrupts; dw_pcie_writew_dbi(pci, reg, val); - reg = ep->msix_cap + func_offset + PCI_MSIX_TABLE; + reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE; val = offset | bir; dw_pcie_writel_dbi(pci, reg, val); - reg = ep->msix_cap + func_offset + PCI_MSIX_PBA; + reg = ep_func->msix_cap + func_offset + PCI_MSIX_PBA; val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; dw_pcie_writel_dbi(pci, reg, val); @@ -428,6 +490,7 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct dw_pcie_ep_func *ep_func; struct pci_epc *epc = ep->epc; unsigned int aligned_offset; unsigned int func_offset = 0; @@ -437,25 +500,26 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, bool has_upper; int ret; - if (!ep->msi_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msi_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; msg_ctrl = dw_pcie_readw_dbi(pci, reg); has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); - reg = ep->msi_cap + func_offset + PCI_MSI_ADDRESS_LO; + reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_LO; msg_addr_lower = dw_pcie_readl_dbi(pci, reg); if (has_upper) { - reg = ep->msi_cap + func_offset + PCI_MSI_ADDRESS_HI; + reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_HI; msg_addr_upper = dw_pcie_readl_dbi(pci, reg); - reg = ep->msi_cap + func_offset + PCI_MSI_DATA_64; + reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_64; msg_data = dw_pcie_readw_dbi(pci, reg); } else { msg_addr_upper = 0; - reg = ep->msi_cap + func_offset + PCI_MSI_DATA_32; + reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_32; msg_data = dw_pcie_readw_dbi(pci, reg); } aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1); @@ -496,6 +560,7 @@ 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 dw_pcie_ep_func *ep_func; struct pci_epf_msix_tbl *msix_tbl; struct pci_epc *epc = ep->epc; unsigned int func_offset = 0; @@ -506,9 +571,13 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, int ret; u8 bir; + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) + return -EINVAL; + func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msix_cap + func_offset + PCI_MSIX_TABLE; + reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE; tbl_offset = dw_pcie_readl_dbi(pci, reg); bir = (tbl_offset & PCI_MSIX_TABLE_BIR); tbl_offset &= PCI_MSIX_TABLE_OFFSET; @@ -606,11 +675,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) { int ret; void *addr; + u8 func_no; struct pci_epc *epc; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct device *dev = pci->dev; struct device_node *np = dev->of_node; const struct pci_epc_features *epc_features; + struct dw_pcie_ep_func *ep_func; + + INIT_LIST_HEAD(&ep->func_list); if (!pci->dbi_base || !pci->dbi_base2) { dev_err(dev, "dbi_base/dbi_base2 is not populated\n"); @@ -673,9 +746,19 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ret < 0) epc->max_functions = 1; - ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); + for (func_no = 0; func_no < epc->max_functions; func_no++) { + ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL); + if (!ep_func) + return -ENOMEM; + + ep_func->func_no = func_no; + ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no, + PCI_CAP_ID_MSI); + ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no, + PCI_CAP_ID_MSIX); - ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX); + list_add_tail(&ep_func->list, &ep->func_list); + } if (ep->ops->ep_init) ep->ops->ep_init(ep); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 4b75b798de98..97c7063b9e89 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -221,8 +221,16 @@ struct dw_pcie_ep_ops { unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no); }; +struct dw_pcie_ep_func { + struct list_head list; + u8 func_no; + u8 msi_cap; /* MSI capability offset */ + u8 msix_cap; /* MSI-X capability offset */ +}; + struct dw_pcie_ep { struct pci_epc *epc; + struct list_head func_list; const struct dw_pcie_ep_ops *ops; phys_addr_t phys_base; size_t addr_size; @@ -235,8 +243,6 @@ 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 pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; }; @@ -420,6 +426,8 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, int dw_pcie_ep_raise_msix_irq_doorbell(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); +struct dw_pcie_ep_func * +dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no); #else static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) { @@ -470,5 +478,11 @@ static inline int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { } + +static inline struct dw_pcie_ep_func * +dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) +{ + return NULL; +} #endif #endif /* _PCIE_DESIGNWARE_H */ -- cgit v1.2.3 From 20e458fb92af8175bfee35ef176c449b184de732 Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Fri, 18 Sep 2020 16:00:18 +0800 Subject: PCI: layerscape: Fix some format issue of the code Fix some format issue of the code in EP driver. Link: https://lore.kernel.org/r/20200918080024.13639-7-Zhiqiang.Hou@nxp.com Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andrew Murray --- drivers/pci/controller/dwc/pci-layerscape-ep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 0d151cead1b7..0691d9ad1356 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -63,7 +63,7 @@ static void ls_pcie_ep_init(struct dw_pcie_ep *ep) } static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, - enum pci_epc_irq_type type, u16 interrupt_num) + enum pci_epc_irq_type type, u16 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -87,7 +87,7 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = { }; static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, - struct platform_device *pdev) + struct platform_device *pdev) { struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; -- cgit v1.2.3 From cc255eb0bfbe86e388383971087f4f93b6191d1e Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Fri, 18 Sep 2020 16:00:19 +0800 Subject: PCI: layerscape: Modify the way of getting capability with different PEX The different PCIe controller in one board may be have different capability of MSI or MSIX, so change the way of getting the MSI capability, make it more flexible. Link: https://lore.kernel.org/r/20200918080024.13639-8-Zhiqiang.Hou@nxp.com Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/dwc/pci-layerscape-ep.c | 31 +++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 0691d9ad1356..9601f9c09cb1 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -22,6 +22,7 @@ struct ls_pcie_ep { struct dw_pcie *pci; + struct pci_epc_features *ls_epc; }; #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) @@ -40,26 +41,31 @@ static const struct of_device_id ls_pcie_ep_of_match[] = { { }, }; -static const struct pci_epc_features ls_pcie_epc_features = { - .linkup_notifier = false, - .msi_capable = true, - .msix_capable = false, - .bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), -}; - static const struct pci_epc_features* ls_pcie_ep_get_features(struct dw_pcie_ep *ep) { - return &ls_pcie_epc_features; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + + return pcie->ls_epc; } static void ls_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + struct dw_pcie_ep_func *ep_func; enum pci_barno bar; + ep_func = dw_pcie_ep_get_func_from_ep(ep, 0); + if (!ep_func) + return; + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) dw_pcie_ep_reset_bar(pci, bar); + + pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false; + pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false; } static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, @@ -119,6 +125,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dw_pcie *pci; struct ls_pcie_ep *pcie; + struct pci_epc_features *ls_epc; struct resource *dbi_base; int ret; @@ -130,6 +137,10 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) if (!pci) return -ENOMEM; + ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL); + if (!ls_epc) + return -ENOMEM; + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); if (IS_ERR(pci->dbi_base)) @@ -140,6 +151,10 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) pci->ops = &ls_pcie_ep_ops; pcie->pci = pci; + ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), + + pcie->ls_epc = ls_epc; + platform_set_drvdata(pdev, pcie); ret = ls_add_pcie_ep(pcie, pdev); -- cgit v1.2.3 From e64844b6da31011ba7369da2593f3c08dbdf511d Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Fri, 18 Sep 2020 16:00:20 +0800 Subject: PCI: layerscape: Modify the MSIX to the doorbell mode dw_pcie_ep_raise_msix_irq was never called in the exisitng driver before, because the ls1046a platform don't support the MSIX feature and msix_capable was always set to false. Now that add the ls1088a platform with MSIX support, use the doorbell method to support the MSIX feature. Link: https://lore.kernel.org/r/20200918080024.13639-9-Zhiqiang.Hou@nxp.com Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andrew Murray --- drivers/pci/controller/dwc/pci-layerscape-ep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 9601f9c09cb1..bfab1c694f00 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -79,7 +79,8 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 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); + return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no, + interrupt_num); default: dev_err(pci->dev, "UNKNOWN IRQ type\n"); return -EINVAL; -- cgit v1.2.3 From 1b6a0e43a1a128265d4a4edbf0ba3120fdf2297c Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Fri, 18 Sep 2020 16:00:21 +0800 Subject: PCI: layerscape: Add EP mode support for ls1088a and ls2088a Add PCIe EP mode support for ls1088a and ls2088a, there are some difference between LS1 and LS2 platform, so refactor the code of the EP driver. Link: https://lore.kernel.org/r/20200918080024.13639-10-Zhiqiang.Hou@nxp.com Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/dwc/pci-layerscape-ep.c | 72 +++++++++++++++++++------- 1 file changed, 53 insertions(+), 19 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index bfab1c694f00..84206f265e54 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -20,27 +20,29 @@ #define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/ -struct ls_pcie_ep { - struct dw_pcie *pci; - struct pci_epc_features *ls_epc; +#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) + +struct ls_pcie_ep_drvdata { + u32 func_offset; + const struct dw_pcie_ep_ops *ops; + const struct dw_pcie_ops *dw_pcie_ops; }; -#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) +struct ls_pcie_ep { + struct dw_pcie *pci; + struct pci_epc_features *ls_epc; + const struct ls_pcie_ep_drvdata *drvdata; +}; static int ls_pcie_establish_link(struct dw_pcie *pci) { return 0; } -static const struct dw_pcie_ops ls_pcie_ep_ops = { +static const struct dw_pcie_ops dw_ls_pcie_ep_ops = { .start_link = ls_pcie_establish_link, }; -static const struct of_device_id ls_pcie_ep_of_match[] = { - { .compatible = "fsl,ls-pcie-ep",}, - { }, -}; - static const struct pci_epc_features* ls_pcie_ep_get_features(struct dw_pcie_ep *ep) { @@ -87,10 +89,39 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } } -static const struct dw_pcie_ep_ops pcie_ep_ops = { +static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep, + u8 func_no) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + + WARN_ON(func_no && !pcie->drvdata->func_offset); + return pcie->drvdata->func_offset * func_no; +} + +static const struct dw_pcie_ep_ops ls_pcie_ep_ops = { .ep_init = ls_pcie_ep_init, .raise_irq = ls_pcie_ep_raise_irq, .get_features = ls_pcie_ep_get_features, + .func_conf_select = ls_pcie_ep_func_conf_select, +}; + +static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = { + .ops = &ls_pcie_ep_ops, + .dw_pcie_ops = &dw_ls_pcie_ep_ops, +}; + +static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = { + .func_offset = 0x20000, + .ops = &ls_pcie_ep_ops, + .dw_pcie_ops = &dw_ls_pcie_ep_ops, +}; + +static const struct of_device_id ls_pcie_ep_of_match[] = { + { .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata }, + { .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata }, + { .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata }, + { }, }; static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, @@ -103,7 +134,7 @@ static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, int ret; ep = &pci->ep; - ep->ops = &pcie_ep_ops; + ep->ops = pcie->drvdata->ops; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); if (!res) @@ -142,20 +173,23 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) if (!ls_epc) return -ENOMEM; - dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); + pcie->drvdata = of_device_get_match_data(dev); - pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET; pci->dev = dev; - pci->ops = &ls_pcie_ep_ops; - pcie->pci = pci; + pci->ops = pcie->drvdata->dw_pcie_ops; ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), + pcie->pci = pci; pcie->ls_epc = ls_epc; + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); + + pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET; + platform_set_drvdata(pdev, pcie); ret = ls_add_pcie_ep(pcie, pdev); -- cgit v1.2.3 From cd198909d680f93b0cb5553d4b560794e6eb8d4a Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Wed, 16 Sep 2020 10:50:25 +0800 Subject: PCI: tegra: Convert to use DEFINE_SEQ_ATTRIBUTE macro Use DEFINE_SEQ_ATTRIBUTE macro to simplify the code. Link: https://lore.kernel.org/r/20200916025025.3992783-1-liushixin2@huawei.com Signed-off-by: Liu Shixin Signed-off-by: Lorenzo Pieralisi Acked-by: Thierry Reding --- drivers/pci/controller/pci-tegra.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index e1a6f9db36f7..8fcabed7c6a6 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -2564,36 +2564,14 @@ static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v) return 0; } -static const struct seq_operations tegra_pcie_ports_seq_ops = { +static const struct seq_operations tegra_pcie_ports_sops = { .start = tegra_pcie_ports_seq_start, .next = tegra_pcie_ports_seq_next, .stop = tegra_pcie_ports_seq_stop, .show = tegra_pcie_ports_seq_show, }; -static int tegra_pcie_ports_open(struct inode *inode, struct file *file) -{ - struct tegra_pcie *pcie = inode->i_private; - struct seq_file *s; - int err; - - err = seq_open(file, &tegra_pcie_ports_seq_ops); - if (err) - return err; - - s = file->private_data; - s->private = pcie; - - return 0; -} - -static const struct file_operations tegra_pcie_ports_ops = { - .owner = THIS_MODULE, - .open = tegra_pcie_ports_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; +DEFINE_SEQ_ATTRIBUTE(tegra_pcie_ports); static void tegra_pcie_debugfs_exit(struct tegra_pcie *pcie) { @@ -2606,7 +2584,7 @@ static void tegra_pcie_debugfs_init(struct tegra_pcie *pcie) pcie->debugfs = debugfs_create_dir("pcie", NULL); debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, pcie, - &tegra_pcie_ports_ops); + &tegra_pcie_ports_fops); } static int tegra_pcie_probe(struct platform_device *pdev) -- cgit v1.2.3 From ce31ff786ddf3dbaa4c2212d2d51611701bc0103 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Tue, 22 Sep 2020 11:59:10 +0200 Subject: PCI: dwc: Fix 'cast truncates bits from constant value' Fixes warning given by executing "make C=2 drivers/pci/" Sparse output: CHECK drivers/pci/controller/dwc/pcie-designware.c drivers/pci/controller/dwc/pcie-designware.c:432:52: warning: cast truncates bits from constant value (ffffffff7fffffff becomes 7fffffff) Link: https://lore.kernel.org/r/7ea7f7d342f97c758949a17b870012f52ce5b3f5.1600767645.git.gustavo.pimentel@synopsys.com Reported-by: Bjorn Helgaas Signed-off-by: Gustavo Pimentel Signed-off-by: Lorenzo Pieralisi Cc: Joao Pinto --- drivers/pci/controller/dwc/pcie-designware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 3fe859f3422d..3c1f17c78241 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -452,7 +452,7 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, int index, } dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index); - dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, (u32)~PCIE_ATU_ENABLE); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE); } int dw_pcie_wait_for_link(struct dw_pcie *pci) -- cgit v1.2.3 From ecc3e424d190eb2408751d2100e97a48f69a222d Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Fri, 18 Sep 2020 14:38:00 +0200 Subject: PCI: kirin: Return -EPROBE_DEFER in case the gpio isn't ready PCI host bridge driver can be probed before the gpiochip it requires, so, of_get_named_gpio() can return -EPROBE_DEFER. Current code lets the kirin_pcie_probe() directly return -ENODEV, which results in the PCI host controller driver probe failure; with this error code the PCI host controller driver will not be probed again when the gpiochip driver is loaded. Fix the above issue by letting kirin_pcie_probe() return -EPROBE_DEFER in such a case. Link: https://lore.kernel.org/r/20200918123800.19983-1-huobean@gmail.com Signed-off-by: Bean Huo [lorenzo.pieralisi@arm.com: commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-kirin.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index e496f51e0152..74b88d158072 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -507,8 +507,12 @@ static int kirin_pcie_probe(struct platform_device *pdev) kirin_pcie->gpio_id_reset = of_get_named_gpio(dev->of_node, "reset-gpios", 0); - if (kirin_pcie->gpio_id_reset < 0) + if (kirin_pcie->gpio_id_reset == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (!gpio_is_valid(kirin_pcie->gpio_id_reset)) { + dev_err(dev, "unable to get a valid gpio pin\n"); return -ENODEV; + } ret = kirin_pcie_power_on(kirin_pcie); if (ret) -- cgit v1.2.3 From 915cff7f38c5e4d47f187f8049245afc2cb3e503 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Fri, 2 Oct 2020 01:51:58 -0700 Subject: PCI: hv: Fix hibernation in case interrupts are not re-created pci_restore_msi_state() directly writes the MSI/MSI-X related registers via MMIO. On a physical machine, this works perfectly; for a Linux VM running on a hypervisor, which typically enables IOMMU interrupt remapping, the hypervisor usually should trap and emulate the MMIO accesses in order to re-create the necessary interrupt remapping table entries in the IOMMU, otherwise the interrupts can not work in the VM after hibernation. Hyper-V is different from other hypervisors in that it does not trap and emulate the MMIO accesses, and instead it uses a para-virtualized method, which requires the VM to call hv_compose_msi_msg() to notify the hypervisor of the info that would be passed to the hypervisor in the case of the trap-and-emulate method. This is not an issue to a lot of PCI device drivers, which destroy and re-create the interrupts across hibernation, so hv_compose_msi_msg() is called automatically. However, some PCI device drivers (e.g. the in-tree GPU driver nouveau and the out-of-tree Nvidia proprietary GPU driver) do not destroy and re-create MSI/MSI-X interrupts across hibernation, so hv_pci_resume() has to call hv_compose_msi_msg(), otherwise the PCI device drivers can no longer receive interrupts after the VM resumes from hibernation. Hyper-V is also different in that chip->irq_unmask() may fail in a Linux VM running on Hyper-V (on a physical machine, chip->irq_unmask() can not fail because unmasking an MSI/MSI-X register just means an MMIO write): during hibernation, when a CPU is offlined, the kernel tries to move the interrupt to the remaining CPUs that haven't been offlined yet. In this case, hv_irq_unmask() -> hv_do_hypercall() always fails because the vmbus channel has been closed: here the early "return" in hv_irq_unmask() means the pci_msi_unmask_irq() is not called, i.e. the desc->masked remains "true", so later after hibernation, the MSI interrupt always remains masked, which is incorrect. Refer to cpu_disable_common() -> fixup_irqs() -> irq_migrate_all_off_this_cpu() -> migrate_one_irq(): static bool migrate_one_irq(struct irq_desc *desc) { ... if (maskchip && chip->irq_mask) chip->irq_mask(d); ... err = irq_do_set_affinity(d, affinity, false); ... if (maskchip && chip->irq_unmask) chip->irq_unmask(d); Fix the issue by calling pci_msi_unmask_irq() unconditionally in hv_irq_unmask(). Also suppress the error message for hibernation because the hypercall failure during hibernation does not matter (at this time all the devices have been frozen). Note: the correct affinity info is still updated into the irqdata data structure in migrate_one_irq() -> irq_do_set_affinity() -> hv_set_affinity(), so later when the VM resumes, hv_pci_restore_msi_state() is able to correctly restore the interrupt with the correct affinity. Link: https://lore.kernel.org/r/20201002085158.9168-1-decui@microsoft.com Fixes: ac82fc832708 ("PCI: hv: Add hibernation support") Signed-off-by: Dexuan Cui Signed-off-by: Lorenzo Pieralisi Reviewed-by: Jake Oshins --- drivers/pci/controller/pci-hyperv.c | 50 ++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index fc4c3a15e570..a9df492fbffa 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1276,11 +1276,25 @@ static void hv_irq_unmask(struct irq_data *data) exit_unlock: spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags); - if (res) { + /* + * During hibernation, when a CPU is offlined, the kernel tries + * to move the interrupt to the remaining CPUs that haven't + * been offlined yet. In this case, the below hv_do_hypercall() + * always fails since the vmbus channel has been closed: + * refer to cpu_disable_common() -> fixup_irqs() -> + * irq_migrate_all_off_this_cpu() -> migrate_one_irq(). + * + * Suppress the error message for hibernation because the failure + * during hibernation does not matter (at this time all the devices + * have been frozen). Note: the correct affinity info is still updated + * into the irqdata data structure in migrate_one_irq() -> + * irq_do_set_affinity() -> hv_set_affinity(), so later when the VM + * resumes, hv_pci_restore_msi_state() is able to correctly restore + * the interrupt with the correct affinity. + */ + if (res && hbus->state != hv_pcibus_removing) dev_err(&hbus->hdev->device, "%s() failed: %#llx", __func__, res); - return; - } pci_msi_unmask_irq(data); } @@ -3372,6 +3386,34 @@ static int hv_pci_suspend(struct hv_device *hdev) return 0; } +static int hv_pci_restore_msi_msg(struct pci_dev *pdev, void *arg) +{ + struct msi_desc *entry; + struct irq_data *irq_data; + + for_each_pci_msi_entry(entry, pdev) { + irq_data = irq_get_irq_data(entry->irq); + if (WARN_ON_ONCE(!irq_data)) + return -EINVAL; + + hv_compose_msi_msg(irq_data, &entry->msg); + } + + return 0; +} + +/* + * Upon resume, pci_restore_msi_state() -> ... -> __pci_write_msi_msg() + * directly writes the MSI/MSI-X registers via MMIO, but since Hyper-V + * doesn't trap and emulate the MMIO accesses, here hv_compose_msi_msg() + * must be used to ask Hyper-V to re-create the IOMMU Interrupt Remapping + * Table entries. + */ +static void hv_pci_restore_msi_state(struct hv_pcibus_device *hbus) +{ + pci_walk_bus(hbus->pci_bus, hv_pci_restore_msi_msg, NULL); +} + static int hv_pci_resume(struct hv_device *hdev) { struct hv_pcibus_device *hbus = hv_get_drvdata(hdev); @@ -3405,6 +3447,8 @@ static int hv_pci_resume(struct hv_device *hdev) prepopulate_bars(hbus); + hv_pci_restore_msi_state(hbus); + hbus->state = hv_pcibus_installed; return 0; out: -- cgit v1.2.3 From 740d6c3708a9325a9ae86aee61c666847be27b36 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:26 -0400 Subject: PCI: brcmstb: Add control of rescal reset Some STB chips have a special purpose reset controller named RESCAL (reset calibration). The PCIe HW can now control RESCAL to start and stop its operation. On probe(), the RESCAL is deasserted and the driver goes through the sequence of setting registers and reading status in order to start the internal PHY that is required for the PCIe. Link: https://lore.kernel.org/r/20200911175232.19016-7-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Florian Fainelli --- drivers/pci/controller/pcie-brcmstb.c | 79 ++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 947cf3115eb0..609c10ea5b63 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -994,6 +995,52 @@ static void brcm_pcie_enter_l23(struct brcm_pcie *pcie) dev_err(pcie->dev, "failed to enter low-power link state\n"); } +static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start) +{ + static const u32 shifts[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = { + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT, + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT, + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_SHIFT,}; + static const u32 masks[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = { + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_MASK, + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_MASK, + PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_MASK,}; + const int beg = start ? 0 : PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS - 1; + const int end = start ? PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS : -1; + u32 tmp, combined_mask = 0; + u32 val; + void __iomem *base = pcie->base; + int i, ret; + + for (i = beg; i != end; start ? i++ : i--) { + val = start ? BIT_MASK(shifts[i]) : 0; + tmp = readl(base + PCIE_DVT_PMU_PCIE_PHY_CTRL); + tmp = (tmp & ~masks[i]) | (val & masks[i]); + writel(tmp, base + PCIE_DVT_PMU_PCIE_PHY_CTRL); + usleep_range(50, 200); + combined_mask |= masks[i]; + } + + tmp = readl(base + PCIE_DVT_PMU_PCIE_PHY_CTRL); + val = start ? combined_mask : 0; + + ret = (tmp & combined_mask) == val ? 0 : -EIO; + if (ret) + dev_err(pcie->dev, "failed to %s phy\n", (start ? "start" : "stop")); + + return ret; +} + +static inline int brcm_phy_start(struct brcm_pcie *pcie) +{ + return pcie->rescal ? brcm_phy_cntl(pcie, 1) : 0; +} + +static inline int brcm_phy_stop(struct brcm_pcie *pcie) +{ + return pcie->rescal ? brcm_phy_cntl(pcie, 0) : 0; +} + static void brcm_pcie_turn_off(struct brcm_pcie *pcie) { void __iomem *base = pcie->base; @@ -1021,11 +1068,13 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie) static int brcm_pcie_suspend(struct device *dev) { struct brcm_pcie *pcie = dev_get_drvdata(dev); + int ret; brcm_pcie_turn_off(pcie); + ret = brcm_phy_stop(pcie); clk_disable_unprepare(pcie->clk); - return 0; + return ret; } static int brcm_pcie_resume(struct device *dev) @@ -1038,6 +1087,10 @@ static int brcm_pcie_resume(struct device *dev) base = pcie->base; clk_prepare_enable(pcie->clk); + ret = brcm_phy_start(pcie); + if (ret) + goto err; + /* Take bridge out of reset so we can access the SERDES reg */ pcie->bridge_sw_init_set(pcie, 0); @@ -1051,18 +1104,24 @@ static int brcm_pcie_resume(struct device *dev) ret = brcm_pcie_setup(pcie); if (ret) - return ret; + goto err; if (pcie->msi) brcm_msi_set_regs(pcie->msi); return 0; + +err: + clk_disable_unprepare(pcie->clk); + return ret; } static void __brcm_pcie_remove(struct brcm_pcie *pcie) { brcm_msi_remove(pcie); brcm_pcie_turn_off(pcie); + brcm_phy_stop(pcie); + reset_control_assert(pcie->rescal); clk_disable_unprepare(pcie->clk); } @@ -1142,6 +1201,22 @@ static int brcm_pcie_probe(struct platform_device *pdev) dev_err(&pdev->dev, "could not enable clock\n"); return ret; } + pcie->rescal = devm_reset_control_get_optional_shared(&pdev->dev, "rescal"); + if (IS_ERR(pcie->rescal)) { + clk_disable_unprepare(pcie->clk); + return PTR_ERR(pcie->rescal); + } + + ret = reset_control_deassert(pcie->rescal); + if (ret) + dev_err(&pdev->dev, "failed to deassert 'rescal'\n"); + + ret = brcm_phy_start(pcie); + if (ret) { + reset_control_assert(pcie->rescal); + clk_disable_unprepare(pcie->clk); + return ret; + } ret = brcm_pcie_setup(pcie); if (ret) -- cgit v1.2.3 From 52ded9e4f07b7b608344c5bbef59e31f7b39cb79 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:27 -0400 Subject: PCI: brcmstb: Set additional internal memory DMA viewport sizes The Raspberry Pi (RPI) is currently the only chip using this driver (pcie-brcmstb.c). There, only one memory controller is used, without an extension region, and the SCB0 viewport size is set to the size of the first and only dma-range region. Other BrcmSTB SOCs have more complicated memory configurations that require setting additional viewport sizes. BrcmSTB PCIe controllers are intimately connected to the memory controller(s) on the SOC. The SOC may have one to three memory controllers; they are indicated by the term SCBi. Each controller has a base region and an optional extension region. In physical memory, the base and extension regions of a controller are not adjacent, but in PCIe-space they are. There is a "viewport" for each memory controller that allows DMA from endpoint devices. Each viewport's size must be set to a power of two, and that size must be equal to or larger than the amount of memory each controller supports which is the sum of base region and its optional extension. Further, the 1-3 viewports are also adjacent in PCIe-space. Unfortunately the viewport sizes cannot be ascertained from the "dma-ranges" property so they have their own property, "brcm,scb-sizes". This is because dma-range information does not indicate what memory controller it is associated. For example, consider the following case where the size of one dma-range is 2GB and the second dma-range is 1GB: /* Case 1: SCB0 size set to 4GB */ dma-range0: 2GB (from memc0-base) dma-range1: 1GB (from memc0-extension) /* Case 2: SCB0 size set to 2GB, SCB1 size set to 1GB */ dma-range0: 2GB (from memc0-base) dma-range1: 1GB (from memc0-extension) By just looking at the dma-ranges information, one cannot tell which situation applies. That is why an additional property is needed. Its length indicates the number of memory controllers being used and each value indicates the viewport size. Note that the RPI DT does not have a "brcm,scb-sizes" property value, as it is assumed that it only requires one memory controller and no extension. So the optional use of "brcm,scb-sizes" will be backwards compatible. One last layer of complexity exists: all of the viewports sizes must be added and rounded up to a power of two to determine what the "BAR" size is. Further, an offset must be given that indicates the base PCIe address of this "BAR". The use of the term BAR is typically associated with endpoint devices, and the term is used here because the PCIe HW may be used as an RC or an EP. In the former case, all of the system memory appears in a single "BAR" region in PCIe memory. As it turns out, BrcmSTB PCIe HW is rarely used in the EP role and its system of mapping memory is an artifact that requires multiple dma-ranges regions. Link: https://lore.kernel.org/r/20200911175232.19016-8-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Florian Fainelli --- drivers/pci/controller/pcie-brcmstb.c | 67 +++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 18 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 609c10ea5b63..8a921fc9879f 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -57,6 +57,9 @@ #define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 #define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 0x0 #define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 +#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK 0x07c00000 +#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK 0x0000001f +#define SCB_SIZE_MASK(x) PCIE_MISC_MISC_CTRL_SCB ## x ## _SIZE_MASK #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c #define PCIE_MEM_WIN0_LO(win) \ @@ -159,6 +162,7 @@ #define SSC_STATUS_OFFSET 0x1 #define SSC_STATUS_SSC_MASK 0x400 #define SSC_STATUS_PLL_LOCK_MASK 0x800 +#define PCIE_BRCM_MAX_MEMC 3 #define IDX_ADDR(pcie) (pcie->reg_offsets[EXT_CFG_INDEX]) #define DATA_ADDR(pcie) (pcie->reg_offsets[EXT_CFG_DATA]) @@ -737,22 +741,44 @@ static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, u64 *rc_bar2_offset) { struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); - struct device *dev = pcie->dev; struct resource_entry *entry; + struct device *dev = pcie->dev; + u64 lowest_pcie_addr = ~(u64)0; + int ret, i = 0; + u64 size = 0; - entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM); - if (!entry) - return -ENODEV; + resource_list_for_each_entry(entry, &bridge->dma_ranges) { + u64 pcie_beg = entry->res->start - entry->offset; + size += entry->res->end - entry->res->start + 1; + if (pcie_beg < lowest_pcie_addr) + lowest_pcie_addr = pcie_beg; + } - /* - * The controller expects the inbound window offset to be calculated as - * the difference between PCIe's address space and CPU's. The offset - * provided by the firmware is calculated the opposite way, so we - * negate it. - */ - *rc_bar2_offset = -entry->offset; - *rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start); + if (lowest_pcie_addr == ~(u64)0) { + dev_err(dev, "DT node has no dma-ranges\n"); + return -EINVAL; + } + + ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1, + PCIE_BRCM_MAX_MEMC); + + if (ret <= 0) { + /* Make an educated guess */ + pcie->num_memc = 1; + pcie->memc_size[0] = 1ULL << fls64(size - 1); + } else { + pcie->num_memc = ret; + } + + /* Each memc is viewed through a "port" that is a power of 2 */ + for (i = 0, size = 0; i < pcie->num_memc; i++) + size += pcie->memc_size[i]; + + /* System memory starts at this address in PCIe-space */ + *rc_bar2_offset = lowest_pcie_addr; + /* The sum of all memc views must also be a power of 2 */ + *rc_bar2_size = 1ULL << fls64(size - 1); /* * We validate the inbound memory view even though we should trust @@ -804,12 +830,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) void __iomem *base = pcie->base; struct device *dev = pcie->dev; struct resource_entry *entry; - unsigned int scb_size_val; bool ssc_good = false; struct resource *res; int num_out_wins = 0; u16 nlw, cls, lnksta; - int i, ret; + int i, ret, memc; u32 tmp, aspm_support; /* Reset the bridge */ @@ -844,11 +869,17 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) writel(upper_32_bits(rc_bar2_offset), base + PCIE_MISC_RC_BAR2_CONFIG_HI); - scb_size_val = rc_bar2_size ? - ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */ tmp = readl(base + PCIE_MISC_MISC_CTRL); - u32p_replace_bits(&tmp, scb_size_val, - PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); + for (memc = 0; memc < pcie->num_memc; memc++) { + u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15; + + if (memc == 0) + u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(0)); + else if (memc == 1) + u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(1)); + else if (memc == 2) + u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2)); + } writel(tmp, base + PCIE_MISC_MISC_CTRL); /* -- cgit v1.2.3 From 3baec684a531866a39d9c20a0227aa272827a6ac Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:28 -0400 Subject: PCI: brcmstb: Accommodate MSI for older chips Older BrcmSTB chips do not have a separate register for MSI interrupts; the MSIs are in a register that also contains unrelated interrupts. In addition, the interrupts lie in bits [31..24] for these legacy chips. This commit provides common code for both legacy and non-legacy MSI interrupt registers. Link: https://lore.kernel.org/r/20200911175232.19016-9-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Florian Fainelli --- drivers/pci/controller/pcie-brcmstb.c | 70 ++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 21 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 8a921fc9879f..977b28289243 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -83,7 +83,8 @@ #define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 #define PCIE_MISC_MSI_DATA_CONFIG 0x404c -#define PCIE_MISC_MSI_DATA_CONFIG_VAL 0xffe06540 +#define PCIE_MISC_MSI_DATA_CONFIG_VAL_32 0xffe06540 +#define PCIE_MISC_MSI_DATA_CONFIG_VAL_8 0xfff86540 #define PCIE_MISC_PCIE_CTRL 0x4064 #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 @@ -95,6 +96,9 @@ #define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10 #define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40 +#define PCIE_MISC_REVISION 0x406c +#define BRCM_PCIE_HW_REV_33 0x0303 + #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0 @@ -115,10 +119,14 @@ #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 #define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 -#define PCIE_MSI_INTR2_STATUS 0x4500 -#define PCIE_MSI_INTR2_CLR 0x4508 -#define PCIE_MSI_INTR2_MASK_SET 0x4510 -#define PCIE_MSI_INTR2_MASK_CLR 0x4514 + +#define PCIE_INTR2_CPU_BASE 0x4300 +#define PCIE_MSI_INTR2_BASE 0x4500 +/* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */ +#define MSI_INT_STATUS 0x0 +#define MSI_INT_CLR 0x8 +#define MSI_INT_MASK_SET 0x10 +#define MSI_INT_MASK_CLR 0x14 #define PCIE_EXT_CFG_DATA 0x8000 @@ -138,6 +146,8 @@ /* PCIe parameters */ #define BRCM_NUM_PCIE_OUT_WINS 0x4 #define BRCM_INT_PCI_MSI_NR 32 +#define BRCM_INT_PCI_MSI_LEGACY_NR 8 +#define BRCM_INT_PCI_MSI_SHIFT 0 /* MSI target adresses */ #define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL @@ -253,6 +263,12 @@ struct brcm_msi { int irq; /* used indicates which MSI interrupts have been alloc'd */ unsigned long used; + bool legacy; + /* Some chips have MSIs in bits [31..24] of a shared register. */ + int legacy_shift; + int nr; /* No. of MSI available, depends on chip */ + /* This is the base pointer for interrupt status/set/clr regs */ + void __iomem *intr_base; }; /* Internal PCIe Host Controller Information.*/ @@ -463,8 +479,10 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc) msi = irq_desc_get_handler_data(desc); dev = msi->dev; - status = readl(msi->base + PCIE_MSI_INTR2_STATUS); - for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) { + status = readl(msi->intr_base + MSI_INT_STATUS); + status >>= msi->legacy_shift; + + for_each_set_bit(bit, &status, msi->nr) { virq = irq_find_mapping(msi->inner_domain, bit); if (virq) generic_handle_irq(virq); @@ -481,7 +499,7 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) msg->address_lo = lower_32_bits(msi->target_addr); msg->address_hi = upper_32_bits(msi->target_addr); - msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq; + msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq; } static int brcm_msi_set_affinity(struct irq_data *irq_data, @@ -493,8 +511,9 @@ static int brcm_msi_set_affinity(struct irq_data *irq_data, static void brcm_msi_ack_irq(struct irq_data *data) { struct brcm_msi *msi = irq_data_get_irq_chip_data(data); + const int shift_amt = data->hwirq + msi->legacy_shift; - writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR); + writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR); } @@ -510,7 +529,7 @@ static int brcm_msi_alloc(struct brcm_msi *msi) int hwirq; mutex_lock(&msi->lock); - hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0); + hwirq = bitmap_find_free_region(&msi->used, msi->nr, 0); mutex_unlock(&msi->lock); return hwirq; @@ -559,8 +578,7 @@ static int brcm_allocate_domains(struct brcm_msi *msi) struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np); struct device *dev = msi->dev; - msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR, - &msi_domain_ops, msi); + msi->inner_domain = irq_domain_add_linear(NULL, msi->nr, &msi_domain_ops, msi); if (!msi->inner_domain) { dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; @@ -597,7 +615,10 @@ static void brcm_msi_remove(struct brcm_pcie *pcie) static void brcm_msi_set_regs(struct brcm_msi *msi) { - writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR); + u32 val = __GENMASK(31, msi->legacy_shift); + + writel(val, msi->intr_base + MSI_INT_MASK_CLR); + writel(val, msi->intr_base + MSI_INT_CLR); /* * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI @@ -608,8 +629,8 @@ static void brcm_msi_set_regs(struct brcm_msi *msi) writel(upper_32_bits(msi->target_addr), msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI); - writel(PCIE_MISC_MSI_DATA_CONFIG_VAL, - msi->base + PCIE_MISC_MSI_DATA_CONFIG); + val = msi->legacy ? PCIE_MISC_MSI_DATA_CONFIG_VAL_8 : PCIE_MISC_MSI_DATA_CONFIG_VAL_32; + writel(val, msi->base + PCIE_MISC_MSI_DATA_CONFIG); } static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) @@ -634,6 +655,17 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) msi->np = pcie->np; msi->target_addr = pcie->msi_target_addr; msi->irq = irq; + msi->legacy = pcie->hw_rev < BRCM_PCIE_HW_REV_33; + + if (msi->legacy) { + msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE; + msi->nr = BRCM_INT_PCI_MSI_LEGACY_NR; + msi->legacy_shift = 24; + } else { + msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE; + msi->nr = BRCM_INT_PCI_MSI_NR; + msi->legacy_shift = 0; + } ret = brcm_allocate_domains(msi); if (ret) @@ -904,12 +936,6 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK; writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO); - /* Mask all interrupts since we are not handling any yet */ - writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET); - - /* clear any interrupts we find on boot */ - writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR); - if (pcie->gen) brcm_pcie_set_gen(pcie, pcie->gen); @@ -1253,6 +1279,8 @@ static int brcm_pcie_probe(struct platform_device *pdev) if (ret) goto fail; + pcie->hw_rev = readl(pcie->base + PCIE_MISC_REVISION); + msi_np = of_parse_phandle(pcie->np, "msi-parent", 0); if (pci_msi_enabled() && msi_np == pcie->np) { ret = brcm_pcie_enable_msi(pcie); -- cgit v1.2.3 From 20b1d6ba606c43d682a68dec45ccaf1d2316c1f5 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:29 -0400 Subject: PCI: brcmstb: Set bus max burst size by chip type The proper value of the parameter SCB_MAX_BURST_SIZE varies per chip. The 2711 family requires 128B whereas other devices can employ 512. The assignment is complicated by the fact that the values for this two-bit field have different meanings; Value Type_Generic Type_7278 00 Reserved 128B 01 128B 256B 10 256B 512B 11 512B Reserved Link: https://lore.kernel.org/r/20200911175232.19016-10-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Florian Fainelli --- drivers/pci/controller/pcie-brcmstb.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 977b28289243..3ccf67eebf4c 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -55,7 +55,7 @@ #define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 #define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 #define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 -#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 0x0 + #define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 #define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK 0x07c00000 #define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK 0x0000001f @@ -867,7 +867,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) int num_out_wins = 0; u16 nlw, cls, lnksta; int i, ret, memc; - u32 tmp, aspm_support; + u32 tmp, burst, aspm_support; /* Reset the bridge */ pcie->bridge_sw_init_set(pcie, 1); @@ -882,11 +882,22 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) /* Wait for SerDes to be stable */ usleep_range(100, 200); + /* + * SCB_MAX_BURST_SIZE is a two bit field. For GENERIC chips it + * is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it + * is encoded as 0=Rsvd, 1=128, 2=256, 3=512. + */ + if (pcie->type == BCM2711) + burst = 0x0; /* 128B */ + else if (pcie->type == BCM7278) + burst = 0x3; /* 512 bytes */ + else + burst = 0x2; /* 512 bytes */ + /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); - u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128, - PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); + u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); writel(tmp, base + PCIE_MISC_MISC_CTRL); ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, -- cgit v1.2.3 From 1f66d95efdb7220913bbecda2f0feb8be3bcddfd Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 11 Sep 2020 13:52:30 -0400 Subject: PCI: brcmstb: Add bcm7211, bcm7216, bcm7445, bcm7278 to match list Now that the support is in place with previous commits, we add several chips that use the BrcmSTB driver. Link: https://lore.kernel.org/r/20200911175232.19016-11-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Acked-by: Florian Fainelli Acked-by: Rob Herring --- drivers/pci/controller/pcie-brcmstb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 3ccf67eebf4c..afa7ba1d9a38 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -1207,6 +1207,10 @@ static int brcm_pcie_remove(struct platform_device *pdev) static const struct of_device_id brcm_pcie_match[] = { { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg }, + { .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg }, + { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg }, + { .compatible = "brcm,bcm7216-pcie", .data = &bcm7278_cfg }, + { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg }, {}, }; -- cgit v1.2.3 From 0c3c87d2b270a179f1149df5b84a7f7ad3474bdb Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Fri, 18 Sep 2020 11:08:29 +0800 Subject: PCI: iproc: Use module_bcma_driver to simplify the code module_bcma_driver() makes the code simpler by eliminating boilerplate code. Link: https://lore.kernel.org/r/20200918030829.3946025-1-liushixin2@huawei.com Signed-off-by: Liu Shixin Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Ray Jui --- drivers/pci/controller/pcie-iproc-bcma.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc-bcma.c b/drivers/pci/controller/pcie-iproc-bcma.c index aa55b064f64d..56b8ee7bf330 100644 --- a/drivers/pci/controller/pcie-iproc-bcma.c +++ b/drivers/pci/controller/pcie-iproc-bcma.c @@ -94,18 +94,7 @@ static struct bcma_driver iproc_pcie_bcma_driver = { .probe = iproc_pcie_bcma_probe, .remove = iproc_pcie_bcma_remove, }; - -static int __init iproc_pcie_bcma_init(void) -{ - return bcma_driver_register(&iproc_pcie_bcma_driver); -} -module_init(iproc_pcie_bcma_init); - -static void __exit iproc_pcie_bcma_exit(void) -{ - bcma_driver_unregister(&iproc_pcie_bcma_driver); -} -module_exit(iproc_pcie_bcma_exit); +module_bcma_driver(iproc_pcie_bcma_driver); MODULE_AUTHOR("Hauke Mehrtens"); MODULE_DESCRIPTION("Broadcom iProc PCIe BCMA driver"); -- cgit v1.2.3 From df7fc05561126f2d3299f02ad0639948ef94d739 Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Mon, 21 Sep 2020 16:24:47 +0800 Subject: PCI: mobiveil: Simplify mobiveil_pcie_init_irq_domain() return expression Simplify the return expression by removing useless code. Link: https://lore.kernel.org/r/20200921082447.2591877-1-liushixin2@huawei.com Signed-off-by: Liu Shixin Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/mobiveil/pcie-mobiveil-host.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c index 3adec419a45b..a2632d02ce8f 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c @@ -480,7 +480,6 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie) struct device *dev = &pcie->pdev->dev; struct device_node *node = dev->of_node; struct mobiveil_root_port *rp = &pcie->rp; - int ret; /* setup INTx */ rp->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX, @@ -494,11 +493,7 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie) raw_spin_lock_init(&rp->intx_mask_lock); /* setup MSI */ - ret = mobiveil_allocate_msi_domains(pcie); - if (ret) - return ret; - - return 0; + return mobiveil_allocate_msi_domains(pcie); } static int mobiveil_pcie_integrated_interrupt_init(struct mobiveil_pcie *pcie) -- cgit v1.2.3 From 9aae3af8767cdfbdcb2d59c008b9477e82ab1029 Mon Sep 17 00:00:00 2001 From: Qinglang Miao Date: Mon, 21 Sep 2020 21:10:53 +0800 Subject: PCI: cadence: Simplify cdns_pcie_host_init_address_translation() return expression Simplify the return expression. Link: https://lore.kernel.org/r/20200921131053.92752-1-miaoqinglang@huawei.com Signed-off-by: Qinglang Miao Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/cadence/pcie-cadence-host.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c index 4550e0d469ca..811c1cb2e8de 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-host.c +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c @@ -337,7 +337,7 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) struct resource_entry *entry; u64 cpu_addr = cfg_res->start; u32 addr0, addr1, desc1; - int r, err, busnr = 0; + int r, busnr = 0; entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS); if (entry) @@ -383,11 +383,7 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) r++; } - err = cdns_pcie_host_map_dma_ranges(rc); - if (err) - return err; - - return 0; + return cdns_pcie_host_map_dma_ranges(rc); } static int cdns_pcie_host_init(struct device *dev, -- cgit v1.2.3 From 9846155b00fe56273b3265f85bef8b39b15305eb Mon Sep 17 00:00:00 2001 From: Qinglang Miao Date: Mon, 21 Sep 2020 21:10:54 +0800 Subject: PCI: loongson: Simplify loongson_pci_probe() return expression Simplify the return expression. Link: https://lore.kernel.org/r/20200921131054.92797-1-miaoqinglang@huawei.com Signed-off-by: Qinglang Miao Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/pci-loongson.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c index 719c19fe2bfb..48169b1e3817 100644 --- a/drivers/pci/controller/pci-loongson.c +++ b/drivers/pci/controller/pci-loongson.c @@ -183,7 +183,6 @@ static int loongson_pci_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; struct pci_host_bridge *bridge; struct resource *regs; - int err; if (!node) return -ENODEV; @@ -222,11 +221,7 @@ static int loongson_pci_probe(struct platform_device *pdev) bridge->ops = &loongson_pci_ops; bridge->map_irq = loongson_map_irq; - err = pci_host_probe(bridge); - if (err) - return err; - - return 0; + return pci_host_probe(bridge); } static struct platform_driver loongson_pci_driver = { -- cgit v1.2.3 From 026b940f18bc531b2bf33a1f4ae47a2970597947 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Tue, 22 Sep 2020 03:02:57 +0000 Subject: PCI: xgene: Remove unused assignment to variable msi_val MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value assigned to msi_val after the inner loop finishes its run is never used for anything, and it is also immediately overridden in the line that follows with the return value from the xgene_msi_int_read() function. Since the value of msi_val following the inner loop completion is never used in any meaningful way the assignment can be removed. Addresses-Coverity-ID: 1437183 ("Unused value") Link: https://lore.kernel.org/r/20200922030257.459898-1-kw@linux.com Signed-off-by: Krzysztof Wilczyński Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Bjorn Helgaas --- drivers/pci/controller/pci-xgene-msi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-xgene-msi.c b/drivers/pci/controller/pci-xgene-msi.c index 02271c6d17a1..2470782cb01a 100644 --- a/drivers/pci/controller/pci-xgene-msi.c +++ b/drivers/pci/controller/pci-xgene-msi.c @@ -493,8 +493,8 @@ static int xgene_msi_probe(struct platform_device *pdev) */ for (irq_index = 0; irq_index < NR_HW_IRQS; irq_index++) { for (msi_idx = 0; msi_idx < IDX_PER_GROUP; msi_idx++) - msi_val = xgene_msi_ir_read(xgene_msi, irq_index, - msi_idx); + xgene_msi_ir_read(xgene_msi, irq_index, msi_idx); + /* Read MSIINTn to confirm */ msi_val = xgene_msi_int_read(xgene_msi, irq_index); if (msi_val) { -- cgit v1.2.3 From b0c6ae0f8948a2be6bf4e8b4bbab9ca1343289b6 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 2 Sep 2020 16:43:44 +0200 Subject: PCI: aardvark: Fix initialization with old Marvell's Arm Trusted Firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Old ATF automatically power on pcie phy and does not provide SMC call for phy power on functionality which leads to aardvark initialization failure: [ 0.330134] mvebu-a3700-comphy d0018300.phy: unsupported SMC call, try updating your firmware [ 0.338846] phy phy-d0018300.phy.1: phy poweron failed --> -95 [ 0.344753] advk-pcie d0070000.pcie: Failed to initialize PHY (-95) [ 0.351160] advk-pcie: probe of d0070000.pcie failed with error -95 This patch fixes above failure by ignoring 'not supported' error in aardvark driver. In this case it is expected that phy is already power on. Tested-by: Tomasz Maciej Nowak Link: https://lore.kernel.org/r/20200902144344.16684-3-pali@kernel.org Fixes: 366697018c9a ("PCI: aardvark: Add PHY support") Signed-off-by: Pali Rohár Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Cc: # 5.8+: ea17a0f153af: phy: marvell: comphy: Convert internal SMCC firmware return codes to errno --- drivers/pci/controller/pci-aardvark.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 50ab6d7519ae..0be485a25327 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -1081,7 +1081,9 @@ static int advk_pcie_enable_phy(struct advk_pcie *pcie) } ret = phy_power_on(pcie->phy); - if (ret) { + if (ret == -EOPNOTSUPP) { + dev_warn(&pcie->pdev->dev, "PHY unsupported by firmware\n"); + } else if (ret) { phy_exit(pcie->phy); return ret; } -- cgit v1.2.3 From a98d2187efd9e6d554efb50e3ed3a2983d340fe5 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 18 Sep 2020 11:12:51 -0700 Subject: PCI: meson: Build as module by default Enable pci-meson to build as a module whenever ARCH_MESON is enabled. Link: https://lore.kernel.org/r/20200918181251.32423-1-khilman@baylibre.com Signed-off-by: Kevin Hilman Signed-off-by: Lorenzo Pieralisi Reviewed-by: Neil Armstrong Cc: Yue Wang --- drivers/pci/controller/dwc/Kconfig | 3 ++- drivers/pci/controller/dwc/pci-meson.c | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 044a3761c44f..bc049865f8e0 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -237,8 +237,9 @@ config PCIE_HISI_STB Say Y here if you want PCIe controller support on HiSilicon STB SoCs config PCI_MESON - bool "MESON PCIe controller" + tristate "MESON PCIe controller" depends on PCI_MSI_IRQ_DOMAIN + default m if ARCH_MESON select PCIE_DW_HOST help Say Y here if you want to enable PCI controller support on Amlogic diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 4f183b96afbb..35b167e907aa 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "pcie-designware.h" @@ -589,6 +590,7 @@ static const struct of_device_id meson_pcie_of_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, meson_pcie_of_match); static struct platform_driver meson_pcie_driver = { .probe = meson_pcie_probe, @@ -598,4 +600,8 @@ static struct platform_driver meson_pcie_driver = { }, }; -builtin_platform_driver(meson_pcie_driver); +module_platform_driver(meson_pcie_driver); + +MODULE_AUTHOR("Yue Wang "); +MODULE_DESCRIPTION("Amlogic PCIe Controller driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 936452941cbec2b2f51cb6b7e5ac1d9b3081c6c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Tue, 22 Sep 2020 19:49:32 +0000 Subject: PCI: iproc: Fix using plain integer as NULL pointer in iproc_pcie_pltfm_probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix sparse build warning: drivers/pci/controller/pcie-iproc-platform.c:102:33: warning: Using plain integer as NULL pointer The map_irq member of the struct iproc_pcie takes a function pointer serving as a callback to map interrupts, therefore we should pass a NULL pointer to it rather than a integer in the iproc_pcie_pltfm_probe() function. Related: commit b64aa11eb2dd ("PCI: Set bridge map_irq and swizzle_irq to default functions") Link: https://lore.kernel.org/r/20200922194932.465925-1-kw@linux.com Signed-off-by: Krzysztof Wilczyński Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/pcie-iproc-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc-platform.c b/drivers/pci/controller/pcie-iproc-platform.c index a956b0c18bd1..b93e7bda101b 100644 --- a/drivers/pci/controller/pcie-iproc-platform.c +++ b/drivers/pci/controller/pcie-iproc-platform.c @@ -99,7 +99,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) switch (pcie->type) { case IPROC_PCIE_PAXC: case IPROC_PCIE_PAXC_V2: - pcie->map_irq = 0; + pcie->map_irq = NULL; break; default: break; -- cgit v1.2.3 From 13ab639ed48c1e777682d1a80097594d21a193dc Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 30 Sep 2020 14:36:06 +0900 Subject: PCI: dwc: Add common iATU register support This gets iATU register area from reg property that has reg-names "atu". In Synopsys DWC version 4.80 or later, since iATU register area is separated from core register area, this area is necessary to get from DT independently. Suggested-by: Rob Herring Link: https://lore.kernel.org/r/1601444167-11316-4-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Kunihiko Hayashi Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Cc: Murali Karicheri Cc: Jingoo Han Cc: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 3c1f17c78241..c2dea8fc97c8 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "../../pci.h" @@ -548,11 +549,15 @@ void dw_pcie_setup(struct dw_pcie *pci) u32 val; struct device *dev = pci->dev; struct device_node *np = dev->of_node; + struct platform_device *pdev = to_platform_device(dev); if (pci->version >= 0x480A || (!pci->version && dw_pcie_iatu_unroll_enabled(pci))) { pci->iatu_unroll_enabled = true; if (!pci->atu_base) + pci->atu_base = + devm_platform_ioremap_resource_byname(pdev, "atu"); + if (IS_ERR(pci->atu_base)) pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; } dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? -- cgit v1.2.3 From b101a39897d8369366e8a901666a32ee6db3974d Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 30 Sep 2020 14:36:07 +0900 Subject: PCI: keystone: Remove iATU register mapping After applying "PCI: dwc: Add common iATU register support", there is no need to set own iATU in the Keystone driver itself. Suggested-by: Rob Herring Link: https://lore.kernel.org/r/1601444167-11316-5-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Kunihiko Hayashi Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Cc: Murali Karicheri Cc: Jingoo Han Cc: Gustavo Pimentel --- drivers/pci/controller/dwc/pci-keystone.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index b554812dace7..a222728238ca 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1154,7 +1154,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct keystone_pcie *ks_pcie; struct device_link **link; struct gpio_desc *gpiod; - void __iomem *atu_base; struct resource *res; unsigned int version; void __iomem *base; @@ -1275,23 +1274,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - if (pci->version >= 0x480A) { - atu_base = devm_platform_ioremap_resource_byname(pdev, "atu"); - if (IS_ERR(atu_base)) { - ret = PTR_ERR(atu_base); - goto err_get_sync; - } - - pci->atu_base = atu_base; - + if (pci->version >= 0x480A) ret = ks_pcie_am654_set_mode(dev, mode); - if (ret < 0) - goto err_get_sync; - } else { + else ret = ks_pcie_set_mode(dev); - if (ret < 0) - goto err_get_sync; - } + if (ret < 0) + goto err_get_sync; switch (mode) { case DW_PCIE_RC_TYPE: -- cgit v1.2.3 From 742833249198bfd07944158eca50f740faf823f3 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 9 Oct 2020 15:54:36 +0800 Subject: PCI: dwc: Skip PCIE_MSI_INTR0* programming if MSI is disabled If MSI is disabled, there's no need to program PCIE_MSI_INTR0_MASK and PCIE_MSI_INTR0_ENABLE registers. Link: https://lore.kernel.org/r/20201009155436.27e67238@xhacker.debian Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 317ff512f8df..d3e9ea11ce9e 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -528,7 +528,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) dw_pcie_setup(pci); - if (!pp->ops->msi_host_init) { + if (pci_msi_enabled() && !pp->ops->msi_host_init) { num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; /* Initialize IRQ Status array */ -- cgit v1.2.3 From 07940c369a6bf940ec4a00eeb76bf51daa4f3973 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 9 Oct 2020 15:55:05 +0800 Subject: PCI: dwc: Fix MSI page leakage in suspend/resume Currently, dw_pcie_msi_init() allocates and maps page for msi, then program the PCIE_MSI_ADDR_LO and PCIE_MSI_ADDR_HI. The Root Complex may lose power during suspend-to-RAM, so when we resume, we want to redo the latter but not the former. If designware based driver (for example, pcie-tegra194.c) calls dw_pcie_msi_init() in resume path, the msi page will be leaked. As pointed out by Rob and Ard, there's no need to allocate a page for the MSI address, we could use an address in the driver data. To avoid map the MSI msg again during resume, we move the map MSI msg from dw_pcie_msi_init() to dw_pcie_host_init(). Suggested-by: Rob Herring Link: https://lore.kernel.org/r/20201009155505.5a580ef5@xhacker.debian Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/dwc/pci-dra7xx.c | 18 ++++++++++++- drivers/pci/controller/dwc/pcie-designware-host.c | 33 ++++++++++++----------- drivers/pci/controller/dwc/pcie-designware.h | 2 +- 3 files changed, 36 insertions(+), 17 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 8f0b6d644e4b..6d012d2b1e90 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -466,7 +466,9 @@ static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = { static int dra7xx_pcie_msi_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct device *dev = pci->dev; u32 ctrl, num_ctrls; + int ret; pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip; @@ -482,7 +484,21 @@ static int dra7xx_pcie_msi_host_init(struct pcie_port *pp) ~0); } - return dw_pcie_allocate_domains(pp); + ret = dw_pcie_allocate_domains(pp); + if (ret) + return ret; + + pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg, + sizeof(pp->msi_msg), + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + ret = dma_mapping_error(dev, pp->msi_data); + if (ret) { + dev_err(dev, "Failed to map MSI data\n"); + pp->msi_data = 0; + dw_pcie_free_msi(pp); + } + return ret; } static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = { diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index d3e9ea11ce9e..d02c7e74738d 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -266,30 +266,23 @@ void dw_pcie_free_msi(struct pcie_port *pp) irq_domain_remove(pp->msi_domain); irq_domain_remove(pp->irq_domain); - if (pp->msi_page) - __free_page(pp->msi_page); + if (pp->msi_data) { + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct device *dev = pci->dev; + + dma_unmap_single_attrs(dev, pp->msi_data, sizeof(pp->msi_msg), + DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + } } void dw_pcie_msi_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct device *dev = pci->dev; - u64 msi_target; + u64 msi_target = (u64)pp->msi_data; if (!IS_ENABLED(CONFIG_PCI_MSI)) return; - pp->msi_page = alloc_page(GFP_KERNEL); - pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE, - DMA_FROM_DEVICE); - if (dma_mapping_error(dev, pp->msi_data)) { - dev_err(dev, "Failed to map MSI data\n"); - __free_page(pp->msi_page); - pp->msi_page = NULL; - return; - } - msi_target = (u64)pp->msi_data; - /* Program the msi_data */ dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target)); dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target)); @@ -394,6 +387,16 @@ int dw_pcie_host_init(struct pcie_port *pp) irq_set_chained_handler_and_data(pp->msi_irq, dw_chained_msi_isr, pp); + + pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg, + sizeof(pp->msi_msg), + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(pci->dev, pp->msi_data)) { + dev_err(pci->dev, "Failed to map MSI data\n"); + pp->msi_data = 0; + goto err_free_msi; + } } else { ret = pp->ops->msi_host_init(pp); if (ret < 0) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 97c7063b9e89..9d2f511f13fa 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -190,8 +190,8 @@ struct pcie_port { int msi_irq; struct irq_domain *irq_domain; struct irq_domain *msi_domain; + u16 msi_msg; dma_addr_t msi_data; - struct page *msi_page; struct irq_chip *msi_irq_chip; u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; -- cgit v1.2.3 From 15b23906347c0af8778d1d4edeea415290342d35 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Wed, 16 Sep 2020 13:41:30 +0800 Subject: PCI: dwc: Add link up check in dw_child_pcie_ops.map_bus() NXP Layerscape (ls1028a, ls2088a), dra7xxx and imx6 platforms are either programmed or statically configured to forward the error triggered by a link-down state (eg no connected endpoint device) on the system bus for PCI configuration transactions; these errors are reported as an SError at system level, which is fatal. Enumerating a PCI tree when the PCIe link is down is not sensible either, so even if the link-up check is racy (link can go down after map_bus() is called) add a link-up check in map_bus() to prevent issuing configuration transactions when the link is down. SError report: SError Interrupt on CPU2, code 0xbf000002 -- SError CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.9.0-rc5-next-20200914-00001-gf965d3ec86fa #67 Hardware name: LS1046A RDB Board (DT) pstate: 20000085 (nzCv daIf -PAN -UAO BTYPE=--) pc : pci_generic_config_read+0x3c/0xe0 lr : pci_generic_config_read+0x24/0xe0 sp : ffff80001003b7b0 x29: ffff80001003b7b0 x28: ffff80001003ba74 x27: ffff000971d96800 x26: ffff00096e77e0a8 x25: ffff80001003b874 x24: ffff80001003b924 x23: 0000000000000004 x22: 0000000000000000 x21: 0000000000000000 x20: ffff80001003b874 x19: 0000000000000004 x18: ffffffffffffffff x17: 00000000000000c0 x16: fffffe0025981840 x15: ffffb94c75b69948 x14: 62203a383634203a x13: 666e6f635f726568 x12: 202c31203d207265 x11: 626d756e3e2d7375 x10: 656877202c307830 x9 : 203d206e66766564 x8 : 0000000000000908 x7 : 0000000000000908 x6 : ffff800010900000 x5 : ffff00096e77e080 x4 : 0000000000000000 x3 : 0000000000000003 x2 : 84fa3440ff7e7000 x1 : 0000000000000000 x0 : ffff800010034000 Kernel panic - not syncing: Asynchronous SError Interrupt CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.9.0-rc5-next-20200914-00001-gf965d3ec86fa #67 Hardware name: LS1046A RDB Board (DT) Call trace: dump_backtrace+0x0/0x1c0 show_stack+0x18/0x28 dump_stack+0xd8/0x134 panic+0x180/0x398 add_taint+0x0/0xb0 arm64_serror_panic+0x78/0x88 do_serror+0x68/0x180 el1_error+0x84/0x100 pci_generic_config_read+0x3c/0xe0 dw_pcie_rd_other_conf+0x78/0x110 pci_bus_read_config_dword+0x88/0xe8 pci_bus_generic_read_dev_vendor_id+0x30/0x1b0 pci_bus_read_dev_vendor_id+0x4c/0x78 pci_scan_single_device+0x80/0x100 Link: https://lore.kernel.org/r/20200916054130.8685-1-Zhiqiang.Hou@nxp.com Signed-off-by: Hou Zhiqiang [lorenzo.pieralisi@arm.com: rewrote the commit log, remove Fixes tag] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-host.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index d02c7e74738d..674f32db85ca 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -444,6 +444,17 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, struct pcie_port *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + /* + * Checking whether the link is up here is a last line of defense + * against platforms that forward errors on the system bus as + * SError upon PCI configuration transactions issued when the link + * is down. This check is racy by definition and does not stop + * the system from triggering an SError if the link goes down + * after this check is performed. + */ + if (!dw_pcie_link_up(pci)) + return NULL; + busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | PCIE_ATU_FUNC(PCI_FUNC(devfn)); -- cgit v1.2.3 From 58e0cd3e23ead3636525e5f47898c1dc92d7f12f Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Mon, 19 Oct 2020 12:02:49 -0700 Subject: PCI: v3-semi: Remove unneeded break A break is not needed if it is preceded by a return Link: https://lore.kernel.org/r/20201019190249.7825-1-trix@redhat.com Signed-off-by: Tom Rix Signed-off-by: Bjorn Helgaas Reviewed-by: Linus Walleij --- drivers/pci/controller/pci-v3-semi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-v3-semi.c b/drivers/pci/controller/pci-v3-semi.c index 1f54334f09f7..154a5398633c 100644 --- a/drivers/pci/controller/pci-v3-semi.c +++ b/drivers/pci/controller/pci-v3-semi.c @@ -658,7 +658,6 @@ static int v3_get_dma_range_config(struct v3_pci *v3, default: dev_err(v3->dev, "illegal dma memory chunk size\n"); return -EINVAL; - break; } val |= V3_PCI_MAP_M_REG_EN | V3_PCI_MAP_M_ENABLE; *pci_map = val; -- cgit v1.2.3 From 030109c0376c8f34e95f8b88d170a47900b3ad07 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 28 Jul 2020 13:49:40 -0600 Subject: PCI: vmd: Create physical offset helper Move the guest-passthrough physical offset discovery code to a new helper. No functional changes. Link: https://lore.kernel.org/r/20200728194945.14126-2-jonathan.derrick@intel.com Signed-off-by: Jon Derrick Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko --- drivers/pci/controller/vmd.c | 105 +++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 43 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index f69ef8c89f72..44b2db789eff 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -417,6 +417,60 @@ static int vmd_find_free_domain(void) return domain + 1; } +static int vmd_get_phys_offsets(struct vmd_dev *vmd, bool native_hint, + resource_size_t *offset1, + resource_size_t *offset2) +{ + struct pci_dev *dev = vmd->dev; + u64 phys1, phys2; + + if (native_hint) { + u32 vmlock; + int ret; + + ret = pci_read_config_dword(dev, PCI_REG_VMLOCK, &vmlock); + if (ret || vmlock == ~0) + return -ENODEV; + + if (MB2_SHADOW_EN(vmlock)) { + void __iomem *membar2; + + membar2 = pci_iomap(dev, VMD_MEMBAR2, 0); + if (!membar2) + return -ENOMEM; + phys1 = readq(membar2 + MB2_SHADOW_OFFSET); + phys2 = readq(membar2 + MB2_SHADOW_OFFSET + 8); + pci_iounmap(dev, membar2); + } else + return 0; + } else { + /* Hypervisor-Emulated Vendor-Specific Capability */ + int pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); + u32 reg, regu; + + pci_read_config_dword(dev, pos + 4, ®); + + /* "SHDW" */ + if (pos && reg == 0x53484457) { + pci_read_config_dword(dev, pos + 8, ®); + pci_read_config_dword(dev, pos + 12, ®u); + phys1 = (u64) regu << 32 | reg; + + pci_read_config_dword(dev, pos + 16, ®); + pci_read_config_dword(dev, pos + 20, ®u); + phys2 = (u64) regu << 32 | reg; + } else + return 0; + } + + *offset1 = dev->resource[VMD_MEMBAR1].start - + (phys1 & PCI_BASE_ADDRESS_MEM_MASK); + *offset2 = dev->resource[VMD_MEMBAR2].start - + (phys2 & PCI_BASE_ADDRESS_MEM_MASK); + + return 0; +} + static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) { struct pci_sysdata *sd = &vmd->sysdata; @@ -428,6 +482,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) resource_size_t offset[2] = {0}; resource_size_t membar2_offset = 0x2000; struct pci_bus *child; + int ret; /* * Shadow registers may exist in certain VMD device ids which allow @@ -436,50 +491,14 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) * or 0, depending on an enable bit in the VMD device. */ if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) { - u32 vmlock; - int ret; - membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE; - ret = pci_read_config_dword(vmd->dev, PCI_REG_VMLOCK, &vmlock); - if (ret || vmlock == ~0) - return -ENODEV; - - if (MB2_SHADOW_EN(vmlock)) { - void __iomem *membar2; - - membar2 = pci_iomap(vmd->dev, VMD_MEMBAR2, 0); - if (!membar2) - return -ENOMEM; - offset[0] = vmd->dev->resource[VMD_MEMBAR1].start - - (readq(membar2 + MB2_SHADOW_OFFSET) & - PCI_BASE_ADDRESS_MEM_MASK); - offset[1] = vmd->dev->resource[VMD_MEMBAR2].start - - (readq(membar2 + MB2_SHADOW_OFFSET + 8) & - PCI_BASE_ADDRESS_MEM_MASK); - pci_iounmap(vmd->dev, membar2); - } - } - - if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) { - int pos = pci_find_capability(vmd->dev, PCI_CAP_ID_VNDR); - u32 reg, regu; - - pci_read_config_dword(vmd->dev, pos + 4, ®); - - /* "SHDW" */ - if (pos && reg == 0x53484457) { - pci_read_config_dword(vmd->dev, pos + 8, ®); - pci_read_config_dword(vmd->dev, pos + 12, ®u); - offset[0] = vmd->dev->resource[VMD_MEMBAR1].start - - (((u64) regu << 32 | reg) & - PCI_BASE_ADDRESS_MEM_MASK); - - pci_read_config_dword(vmd->dev, pos + 16, ®); - pci_read_config_dword(vmd->dev, pos + 20, ®u); - offset[1] = vmd->dev->resource[VMD_MEMBAR2].start - - (((u64) regu << 32 | reg) & - PCI_BASE_ADDRESS_MEM_MASK); - } + ret = vmd_get_phys_offsets(vmd, true, &offset[0], &offset[1]); + if (ret) + return ret; + } else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) { + ret = vmd_get_phys_offsets(vmd, false, &offset[0], &offset[1]); + if (ret) + return ret; } /* -- cgit v1.2.3 From 2e1224183b1bec6610e01be80f007ee9ab0af9c0 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 28 Jul 2020 13:49:41 -0600 Subject: PCI: vmd: Create bus offset configuration helper Move the bus offset configuration discovery code to a new helper. Modify the bus offset 2-bit decode switch to have a 0 case and a default error case, just in case the field is expanded in future hardware. Link: https://lore.kernel.org/r/20200728194945.14126-3-jonathan.derrick@intel.com Signed-off-by: Jon Derrick Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko --- drivers/pci/controller/vmd.c | 53 ++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 44b2db789eff..a462719af12a 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -471,6 +471,35 @@ static int vmd_get_phys_offsets(struct vmd_dev *vmd, bool native_hint, return 0; } +static int vmd_get_bus_number_start(struct vmd_dev *vmd) +{ + struct pci_dev *dev = vmd->dev; + u16 reg; + + pci_read_config_word(dev, PCI_REG_VMCAP, ®); + if (BUS_RESTRICT_CAP(reg)) { + pci_read_config_word(dev, PCI_REG_VMCONFIG, ®); + + switch (BUS_RESTRICT_CFG(reg)) { + case 0: + vmd->busn_start = 0; + break; + case 1: + vmd->busn_start = 128; + break; + case 2: + vmd->busn_start = 224; + break; + default: + pci_err(dev, "Unknown Bus Offset Setting (%d)\n", + BUS_RESTRICT_CFG(reg)); + return -ENODEV; + } + } + + return 0; +} + static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) { struct pci_sysdata *sd = &vmd->sysdata; @@ -506,27 +535,9 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) * limits the bus range to between 0-127, 128-255, or 224-255 */ if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) { - u16 reg16; - - pci_read_config_word(vmd->dev, PCI_REG_VMCAP, ®16); - if (BUS_RESTRICT_CAP(reg16)) { - pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, - ®16); - - switch (BUS_RESTRICT_CFG(reg16)) { - case 1: - vmd->busn_start = 128; - break; - case 2: - vmd->busn_start = 224; - break; - case 3: - pci_err(vmd->dev, "Unknown Bus Offset Setting\n"); - return -ENODEV; - default: - break; - } - } + ret = vmd_get_bus_number_start(vmd); + if (ret) + return ret; } res = &vmd->dev->resource[VMD_CFGBAR]; -- cgit v1.2.3 From 1552b11ba15e93ee550c4672aa5acd8c1c5e8a82 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 28 Jul 2020 13:49:42 -0600 Subject: PCI: vmd: Create IRQ Domain configuration helper Move the IRQ and MSI Domain configuration code to new helpers. No functional changes. Link: https://lore.kernel.org/r/20200728194945.14126-4-jonathan.derrick@intel.com Signed-off-by: Jon Derrick Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko --- drivers/pci/controller/vmd.c | 52 +++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 17 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index a462719af12a..703c48171993 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -298,6 +298,34 @@ static struct msi_domain_info vmd_msi_domain_info = { .chip = &vmd_msi_controller, }; +static int vmd_create_irq_domain(struct vmd_dev *vmd) +{ + struct fwnode_handle *fn; + + fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain); + if (!fn) + return -ENODEV; + + vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, + x86_vector_domain); + if (!vmd->irq_domain) { + irq_domain_free_fwnode(fn); + return -ENODEV; + } + + return 0; +} + +static void vmd_remove_irq_domain(struct vmd_dev *vmd) +{ + if (vmd->irq_domain) { + struct fwnode_handle *fn = vmd->irq_domain->fwnode; + + irq_domain_remove(vmd->irq_domain); + irq_domain_free_fwnode(fn); + } +} + static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, unsigned int devfn, int reg, int len) { @@ -503,7 +531,6 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd) static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) { struct pci_sysdata *sd = &vmd->sysdata; - struct fwnode_handle *fn; struct resource *res; u32 upper_bits; unsigned long flags; @@ -598,16 +625,9 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) sd->node = pcibus_to_node(vmd->dev->bus); - fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain); - if (!fn) - return -ENODEV; - - vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, - x86_vector_domain); - if (!vmd->irq_domain) { - irq_domain_free_fwnode(fn); - return -ENODEV; - } + ret = vmd_create_irq_domain(vmd); + if (ret) + return ret; pci_add_resource(&resources, &vmd->resources[0]); pci_add_resource_offset(&resources, &vmd->resources[1], offset[0]); @@ -617,13 +637,13 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) &vmd_ops, sd, &resources); if (!vmd->bus) { pci_free_resource_list(&resources); - irq_domain_remove(vmd->irq_domain); - irq_domain_free_fwnode(fn); + vmd_remove_irq_domain(vmd); return -ENODEV; } vmd_attach_resources(vmd); - dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain); + if (vmd->irq_domain) + dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain); pci_scan_child_bus(vmd->bus); pci_assign_unassigned_bus_resources(vmd->bus); @@ -732,15 +752,13 @@ static void vmd_cleanup_srcu(struct vmd_dev *vmd) static void vmd_remove(struct pci_dev *dev) { struct vmd_dev *vmd = pci_get_drvdata(dev); - struct fwnode_handle *fn = vmd->irq_domain->fwnode; sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); pci_stop_root_bus(vmd->bus); pci_remove_root_bus(vmd->bus); vmd_cleanup_srcu(vmd); vmd_detach_resources(vmd); - irq_domain_remove(vmd->irq_domain); - irq_domain_free_fwnode(fn); + vmd_remove_irq_domain(vmd); } #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3 From 875b4e2a93bb2c3ddefb4dcb292c4bfd46ccc464 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 28 Jul 2020 13:49:43 -0600 Subject: PCI: vmd: Create IRQ allocation helper Move the IRQ allocation and SRCU initialization code to a new helper. No functional changes. Link: https://lore.kernel.org/r/20200728194945.14126-5-jonathan.derrick@intel.com Signed-off-by: Jon Derrick Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko --- drivers/pci/controller/vmd.c | 94 +++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 41 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 703c48171993..3214d785fa5d 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -528,6 +528,55 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd) return 0; } +static irqreturn_t vmd_irq(int irq, void *data) +{ + struct vmd_irq_list *irqs = data; + struct vmd_irq *vmdirq; + int idx; + + idx = srcu_read_lock(&irqs->srcu); + list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node) + generic_handle_irq(vmdirq->virq); + srcu_read_unlock(&irqs->srcu, idx); + + return IRQ_HANDLED; +} + +static int vmd_alloc_irqs(struct vmd_dev *vmd) +{ + struct pci_dev *dev = vmd->dev; + int i, err; + + vmd->msix_count = pci_msix_vec_count(dev); + if (vmd->msix_count < 0) + return -ENODEV; + + vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count, + PCI_IRQ_MSIX); + if (vmd->msix_count < 0) + return vmd->msix_count; + + vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs), + GFP_KERNEL); + if (!vmd->irqs) + return -ENOMEM; + + for (i = 0; i < vmd->msix_count; i++) { + err = init_srcu_struct(&vmd->irqs[i].srcu); + if (err) + return err; + + INIT_LIST_HEAD(&vmd->irqs[i].irq_list); + err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i), + vmd_irq, IRQF_NO_THREAD, + "vmd", &vmd->irqs[i]); + if (err) + return err; + } + + return 0; +} + static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) { struct pci_sysdata *sd = &vmd->sysdata; @@ -663,24 +712,10 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) return 0; } -static irqreturn_t vmd_irq(int irq, void *data) -{ - struct vmd_irq_list *irqs = data; - struct vmd_irq *vmdirq; - int idx; - - idx = srcu_read_lock(&irqs->srcu); - list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node) - generic_handle_irq(vmdirq->virq); - srcu_read_unlock(&irqs->srcu, idx); - - return IRQ_HANDLED; -} - static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct vmd_dev *vmd; - int i, err; + int err; if (resource_size(&dev->resource[VMD_CFGBAR]) < (1 << 20)) return -ENOMEM; @@ -703,32 +738,9 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32))) return -ENODEV; - vmd->msix_count = pci_msix_vec_count(dev); - if (vmd->msix_count < 0) - return -ENODEV; - - vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count, - PCI_IRQ_MSIX); - if (vmd->msix_count < 0) - return vmd->msix_count; - - vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs), - GFP_KERNEL); - if (!vmd->irqs) - return -ENOMEM; - - for (i = 0; i < vmd->msix_count; i++) { - err = init_srcu_struct(&vmd->irqs[i].srcu); - if (err) - return err; - - INIT_LIST_HEAD(&vmd->irqs[i].irq_list); - err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i), - vmd_irq, IRQF_NO_THREAD, - "vmd", &vmd->irqs[i]); - if (err) - return err; - } + err = vmd_alloc_irqs(vmd); + if (err) + return err; spin_lock_init(&vmd->cfg_lock); pci_set_drvdata(dev, vmd); -- cgit v1.2.3 From 93c9fce7d5f3db87f67718a2e5cf09b02c2c2c6a Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Thu, 6 Aug 2020 17:00:17 -0400 Subject: PCI: vmd: Update VMD PM to correctly use generic PCI PM The pci_save_state() call in vmd_suspend() can be performed by pci_pm_suspend_irq(). This also allows VMD to benefit from the call into pci_prepare_to_sleep(). The pci_restore_state() call in vmd_resume() was restoring state after pci_pm_resume()::pci_restore_standard_config() had already restored state. It's also been suspected that the config state should have been restored before re-requesting IRQs instead of afterwards. Remove the pci_save_state()/pci_restore_state() calls in vmd_suspend()/vmd_resume() to allow proper flow through generic PCI core Power Management code. Link: https://lore.kernel.org/r/20200806210017.5654-1-jonathan.derrick@intel.com Signed-off-by: Jon Derrick Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Cc: Kai-Heng Feng Cc: You-Sheng Yang --- drivers/pci/controller/vmd.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 3214d785fa5d..c8d46bd01e87 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -783,7 +783,6 @@ static int vmd_suspend(struct device *dev) for (i = 0; i < vmd->msix_count; i++) devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]); - pci_save_state(pdev); return 0; } @@ -801,7 +800,6 @@ static int vmd_resume(struct device *dev) return err; } - pci_restore_state(pdev); return 0; } #endif -- cgit v1.2.3