From 69b264df8a412820e98867dbab871c6526c5e5aa Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 10 Jul 2023 18:21:35 -0500 Subject: PCI/AER: Drop unused pci_disable_pcie_error_reporting() pci_disable_pcie_error_reporting() has no callers. Remove it. Link: https://lore.kernel.org/r/20230710232136.233034-2-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig Reviewed-by: Kuppuswamy Sathyanarayanan --- drivers/pci/pcie/aer.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index f6c24ded134c..d4c948b7c449 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -242,18 +242,6 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); -int pci_disable_pcie_error_reporting(struct pci_dev *dev) -{ - int rc; - - if (!pcie_aer_is_native(dev)) - return -EIO; - - rc = pcie_capability_clear_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS); - return pcibios_err_to_errno(rc); -} -EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); - int pci_aer_clear_nonfatal_status(struct pci_dev *dev) { int aer = dev->aer_cap; -- cgit v1.2.3 From 7ec4b34be4234599cf1241ef807cdb7c3636f6fe Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 10 Jul 2023 18:21:36 -0500 Subject: PCI/AER: Unexport pci_enable_pcie_error_reporting() pci_enable_pcie_error_reporting() is used only inside aer.c. Stop exposing it outside the file. Link: https://lore.kernel.org/r/20230710232136.233034-3-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig Reviewed-by: Kuppuswamy Sathyanarayanan --- drivers/pci/pcie/aer.c | 3 +-- include/linux/aer.h | 6 ------ 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index d4c948b7c449..645149608054 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -230,7 +230,7 @@ int pcie_aer_is_native(struct pci_dev *dev) return pcie_ports_native || host->native_aer; } -int pci_enable_pcie_error_reporting(struct pci_dev *dev) +static int pci_enable_pcie_error_reporting(struct pci_dev *dev) { int rc; @@ -240,7 +240,6 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev) rc = pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS); return pcibios_err_to_errno(rc); } -EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); int pci_aer_clear_nonfatal_status(struct pci_dev *dev) { diff --git a/include/linux/aer.h b/include/linux/aer.h index aadc9242cb20..2dd175f5debd 100644 --- a/include/linux/aer.h +++ b/include/linux/aer.h @@ -41,14 +41,8 @@ struct aer_capability_regs { }; #if defined(CONFIG_PCIEAER) -/* PCIe port driver needs this function to enable AER */ -int pci_enable_pcie_error_reporting(struct pci_dev *dev); int pci_aer_clear_nonfatal_status(struct pci_dev *dev); #else -static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev) -{ - return -EINVAL; -} static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev) { return -EINVAL; -- cgit v1.2.3 From d8650c0c2aa2e413594e4cb0faafa9958c1d7782 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Sat, 11 Mar 2023 14:34:53 +0100 Subject: PCI: apple: Initialize pcie->nvecs before use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The apple_pcie_setup_port() function computes ilog2(pcie->nvecs) to set up the number of MSIs available for each port. However, it's called before apple_msi_init(), which initializes pcie->nvecs. Luckily, pcie->nvecs is part of kzalloc()-ed structure and, as such, initialized as zero. ilog2(0) happens to be 0xffffffff which then simply configures more MSIs in hardware than we have. This doesn't break anything because we never hand out those vectors. Thus, swap the order of the two calls so that the correctly initialized value is then used. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230311133453.63246-1-sven@svenpeter.dev Fixes: 476c41ed4597 ("PCI: apple: Implement MSI support") Signed-off-by: Sven Peter Signed-off-by: Krzysztof Wilczyński Reviewed-by: Marc Zyngier Reviewed-by: Alyssa Rosenzweig Reviewed-by: Eric Curtin --- drivers/pci/controller/pcie-apple.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 66f37e403a09..2340dab6cd5b 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -783,6 +783,10 @@ static int apple_pcie_init(struct pci_config_window *cfg) cfg->priv = pcie; INIT_LIST_HEAD(&pcie->ports); + ret = apple_msi_init(pcie); + if (ret) + return ret; + for_each_child_of_node(dev->of_node, of_port) { ret = apple_pcie_setup_port(pcie, of_port); if (ret) { @@ -792,7 +796,7 @@ static int apple_pcie_init(struct pci_config_window *cfg) } } - return apple_msi_init(pcie); + return 0; } static int apple_pcie_probe(struct platform_device *pdev) -- cgit v1.2.3 From 8f1c517ccd378a41b8c4ac951b6793ad693dbfbc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 9 Jun 2023 13:33:25 -0600 Subject: PCI: iproc: Use of_property_read_bool() for boolean properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace low-level property access functions like of_get_property() and of_find_property() with their typed equivalents (i.e., of_property_read_ functions), as it's preferred to use typed property access functions for reading properties. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230609193326.1963542-1-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Krzysztof Wilczyński Reviewed-by: Florian Fainelli Acked-by: Ray Jui --- drivers/pci/controller/pcie-iproc-msi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c index fee036b07cd4..649fcb449f34 100644 --- a/drivers/pci/controller/pcie-iproc-msi.c +++ b/drivers/pci/controller/pcie-iproc-msi.c @@ -525,7 +525,7 @@ int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node) if (!of_device_is_compatible(node, "brcm,iproc-msi")) return -ENODEV; - if (!of_find_property(node, "msi-controller", NULL)) + if (!of_property_read_bool(node, "msi-controller")) return -ENODEV; if (pcie->msi) @@ -585,8 +585,7 @@ int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node) return -EINVAL; } - if (of_find_property(node, "brcm,pcie-msi-inten", NULL)) - msi->has_inten_reg = true; + msi->has_inten_reg = of_property_read_bool(node, "brcm,pcie-msi-inten"); msi->nr_msi_vecs = msi->nr_irqs * EQ_LEN; msi->bitmap = devm_bitmap_zalloc(pcie->dev, msi->nr_msi_vecs, -- cgit v1.2.3 From b9cbc06049cb6b7a322d708c2098195fb9fdcc4c Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 27 Jun 2023 19:40:36 +0530 Subject: PCI: qcom-ep: Switch MHI bus master clock off during L1SS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, as part of the qcom_pcie_perst_deassert() function, instead of writing the updated value to clear PARF_MSTR_AXI_CLK_EN, the variable "val" is re-read. This must be fixed to ensure that the master clock supplied to the MHI bus is correctly gated during L1.1/L1.2 to save power. Thus, replace the line that re-reads "val" with a line that writes the updated value to the register to clear PARF_MSTR_AXI_CLK_EN. [kwilczynski: commit log] Fixes: c457ac029e44 ("PCI: qcom-ep: Gate Master AXI clock to MHI bus during L1SS") Link: https://lore.kernel.org/linux-pci/20230627141036.11600-1-manivannan.sadhasivam@linaro.org Reported-by: Krzysztof Wilczyński Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 0fe7f06f2102..267e1247d548 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -415,7 +415,7 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) /* Gate Master AXI clock to MHI bus during L1SS */ val = readl_relaxed(pcie_ep->parf + PARF_MHI_CLOCK_RESET_CTRL); val &= ~PARF_MSTR_AXI_CLK_EN; - val = readl_relaxed(pcie_ep->parf + PARF_MHI_CLOCK_RESET_CTRL); + writel_relaxed(val, pcie_ep->parf + PARF_MHI_CLOCK_RESET_CTRL); dw_pcie_ep_init_notify(&pcie_ep->pci.ep); -- cgit v1.2.3 From da1e3277a8fe6bc0d368db7d3210e369566a47fb Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 23 Mar 2023 17:16:44 +0800 Subject: PCI: rcar-gen2: Use devm_platform_get_and_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert calls to platform_get_resource() and devm_ioremap_resource() into a single call to devm_platform_get_and_ioremap_resource(), to simplify the code. This new helper added in commit 890cc39a8799 ("drivers: provide devm_platform_get_and_ioremap_resource()") does what both of the other separate functions do. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230323091644.91981-1-yang.lee@linux.alibaba.com Signed-off-by: Yang Li Signed-off-by: Krzysztof Wilczyński Reviewed-by: Geert Uytterhoeven --- drivers/pci/controller/pci-rcar-gen2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pci-rcar-gen2.c b/drivers/pci/controller/pci-rcar-gen2.c index 839695791757..d29866485361 100644 --- a/drivers/pci/controller/pci-rcar-gen2.c +++ b/drivers/pci/controller/pci-rcar-gen2.c @@ -290,8 +290,7 @@ static int rcar_pci_probe(struct platform_device *pdev) priv = pci_host_bridge_priv(bridge); bridge->sysdata = priv; - cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(dev, cfg_res); + reg = devm_platform_get_and_ioremap_resource(pdev, 0, &cfg_res); if (IS_ERR(reg)) return PTR_ERR(reg); -- cgit v1.2.3 From 88f29abd249a1e2bd74206841963780f445226e9 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 23 Mar 2023 17:04:31 +0800 Subject: PCI: v3: Use devm_platform_get_and_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert calls to platform_get_resource() and devm_ioremap_resource() into a single call to devm_platform_get_and_ioremap_resource(), to simplify the code. This new helper added in commit 890cc39a8799 ("drivers: provide devm_platform_get_and_ioremap_resource()") does what both of the other separate functions do. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230323090431.73526-1-yang.lee@linux.alibaba.com Signed-off-by: Yang Li Signed-off-by: Krzysztof Wilczyński Acked-by: Linus Walleij --- drivers/pci/controller/pci-v3-semi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pci-v3-semi.c b/drivers/pci/controller/pci-v3-semi.c index ca44b0c83d1b..a8b49f841534 100644 --- a/drivers/pci/controller/pci-v3-semi.c +++ b/drivers/pci/controller/pci-v3-semi.c @@ -736,8 +736,7 @@ static int v3_pci_probe(struct platform_device *pdev) return ret; } - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - v3->base = devm_ioremap_resource(dev, regs); + v3->base = devm_platform_get_and_ioremap_resource(pdev, 0, ®s); if (IS_ERR(v3->base)) return PTR_ERR(v3->base); /* -- cgit v1.2.3 From b1042a7caa02e4e52cd4ccf1c04c07e635fe7dd6 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 23 Mar 2023 17:00:11 +0800 Subject: PCI: xgene-msi: Use devm_platform_get_and_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert calls to platform_get_resource() and devm_ioremap_resource() into a single call to devm_platform_get_and_ioremap_resource(), to simplify the code. This new helper added in commit 890cc39a8799 ("drivers: provide devm_platform_get_and_ioremap_resource()") does what both of the other separate functions do. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230323090011.66754-1-yang.lee@linux.alibaba.com Signed-off-by: Yang Li Signed-off-by: Krzysztof Wilczyński --- drivers/pci/controller/pci-xgene-msi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pci-xgene-msi.c b/drivers/pci/controller/pci-xgene-msi.c index 0234e528b9a5..3ce38dfd0d29 100644 --- a/drivers/pci/controller/pci-xgene-msi.c +++ b/drivers/pci/controller/pci-xgene-msi.c @@ -441,8 +441,7 @@ static int xgene_msi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, xgene_msi); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - xgene_msi->msi_regs = devm_ioremap_resource(&pdev->dev, res); + xgene_msi->msi_regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(xgene_msi->msi_regs)) { rc = PTR_ERR(xgene_msi->msi_regs); goto error; -- cgit v1.2.3 From 188f46cac267b9b8f3201ed21d719a51946e1e34 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 23 Mar 2023 15:45:53 +0800 Subject: PCI: imx6: Use devm_platform_get_and_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert calls to platform_get_resource() and devm_ioremap_resource() into a single call to devm_platform_get_and_ioremap_resource(), to simplify the code. This new helper added in commit 890cc39a8799 ("drivers: provide devm_platform_get_and_ioremap_resource()") does what both of the other separate functions do. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230323074553.90372-1-yang.lee@linux.alibaba.com Signed-off-by: Yang Li Signed-off-by: Krzysztof Wilczyński Reviewed-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 27aaa2a6bf39..6bf7ad2f7b48 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1282,8 +1282,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) return PTR_ERR(imx6_pcie->phy_base); } - dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pci->dbi_base = devm_ioremap_resource(dev, dbi_base); + pci->dbi_base = devm_platform_get_and_ioremap_resource(pdev, 0, &dbi_base); if (IS_ERR(pci->dbi_base)) return PTR_ERR(pci->dbi_base); -- cgit v1.2.3 From 1a8bf351ccde7527ca0427151b5fe43f64fa1eac Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Thu, 29 Jun 2023 16:59:54 +0000 Subject: PCI: meson: Remove cast between incompatible function type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than casting void(*)(struct clk *) to void (*)(void *), that forces conversion to an incompatible function type, replace the cast with a small local stub function with a signature that matches what the devm_add_action_or_reset() function expects. The sub function takes a void *, then passes it directly to clk_disable_unprepare(), which handles the more specific type. Reported by clang when building with warnings enabled: drivers/pci/controller/dwc/pci-meson.c:191:6: warning: cast from 'void (*)(struct clk *)' to 'void (*)(void *)' converts to incompatible function type [-Wcast-function-type-strict] (void (*) (void *))clk_disable_unprepare, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ No functional changes are intended. Fixes: 9c0ef6d34fdb ("PCI: amlogic: Add the Amlogic Meson PCIe controller driver") Link: https://lore.kernel.org/linux-pci/20230629165956.237832-1-kwilczynski@kernel.org Reviewed-by: Neil Armstrong Signed-off-by: Krzysztof Wilczyński --- drivers/pci/controller/dwc/pci-meson.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index c1527693bed9..34990a6363d0 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -163,6 +163,13 @@ static int meson_pcie_reset(struct meson_pcie *mp) return 0; } +static inline void meson_pcie_disable_clock(void *data) +{ + struct clk *clk = data; + + clk_disable_unprepare(clk); +} + static inline struct clk *meson_pcie_probe_clock(struct device *dev, const char *id, u64 rate) { @@ -187,9 +194,7 @@ static inline struct clk *meson_pcie_probe_clock(struct device *dev, return ERR_PTR(ret); } - devm_add_action_or_reset(dev, - (void (*) (void *))clk_disable_unprepare, - clk); + devm_add_action_or_reset(dev, meson_pcie_disable_clock, clk); return clk; } -- cgit v1.2.3 From 7a6531696668f1c9251f6b7219c02519f652be3d Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Thu, 29 Jun 2023 16:59:55 +0000 Subject: PCI: keembay: Remove cast between incompatible function type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than casting void(*)(struct clk *) to void (*)(void *), that forces conversion to an incompatible function type, replace the cast with a small local stub function with a signature that matches what the devm_add_action_or_reset() function expects. The sub function takes a void *, then passes it directly to clk_disable_unprepare(), which handles the more specific type. Reported by clang when building with warnings enabled: drivers/pci/controller/dwc/pcie-keembay.c:172:12: warning: cast from 'void (*)(struct clk *)' to 'void (*)(void *)' converts to incompatible function type [-Wcast-function-type-strict] (void(*)(void *))clk_disable_unprepare, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ No functional changes are intended. Fixes: 0c87f90b4c13 ("PCI: keembay: Add support for Intel Keem Bay") Link: https://lore.kernel.org/linux-pci/20230629165956.237832-2-kwilczynski@kernel.org Acked-by: Srikanth Thokala Signed-off-by: Krzysztof Wilczyński --- drivers/pci/controller/dwc/pcie-keembay.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c index f90f36bac018..289bff99d762 100644 --- a/drivers/pci/controller/dwc/pcie-keembay.c +++ b/drivers/pci/controller/dwc/pcie-keembay.c @@ -148,6 +148,13 @@ static const struct dw_pcie_ops keembay_pcie_ops = { .stop_link = keembay_pcie_stop_link, }; +static inline void keembay_pcie_disable_clock(void *data) +{ + struct clk *clk = data; + + clk_disable_unprepare(clk); +} + static inline struct clk *keembay_pcie_probe_clock(struct device *dev, const char *id, u64 rate) { @@ -168,9 +175,7 @@ static inline struct clk *keembay_pcie_probe_clock(struct device *dev, if (ret) return ERR_PTR(ret); - ret = devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - clk); + ret = devm_add_action_or_reset(dev, keembay_pcie_disable_clock, clk); if (ret) return ERR_PTR(ret); -- cgit v1.2.3 From ed3cac7c5ac6e7f284100995b80a0a60770c990c Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Thu, 29 Jun 2023 16:59:56 +0000 Subject: PCI: microchip: Remove cast between incompatible function type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than casting void(*)(struct clk *) to void (*)(void *), that forces conversion to an incompatible function type, replace the cast with a small local stub function with a signature that matches what the devm_add_action_or_reset() function expects. The sub function takes a void *, then passes it directly to clk_disable_unprepare(), which handles the more specific type. Reported by clang when building with warnings enabled: drivers/pci/controller/pcie-microchip-host.c:866:32: warning: cast from 'void (*)(struct clk *)' to 'void (*)(void *)' converts to incompatible function type [-Wcast-function-type-strict] devm_add_action_or_reset(dev, (void (*) (void *))clk_disable_unprepare, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ No functional changes are intended. Fixes: 6f15a9c9f941 ("PCI: microchip: Add Microchip PolarFire PCIe controller driver") Link: https://lore.kernel.org/linux-pci/20230629165956.237832-3-kwilczynski@kernel.org Link: https://lore.kernel.org/linux-pci/20230511-pci-microchip-clk-cast-v1-1-7674f4d4e218@kernel.org Link: https://lore.kernel.org/linux-pci/20230111125323.1911373-3-daire.mcnamara@microchip.com Co-developed-by: Daire McNamara Signed-off-by: Daire McNamara Co-developed-by: Simon Horman Signed-off-by: Simon Horman Signed-off-by: Krzysztof Wilczyński Acked-by: Conor Dooley --- drivers/pci/controller/pcie-microchip-host.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index 5e710e485464..d30286f815e7 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -848,6 +848,13 @@ static const struct irq_domain_ops event_domain_ops = { .map = mc_pcie_event_map, }; +static inline void mc_pcie_deinit_clk(void *data) +{ + struct clk *clk = data; + + clk_disable_unprepare(clk); +} + static inline struct clk *mc_pcie_init_clk(struct device *dev, const char *id) { struct clk *clk; @@ -863,8 +870,7 @@ static inline struct clk *mc_pcie_init_clk(struct device *dev, const char *id) if (ret) return ERR_PTR(ret); - devm_add_action_or_reset(dev, (void (*) (void *))clk_disable_unprepare, - clk); + devm_add_action_or_reset(dev, mc_pcie_deinit_clk, clk); return clk; } -- cgit v1.2.3 From cdb50033dd6dfcf02ae3d4ee56bc1a9555be6d36 Mon Sep 17 00:00:00 2001 From: Rick Wertenbroek Date: Mon, 3 Jul 2023 10:58:45 +0200 Subject: PCI: rockchip: Use 64-bit mask on MSI 64-bit PCI address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A 32-bit mask was used on the 64-bit PCI address used for mapping MSIs. This would result in the upper 32 bits being unintentionally zeroed and MSIs getting mapped to incorrect PCI addresses if the address had any of the upper bits set. Replace 32-bit mask by appropriate 64-bit mask. [kwilczynski: use GENMASK_ULL() over GENMASK() for 32-bit compatibility] Fixes: dc73ed0f1b8b ("PCI: rockchip: Fix window mapping and address translation for endpoint") Closes: https://lore.kernel.org/linux-pci/8d19e5b7-8fa0-44a4-90e2-9bb06f5eb694@moroto.mountain Link: https://lore.kernel.org/linux-pci/20230703085845.2052008-1-rick.wertenbroek@gmail.com Reported-by: Dan Carpenter Signed-off-by: Rick Wertenbroek Signed-off-by: Krzysztof Wilczyński Reviewed-by: Damien Le Moal Cc: stable@vger.kernel.org --- drivers/pci/controller/pcie-rockchip.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h index fe0333778fd9..6111de35f84c 100644 --- a/drivers/pci/controller/pcie-rockchip.h +++ b/drivers/pci/controller/pcie-rockchip.h @@ -158,7 +158,9 @@ #define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274) #define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK GENMASK(31, 20) -#define PCIE_ADDR_MASK 0xffffff00 +#define MAX_AXI_IB_ROOTPORT_REGION_NUM 3 +#define MIN_AXI_ADDR_BITS_PASSED 8 +#define PCIE_ADDR_MASK GENMASK_ULL(63, MIN_AXI_ADDR_BITS_PASSED) #define PCIE_CORE_AXI_CONF_BASE 0xc00000 #define PCIE_CORE_OB_REGION_ADDR0 (PCIE_CORE_AXI_CONF_BASE + 0x0) #define PCIE_CORE_OB_REGION_ADDR0_NUM_BITS 0x3f @@ -185,8 +187,6 @@ #define AXI_WRAPPER_TYPE1_CFG 0xb #define AXI_WRAPPER_NOR_MSG 0xc -#define MAX_AXI_IB_ROOTPORT_REGION_NUM 3 -#define MIN_AXI_ADDR_BITS_PASSED 8 #define PCIE_RC_SEND_PME_OFF 0x11960 #define ROCKCHIP_VENDOR_ID 0x1d87 #define PCIE_LINK_IS_L2(x) \ -- cgit v1.2.3 From c925cfaf0992f151c02f239e035ca9316224f224 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:48:25 -0600 Subject: PCI: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Link: https://lore.kernel.org/r/20230714174827.4061572-1-robh@kernel.org Signed-off-by: Rob Herring Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/cadence/pci-j721e.c | 2 +- drivers/pci/controller/cadence/pcie-cadence-plat.c | 3 +-- drivers/pci/controller/cadence/pcie-cadence.c | 1 + drivers/pci/controller/dwc/pci-dra7xx.c | 2 +- drivers/pci/controller/dwc/pci-exynos.c | 2 +- drivers/pci/controller/dwc/pci-imx6.c | 2 +- drivers/pci/controller/dwc/pci-keystone.c | 1 - drivers/pci/controller/dwc/pci-meson.c | 2 +- drivers/pci/controller/dwc/pcie-artpec6.c | 2 +- drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +- drivers/pci/controller/dwc/pcie-designware.c | 2 +- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 +- drivers/pci/controller/dwc/pcie-intel-gw.c | 2 ++ drivers/pci/controller/dwc/pcie-kirin.c | 3 +-- drivers/pci/controller/dwc/pcie-qcom.c | 2 +- drivers/pci/controller/dwc/pcie-tegra194.c | 1 - drivers/pci/controller/dwc/pcie-uniphier-ep.c | 2 +- drivers/pci/controller/mobiveil/pcie-mobiveil-host.c | 3 --- drivers/pci/controller/pci-ftpci100.c | 3 +-- drivers/pci/controller/pci-host-common.c | 2 +- drivers/pci/controller/pci-ixp4xx.c | 3 +-- drivers/pci/controller/pci-loongson.c | 2 +- drivers/pci/controller/pci-v3-semi.c | 3 +-- drivers/pci/controller/pcie-altera.c | 5 ++--- drivers/pci/controller/pcie-rockchip-host.c | 4 +--- drivers/pci/controller/pcie-rockchip.c | 1 + drivers/pci/endpoint/pci-epc-core.c | 1 - drivers/pci/probe.c | 1 - 28 files changed, 25 insertions(+), 36 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c index e70213c9060a..2c87e7728a65 100644 --- a/drivers/pci/controller/cadence/pci-j721e.c +++ b/drivers/pci/controller/cadence/pci-j721e.c @@ -14,8 +14,8 @@ #include #include #include -#include #include +#include #include #include diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c index bac0541317c1..371ffc1f00f8 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-plat.c +++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c @@ -6,11 +6,10 @@ * Author: Tom Joseph */ #include -#include +#include #include #include #include -#include #include "pcie-cadence.h" #define CDNS_PLAT_CPU_TO_BUS_ADDR 0x0FFFFFFF diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c index 13c4032ca379..4251fac5e310 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.c +++ b/drivers/pci/controller/cadence/pcie-cadence.c @@ -4,6 +4,7 @@ // Author: Cyrille Pitchen #include +#include #include "pcie-cadence.h" diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 4ae807e7cf79..b445ffe95e3f 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index ec5611005566..6319082301d6 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -14,11 +14,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include "pcie-designware.h" diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 27aaa2a6bf39..d123797a06a2 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 78818853af9e..49aea6ce3e87 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index c1527693bed9..973b0fc81315 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include #include #include +#include #include #include "pcie-designware.h" diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 98102079e26d..9b572a2b2c9a 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 1fcfb840f238..b625841e98aa 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index c87848cd8686..2459f2a61b9b 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index c1e7653e508e..2fe42c70097f 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 9c7caed9e706..c9c93524e01d 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -9,9 +9,11 @@ #include #include #include +#include #include #include #include +#include #include #include "../../pci.h" diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d09507f822a7..d93bc2906950 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -16,8 +16,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 7a87a47eb7ed..cee4e400a695 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index e1db909f53ec..383ba71d1e8f 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c index 4d0a587c0ba5..cba3c88fcf39 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c +++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c index 31a7bdebe540..45b97a4b14db 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c @@ -17,9 +17,6 @@ #include #include #include -#include -#include -#include #include #include #include diff --git a/drivers/pci/controller/pci-ftpci100.c b/drivers/pci/controller/pci-ftpci100.c index 6e7981d2ed5e..ffdeed25e961 100644 --- a/drivers/pci/controller/pci-ftpci100.c +++ b/drivers/pci/controller/pci-ftpci100.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index d3924a44db02..6be3266cd7b5 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include #include diff --git a/drivers/pci/controller/pci-ixp4xx.c b/drivers/pci/controller/pci-ixp4xx.c index e44252db6085..acb85e0d5675 100644 --- a/drivers/pci/controller/pci-ixp4xx.c +++ b/drivers/pci/controller/pci-ixp4xx.c @@ -19,8 +19,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c index fe0f732f6e43..d45e7b8dc530 100644 --- a/drivers/pci/controller/pci-loongson.c +++ b/drivers/pci/controller/pci-loongson.c @@ -5,7 +5,7 @@ * Copyright (C) 2020 Jiaxun Yang */ -#include +#include #include #include #include diff --git a/drivers/pci/controller/pci-v3-semi.c b/drivers/pci/controller/pci-v3-semi.c index ca44b0c83d1b..0917f571bb6d 100644 --- a/drivers/pci/controller/pci-v3-semi.c +++ b/drivers/pci/controller/pci-v3-semi.c @@ -20,8 +20,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c index c95a29fff8bf..a9536dc4bf96 100644 --- a/drivers/pci/controller/pcie-altera.c +++ b/drivers/pci/controller/pcie-altera.c @@ -9,11 +9,10 @@ #include #include #include +#include #include #include -#include -#include -#include +#include #include #include #include diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index 2438bc9b3a1a..afbbdccd195d 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -24,10 +24,8 @@ #include #include #include -#include -#include +#include #include -#include #include #include #include diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c index 1aa84035a8bc..0ef2e622d36e 100644 --- a/drivers/pci/controller/pcie-rockchip.c +++ b/drivers/pci/controller/pcie-rockchip.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 6c54fa5684d2..5a4a8b0be626 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8bac3ce02609..31fb02fbb2cc 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 5810ab21860538bce22acb6f9bb74086e493a7e2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Jun 2023 13:56:12 +0100 Subject: PCI: ibmphp: Make read-only arrays static Don't populate the arrays on the stack; instead make them static const. Link: https://lore.kernel.org/r/20230627125612.724764-1-colin.i.king@gmail.com Signed-off-by: Colin Ian King Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/ibmphp_pci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c index 754c3f23282e..50038e5f9ca4 100644 --- a/drivers/pci/hotplug/ibmphp_pci.c +++ b/drivers/pci/hotplug/ibmphp_pci.c @@ -329,7 +329,7 @@ error: static int configure_device(struct pci_func *func) { u32 bar[6]; - u32 address[] = { + static const u32 address[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, @@ -564,7 +564,7 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno) struct resource_node *pfmem = NULL; struct resource_node *bus_pfmem[2] = {NULL, NULL}; struct bus_node *bus; - u32 address[] = { + static const u32 address[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, 0 @@ -1053,7 +1053,7 @@ static struct res_needed *scan_behind_bridge(struct pci_func *func, u8 busno) int howmany = 0; /*this is to see if there are any devices behind the bridge */ u32 bar[6], class; - u32 address[] = { + static const u32 address[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, @@ -1182,7 +1182,7 @@ static struct res_needed *scan_behind_bridge(struct pci_func *func, u8 busno) static int unconfigure_boot_device(u8 busno, u8 device, u8 function) { u32 start_address; - u32 address[] = { + static const u32 address[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, @@ -1310,7 +1310,7 @@ static int unconfigure_boot_bridge(u8 busno, u8 device, u8 function) struct resource_node *mem = NULL; struct resource_node *pfmem = NULL; struct bus_node *bus; - u32 address[] = { + static const u32 address[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, 0 -- cgit v1.2.3 From f768c75d61582b011962f9dcb9ff8eafb8da0383 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Mon, 3 Jul 2023 15:52:54 +0200 Subject: PCI: Make quirk using inw() depend on HAS_IOPORT In the future inw() and friends will not be compiled on architectures without I/O port support. Co-developed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230703135255.2202721-2-schnelle@linux.ibm.com Signed-off-by: Arnd Bergmann Signed-off-by: Niklas Schnelle Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 321156ca273d..ef193661c3d1 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -361,6 +361,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_d DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs); #endif +#ifdef CONFIG_HAS_IOPORT /* * Intel NM10 "TigerPoint" LPC PM1a_STS.BM_STS must be clear * for some HT machines to use C4 w/o hanging. @@ -380,6 +381,7 @@ static void quirk_tigerpoint_bm_sts(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGP_LPC, quirk_tigerpoint_bm_sts); +#endif /* Chipsets where PCI->PCI transfers vanish or hang */ static void quirk_nopcipci(struct pci_dev *dev) -- cgit v1.2.3 From 5da1b58868a620cb58ad9ab31632ce9304c9f4f4 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Mon, 3 Jul 2023 15:52:55 +0200 Subject: PCI/sysfs: Make I/O resource depend on HAS_IOPORT If legacy I/O spaces are not supported simply return an error when trying to access them via pci_resource_io(). This allows inb() and friends to become undefined when they are known at compile time to be non-functional in a later patch. Co-developed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230703135255.2202721-3-schnelle@linux.ibm.com Signed-off-by: Arnd Bergmann Signed-off-by: Niklas Schnelle Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index ab32a91f287b..d9eede2dbc0e 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1083,6 +1083,7 @@ static ssize_t pci_resource_io(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count, bool write) { +#ifdef CONFIG_HAS_IOPORT struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); int bar = (unsigned long)attr->private; unsigned long port = off; @@ -1116,6 +1117,9 @@ static ssize_t pci_resource_io(struct file *filp, struct kobject *kobj, return 4; } return -EINVAL; +#else + return -ENXIO; +#endif } static ssize_t pci_read_resource_io(struct file *filp, struct kobject *kobj, -- cgit v1.2.3 From e3a3a097eaebaf234a482b4d2f9f18fe989208c1 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Wed, 26 Jul 2023 11:29:42 -0700 Subject: PCI/DOE: Fix destroy_work_on_stack() race The following debug object splat was observed in testing: ODEBUG: free active (active state 0) object: 0000000097d23782 object type: work_struct hint: doe_statemachine_work+0x0/0x510 WARNING: CPU: 1 PID: 71 at lib/debugobjects.c:514 debug_print_object+0x7d/0xb0 ... Workqueue: pci 0000:36:00.0 DOE [1 doe_statemachine_work RIP: 0010:debug_print_object+0x7d/0xb0 ... Call Trace: ? debug_print_object+0x7d/0xb0 ? __pfx_doe_statemachine_work+0x10/0x10 debug_object_free.part.0+0x11b/0x150 doe_statemachine_work+0x45e/0x510 process_one_work+0x1d4/0x3c0 This occurs because destroy_work_on_stack() was called after signaling the completion in the calling thread. This creates a race between destroy_work_on_stack() and the task->work struct going out of scope in pci_doe(). Signal the work complete after destroying the work struct. This is safe because signal_task_complete() is the final thing the work item does and the workqueue code is careful not to access the work struct after. Fixes: abf04be0e707 ("PCI/DOE: Fix memory leak with CONFIG_DEBUG_OBJECTS=y") Link: https://lore.kernel.org/r/20230726-doe-fix-v1-1-af07e614d4dd@intel.com Signed-off-by: Ira Weiny Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner Acked-by: Dan Williams --- drivers/pci/doe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index 1b97a5ab71a9..e3aab5edaf70 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -293,8 +293,8 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas static void signal_task_complete(struct pci_doe_task *task, int rv) { task->rv = rv; - task->complete(task); destroy_work_on_stack(&task->work); + task->complete(task); } static void signal_task_abort(struct pci_doe_task *task, int rv) -- cgit v1.2.3 From ebfde1584d9f037b6309fc682c96e22dac7bcb7a Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Mon, 19 Jun 2023 15:56:04 +0530 Subject: Revert "PCI: tegra194: Enable support for 256 Byte payload" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit 4fb8e46c1bc4 ("PCI: tegra194: Enable support for 256 Byte payload"), we initialize MPS=256 for tegra194 Root Ports before enumerating the hierarchy. Consider an Endpoint that supports only MPS=128. In the default situation (CONFIG_PCIE_BUS_DEFAULT set and no "pci=pcie_bus_*" parameter), Linux tries to configure the MPS of every device to match the upstream bridge. If the Endpoint is directly below the Root Port, Linux can reduce the Root Port MPS to 128 to match the Endpoint. But if there's a switch in the middle, Linux doesn't reduce the Root Port MPS because other devices below the switch may already be configured with MPS larger than 128. This scenario results in uncorrectable Malformed TLP errors if the Root Port sends TLPs with payloads larger than 128 bytes. These errors can be avoided by using the "pci=pcie_bus_safe" parameter, but it doesn't seem to be a good idea to always have this parameter even for basic functionality to work. Revert commit 4fb8e46c1bc4 ("PCI: tegra194: Enable support for 256 Byte payload") so the Root Ports default to MPS=128, which all devices support. If peer-to-peer DMA is not required, one can use "pci=pcie_bus_perf" to get the benefit of larger MPS settings. [bhelgaas: commit log; kwilczynski: retain "u16 val_16" declaration at the top, add missing acked by tag] Fixes: 4fb8e46c1bc4 ("PCI: tegra194: Enable support for 256 Byte payload") Link: https://lore.kernel.org/linux-pci/20230619102604.3735001-1-vidyas@nvidia.com Signed-off-by: Vidya Sagar Signed-off-by: Krzysztof Wilczyński Acked-by: Jon Hunter Cc: stable@vger.kernel.org # v6.0-rc1+ --- drivers/pci/controller/dwc/pcie-tegra194.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index e1db909f53ec..ccff8cde5cff 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -900,11 +900,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp) pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP); - val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_DEVCTL); - val_16 &= ~PCI_EXP_DEVCTL_PAYLOAD; - val_16 |= PCI_EXP_DEVCTL_PAYLOAD_256B; - dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_DEVCTL, val_16); - val = dw_pcie_readl_dbi(pci, PCI_IO_BASE); val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8); dw_pcie_writel_dbi(pci, PCI_IO_BASE, val); @@ -1887,11 +1882,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP); - val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_DEVCTL); - val_16 &= ~PCI_EXP_DEVCTL_PAYLOAD; - val_16 |= PCI_EXP_DEVCTL_PAYLOAD_256B; - dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_DEVCTL, val_16); - /* Clear Slot Clock Configuration bit if SRNS configuration */ if (pcie->enable_srns) { val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + -- cgit v1.2.3 From d332642a9821bfab4c0ddf1173e3af40127f0157 Mon Sep 17 00:00:00 2001 From: Xiongfeng Wang Date: Mon, 7 Aug 2023 21:48:56 +0800 Subject: PCI: apple: Use pci_dev_id() to simplify the code When we have a struct pci_dev *, use pci_dev_id() instead of manually composing the ID with PCI_DEVID() from dev->bus->number and dev->devfn. [bhelgaas: commit log] Link: https://lore.kernel.org/r/20230807134858.116051-2-wangxiongfeng2@huawei.com Signed-off-by: Xiongfeng Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/pcie-apple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 66f37e403a09..2abca318e22a 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -670,7 +670,7 @@ static struct apple_pcie_port *apple_pcie_get_port(struct pci_dev *pdev) static int apple_pcie_add_device(struct apple_pcie_port *port, struct pci_dev *pdev) { - u32 sid, rid = PCI_DEVID(pdev->bus->number, pdev->devfn); + u32 sid, rid = pci_dev_id(pdev); int idx, err; dev_dbg(&pdev->dev, "added to bus %s, index %d\n", @@ -701,7 +701,7 @@ static int apple_pcie_add_device(struct apple_pcie_port *port, static void apple_pcie_release_device(struct apple_pcie_port *port, struct pci_dev *pdev) { - u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn); + u32 rid = pci_dev_id(pdev); int idx; mutex_lock(&port->pcie->lock); -- cgit v1.2.3 From f7f7c3d61556bb25c8c45c164056533fb2dde867 Mon Sep 17 00:00:00 2001 From: Xiongfeng Wang Date: Mon, 7 Aug 2023 21:48:57 +0800 Subject: PCI/AER: Use pci_dev_id() to simplify the code When we have a struct pci_dev *, use pci_dev_id() instead of manually composing the ID with PCI_DEVID() from dev->bus->number and dev->devfn. [bhelgaas: commit log] Link: https://lore.kernel.org/r/20230807134858.116051-3-wangxiongfeng2@huawei.com Signed-off-by: Xiongfeng Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index f6c24ded134c..2bc03937452b 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -712,7 +712,7 @@ static void __aer_print_error(struct pci_dev *dev, void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { int layer, agent; - int id = ((dev->bus->number << 8) | dev->devfn); + int id = pci_dev_id(dev); const char *level; if (!info->status) { @@ -847,7 +847,7 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info) if ((PCI_BUS_NUM(e_info->id) != 0) && !(dev->bus->bus_flags & PCI_BUS_FLAGS_NO_AERSID)) { /* Device ID match? */ - if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) + if (e_info->id == pci_dev_id(dev)) return true; /* Continue id comparing if there is no multiple error */ -- cgit v1.2.3 From 6f7dc3076717d48980d8214eee083ee401fbe66d Mon Sep 17 00:00:00 2001 From: Xiongfeng Wang Date: Mon, 7 Aug 2023 21:48:58 +0800 Subject: PCI/IOV: Use pci_dev_id() to simplify the code When we have a struct pci_dev *, use pci_dev_id() instead of manually composing the ID with PCI_DEVID() from dev->bus->number and dev->devfn. [bhelgaas: commit log] Link: https://lore.kernel.org/r/20230807134858.116051-4-wangxiongfeng2@huawei.com Signed-off-by: Xiongfeng Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/iov.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index b2e8322755c1..25dbe85c4217 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -41,8 +41,7 @@ int pci_iov_vf_id(struct pci_dev *dev) return -EINVAL; pf = pci_physfn(dev); - return (((dev->bus->number << 8) + dev->devfn) - - ((pf->bus->number << 8) + pf->devfn + pf->sriov->offset)) / + return (pci_dev_id(dev) - (pci_dev_id(pf) + pf->sriov->offset)) / pf->sriov->stride; } EXPORT_SYMBOL_GPL(pci_iov_vf_id); -- cgit v1.2.3 From 6d473a5a26136edf55c435a1c433e52910e03926 Mon Sep 17 00:00:00 2001 From: Daire McNamara Date: Fri, 28 Jul 2023 14:13:55 +0100 Subject: PCI: microchip: Correct the DED and SEC interrupt bit offsets The SEC and DED interrupt bits are laid out the wrong way round so the SEC interrupt handler attempts to mask, unmask, and clear the DED interrupt and vice versa. Correct the bit offsets so that each interrupt handler operates properly. Link: https://lore.kernel.org/r/20230728131401.1615724-2-daire.mcnamara@microchip.com Fixes: 6f15a9c9f941 ("PCI: microchip: Add Microchip PolarFire PCIe controller driver") Signed-off-by: Daire McNamara Signed-off-by: Lorenzo Pieralisi Reviewed-by: Conor Dooley --- drivers/pci/controller/pcie-microchip-host.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index 5e710e485464..dd5245904c87 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -167,12 +167,12 @@ #define EVENT_PCIE_DLUP_EXIT 2 #define EVENT_SEC_TX_RAM_SEC_ERR 3 #define EVENT_SEC_RX_RAM_SEC_ERR 4 -#define EVENT_SEC_AXI2PCIE_RAM_SEC_ERR 5 -#define EVENT_SEC_PCIE2AXI_RAM_SEC_ERR 6 +#define EVENT_SEC_PCIE2AXI_RAM_SEC_ERR 5 +#define EVENT_SEC_AXI2PCIE_RAM_SEC_ERR 6 #define EVENT_DED_TX_RAM_DED_ERR 7 #define EVENT_DED_RX_RAM_DED_ERR 8 -#define EVENT_DED_AXI2PCIE_RAM_DED_ERR 9 -#define EVENT_DED_PCIE2AXI_RAM_DED_ERR 10 +#define EVENT_DED_PCIE2AXI_RAM_DED_ERR 9 +#define EVENT_DED_AXI2PCIE_RAM_DED_ERR 10 #define EVENT_LOCAL_DMA_END_ENGINE_0 11 #define EVENT_LOCAL_DMA_END_ENGINE_1 12 #define EVENT_LOCAL_DMA_ERROR_ENGINE_0 13 -- cgit v1.2.3 From 2e245bc8a2abf61e0adbac99c9f89fa537f67ecd Mon Sep 17 00:00:00 2001 From: Daire McNamara Date: Fri, 28 Jul 2023 14:13:56 +0100 Subject: PCI: microchip: Enable building driver as a module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable building driver as a module. The expected use case is the driver is built as a module, is installed when needed, and cannot be removed once installed since it is not possible to clean-up the irq_chip data structures on removal, as described in: https://lore.kernel.org/linux-pci/87y1wgbah8.wl-maz@kernel.org/ The driver has .suppress_bind_attrs set to true for the same reasons (ie prevent unbinding, that would leave the kernel with stale IRQ configuration that cannot be cleaned up). Link: https://lore.kernel.org/linux-pci/87y1wgbah8.wl-maz@kernel.org/ Link: https://lore.kernel.org/r/20230728131401.1615724-3-daire.mcnamara@microchip.com Suggested-by: Uwe Kleine-König Signed-off-by: Daire McNamara Signed-off-by: Lorenzo Pieralisi Acked-by: Conor Dooley --- drivers/pci/controller/Kconfig | 2 +- drivers/pci/controller/pcie-microchip-host.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 8d49bad7f847..f4ad0e9cca45 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -217,7 +217,7 @@ config PCIE_MT7621 This selects a driver for the MediaTek MT7621 PCIe Controller. config PCIE_MICROCHIP_HOST - bool "Microchip AXI PCIe controller" + tristate "Microchip AXI PCIe controller" depends on PCI_MSI && OF select PCI_HOST_COMMON help diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index dd5245904c87..5c89caaab8c9 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -1135,5 +1135,6 @@ static struct platform_driver mc_pcie_driver = { }; builtin_platform_driver(mc_pcie_driver); +MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Microchip PCIe host controller driver"); MODULE_AUTHOR("Daire McNamara "); -- cgit v1.2.3 From 4d6bf4c49578b9d29bc0f22fc0e7193087619aed Mon Sep 17 00:00:00 2001 From: Daire McNamara Date: Fri, 28 Jul 2023 14:13:57 +0100 Subject: PCI: microchip: Align register, offset, and mask names with HW docs Minor code re-organisation so that macros representing registers ascend in numerical order and use the same names as their hardware documentation. Removed registers not used by the driver. Link: https://lore.kernel.org/r/20230728131401.1615724-4-daire.mcnamara@microchip.com Signed-off-by: Daire McNamara Signed-off-by: Lorenzo Pieralisi Reviewed-by: Conor Dooley --- drivers/pci/controller/pcie-microchip-host.c | 122 +++++++++++++-------------- 1 file changed, 60 insertions(+), 62 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index 5c89caaab8c9..30153fd1a2b3 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -30,66 +30,7 @@ #define MC_PCIE_BRIDGE_ADDR (MC_PCIE1_BRIDGE_ADDR) #define MC_PCIE_CTRL_ADDR (MC_PCIE1_CTRL_ADDR) -/* PCIe Controller Phy Regs */ -#define SEC_ERROR_CNT 0x20 -#define DED_ERROR_CNT 0x24 -#define SEC_ERROR_INT 0x28 -#define SEC_ERROR_INT_TX_RAM_SEC_ERR_INT GENMASK(3, 0) -#define SEC_ERROR_INT_RX_RAM_SEC_ERR_INT GENMASK(7, 4) -#define SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT GENMASK(11, 8) -#define SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT GENMASK(15, 12) -#define NUM_SEC_ERROR_INTS (4) -#define SEC_ERROR_INT_MASK 0x2c -#define DED_ERROR_INT 0x30 -#define DED_ERROR_INT_TX_RAM_DED_ERR_INT GENMASK(3, 0) -#define DED_ERROR_INT_RX_RAM_DED_ERR_INT GENMASK(7, 4) -#define DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT GENMASK(11, 8) -#define DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT GENMASK(15, 12) -#define NUM_DED_ERROR_INTS (4) -#define DED_ERROR_INT_MASK 0x34 -#define ECC_CONTROL 0x38 -#define ECC_CONTROL_TX_RAM_INJ_ERROR_0 BIT(0) -#define ECC_CONTROL_TX_RAM_INJ_ERROR_1 BIT(1) -#define ECC_CONTROL_TX_RAM_INJ_ERROR_2 BIT(2) -#define ECC_CONTROL_TX_RAM_INJ_ERROR_3 BIT(3) -#define ECC_CONTROL_RX_RAM_INJ_ERROR_0 BIT(4) -#define ECC_CONTROL_RX_RAM_INJ_ERROR_1 BIT(5) -#define ECC_CONTROL_RX_RAM_INJ_ERROR_2 BIT(6) -#define ECC_CONTROL_RX_RAM_INJ_ERROR_3 BIT(7) -#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_0 BIT(8) -#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_1 BIT(9) -#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_2 BIT(10) -#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_3 BIT(11) -#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_0 BIT(12) -#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_1 BIT(13) -#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_2 BIT(14) -#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_3 BIT(15) -#define ECC_CONTROL_TX_RAM_ECC_BYPASS BIT(24) -#define ECC_CONTROL_RX_RAM_ECC_BYPASS BIT(25) -#define ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS BIT(26) -#define ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS BIT(27) -#define LTSSM_STATE 0x5c -#define LTSSM_L0_STATE 0x10 -#define PCIE_EVENT_INT 0x14c -#define PCIE_EVENT_INT_L2_EXIT_INT BIT(0) -#define PCIE_EVENT_INT_HOTRST_EXIT_INT BIT(1) -#define PCIE_EVENT_INT_DLUP_EXIT_INT BIT(2) -#define PCIE_EVENT_INT_MASK GENMASK(2, 0) -#define PCIE_EVENT_INT_L2_EXIT_INT_MASK BIT(16) -#define PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK BIT(17) -#define PCIE_EVENT_INT_DLUP_EXIT_INT_MASK BIT(18) -#define PCIE_EVENT_INT_ENB_MASK GENMASK(18, 16) -#define PCIE_EVENT_INT_ENB_SHIFT 16 -#define NUM_PCIE_EVENTS (3) - /* PCIe Bridge Phy Regs */ -#define PCIE_PCI_IDS_DW1 0x9c - -/* PCIe Config space MSI capability structure */ -#define MC_MSI_CAP_CTRL_OFFSET 0xe0u -#define MC_MSI_MAX_Q_AVAIL (MC_NUM_MSI_IRQS_CODED << 1) -#define MC_MSI_Q_SIZE (MC_NUM_MSI_IRQS_CODED << 4) - #define IMASK_LOCAL 0x180 #define DMA_END_ENGINE_0_MASK 0x00000000u #define DMA_END_ENGINE_0_SHIFT 0 @@ -137,7 +78,8 @@ #define ISTATUS_LOCAL 0x184 #define IMASK_HOST 0x188 #define ISTATUS_HOST 0x18c -#define MSI_ADDR 0x190 +#define IMSI_ADDR 0x190 +#define MSI_ADDR 0x190 #define ISTATUS_MSI 0x194 /* PCIe Master table init defines */ @@ -162,6 +104,62 @@ #define ATR_ENTRY_SIZE 32 +/* PCIe Controller Phy Regs */ +#define SEC_ERROR_EVENT_CNT 0x20 +#define DED_ERROR_EVENT_CNT 0x24 +#define SEC_ERROR_INT 0x28 +#define SEC_ERROR_INT_TX_RAM_SEC_ERR_INT GENMASK(3, 0) +#define SEC_ERROR_INT_RX_RAM_SEC_ERR_INT GENMASK(7, 4) +#define SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT GENMASK(11, 8) +#define SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT GENMASK(15, 12) +#define NUM_SEC_ERROR_INTS (4) +#define SEC_ERROR_INT_MASK 0x2c +#define DED_ERROR_INT 0x30 +#define DED_ERROR_INT_TX_RAM_DED_ERR_INT GENMASK(3, 0) +#define DED_ERROR_INT_RX_RAM_DED_ERR_INT GENMASK(7, 4) +#define DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT GENMASK(11, 8) +#define DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT GENMASK(15, 12) +#define NUM_DED_ERROR_INTS (4) +#define DED_ERROR_INT_MASK 0x34 +#define ECC_CONTROL 0x38 +#define ECC_CONTROL_TX_RAM_INJ_ERROR_0 BIT(0) +#define ECC_CONTROL_TX_RAM_INJ_ERROR_1 BIT(1) +#define ECC_CONTROL_TX_RAM_INJ_ERROR_2 BIT(2) +#define ECC_CONTROL_TX_RAM_INJ_ERROR_3 BIT(3) +#define ECC_CONTROL_RX_RAM_INJ_ERROR_0 BIT(4) +#define ECC_CONTROL_RX_RAM_INJ_ERROR_1 BIT(5) +#define ECC_CONTROL_RX_RAM_INJ_ERROR_2 BIT(6) +#define ECC_CONTROL_RX_RAM_INJ_ERROR_3 BIT(7) +#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_0 BIT(8) +#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_1 BIT(9) +#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_2 BIT(10) +#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_3 BIT(11) +#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_0 BIT(12) +#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_1 BIT(13) +#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_2 BIT(14) +#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_3 BIT(15) +#define ECC_CONTROL_TX_RAM_ECC_BYPASS BIT(24) +#define ECC_CONTROL_RX_RAM_ECC_BYPASS BIT(25) +#define ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS BIT(26) +#define ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS BIT(27) +#define PCIE_EVENT_INT 0x14c +#define PCIE_EVENT_INT_L2_EXIT_INT BIT(0) +#define PCIE_EVENT_INT_HOTRST_EXIT_INT BIT(1) +#define PCIE_EVENT_INT_DLUP_EXIT_INT BIT(2) +#define PCIE_EVENT_INT_MASK GENMASK(2, 0) +#define PCIE_EVENT_INT_L2_EXIT_INT_MASK BIT(16) +#define PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK BIT(17) +#define PCIE_EVENT_INT_DLUP_EXIT_INT_MASK BIT(18) +#define PCIE_EVENT_INT_ENB_MASK GENMASK(18, 16) +#define PCIE_EVENT_INT_ENB_SHIFT 16 +#define NUM_PCIE_EVENTS (3) + +/* PCIe Config space MSI capability structure */ +#define MC_MSI_CAP_CTRL_OFFSET 0xe0u +#define MC_MSI_MAX_Q_AVAIL (MC_NUM_MSI_IRQS_CODED << 1) +#define MC_MSI_Q_SIZE (MC_NUM_MSI_IRQS_CODED << 4) + +/* Events */ #define EVENT_PCIE_L2_EXIT 0 #define EVENT_PCIE_HOTRST_EXIT 1 #define EVENT_PCIE_DLUP_EXIT 2 @@ -1086,7 +1084,7 @@ static int mc_platform_init(struct pci_config_window *cfg) SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT; writel_relaxed(val, ctrl_base_addr + SEC_ERROR_INT); writel_relaxed(0, ctrl_base_addr + SEC_ERROR_INT_MASK); - writel_relaxed(0, ctrl_base_addr + SEC_ERROR_CNT); + writel_relaxed(0, ctrl_base_addr + SEC_ERROR_EVENT_CNT); val = DED_ERROR_INT_TX_RAM_DED_ERR_INT | DED_ERROR_INT_RX_RAM_DED_ERR_INT | @@ -1094,7 +1092,7 @@ static int mc_platform_init(struct pci_config_window *cfg) DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT; writel_relaxed(val, ctrl_base_addr + DED_ERROR_INT); writel_relaxed(0, ctrl_base_addr + DED_ERROR_INT_MASK); - writel_relaxed(0, ctrl_base_addr + DED_ERROR_CNT); + writel_relaxed(0, ctrl_base_addr + DED_ERROR_EVENT_CNT); writel_relaxed(0, bridge_base_addr + IMASK_HOST); writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST); -- cgit v1.2.3 From d1d6a0c9e79c595b3961d5b62594e058d811d6cb Mon Sep 17 00:00:00 2001 From: Daire McNamara Date: Fri, 28 Jul 2023 14:13:58 +0100 Subject: PCI: microchip: Enable event handlers to access bridge and control pointers Minor re-organisation so that event handlers can access both a pointer to the bridge area of the PCIe Root Port and the control area of the PCIe Root Port. Link: https://lore.kernel.org/r/20230728131401.1615724-5-daire.mcnamara@microchip.com Signed-off-by: Daire McNamara Signed-off-by: Lorenzo Pieralisi Reviewed-by: Conor Dooley --- drivers/pci/controller/pcie-microchip-host.c | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index 30153fd1a2b3..a81e6d25e347 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -654,9 +654,10 @@ static inline u32 reg_to_event(u32 reg, struct event_map field) return (reg & field.reg_mask) ? BIT(field.event_bit) : 0; } -static u32 pcie_events(void __iomem *addr) +static u32 pcie_events(struct mc_pcie *port) { - u32 reg = readl_relaxed(addr); + void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; + u32 reg = readl_relaxed(ctrl_base_addr + PCIE_EVENT_INT); u32 val = 0; int i; @@ -666,9 +667,10 @@ static u32 pcie_events(void __iomem *addr) return val; } -static u32 sec_errors(void __iomem *addr) +static u32 sec_errors(struct mc_pcie *port) { - u32 reg = readl_relaxed(addr); + void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; + u32 reg = readl_relaxed(ctrl_base_addr + SEC_ERROR_INT); u32 val = 0; int i; @@ -678,9 +680,10 @@ static u32 sec_errors(void __iomem *addr) return val; } -static u32 ded_errors(void __iomem *addr) +static u32 ded_errors(struct mc_pcie *port) { - u32 reg = readl_relaxed(addr); + void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; + u32 reg = readl_relaxed(ctrl_base_addr + DED_ERROR_INT); u32 val = 0; int i; @@ -690,9 +693,10 @@ static u32 ded_errors(void __iomem *addr) return val; } -static u32 local_events(void __iomem *addr) +static u32 local_events(struct mc_pcie *port) { - u32 reg = readl_relaxed(addr); + void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; + u32 reg = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL); u32 val = 0; int i; @@ -704,15 +708,12 @@ static u32 local_events(void __iomem *addr) static u32 get_events(struct mc_pcie *port) { - void __iomem *bridge_base_addr = - port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; - void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; u32 events = 0; - events |= pcie_events(ctrl_base_addr + PCIE_EVENT_INT); - events |= sec_errors(ctrl_base_addr + SEC_ERROR_INT); - events |= ded_errors(ctrl_base_addr + DED_ERROR_INT); - events |= local_events(bridge_base_addr + ISTATUS_LOCAL); + events |= pcie_events(port); + events |= sec_errors(port); + events |= ded_errors(port); + events |= local_events(port); return events; } -- cgit v1.2.3 From 4f0b91247f78ccd702f2da5a17d4524101adfc7d Mon Sep 17 00:00:00 2001 From: Daire McNamara Date: Fri, 28 Jul 2023 14:13:59 +0100 Subject: PCI: microchip: Clean up initialisation of interrupts Refactor interrupt handling in _init() function into disable_interrupts(), init_interrupts(), clear_sec_errors() and clear ded_errors() because current code is unwieldy and prone to bugs. Disable interrupts as soon as possible and only enable interrupts after address translation is setup to prevent spurious axi2pcie and pcie2axi translation errors being reported. Link: https://lore.kernel.org/r/20230728131401.1615724-6-daire.mcnamara@microchip.com Signed-off-by: Daire McNamara Signed-off-by: Lorenzo Pieralisi Reviewed-by: Conor Dooley --- drivers/pci/controller/pcie-microchip-host.c | 156 +++++++++++++++++---------- 1 file changed, 100 insertions(+), 56 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index a81e6d25e347..7b212eea42d2 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -112,6 +112,7 @@ #define SEC_ERROR_INT_RX_RAM_SEC_ERR_INT GENMASK(7, 4) #define SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT GENMASK(11, 8) #define SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT GENMASK(15, 12) +#define SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT GENMASK(15, 0) #define NUM_SEC_ERROR_INTS (4) #define SEC_ERROR_INT_MASK 0x2c #define DED_ERROR_INT 0x30 @@ -119,6 +120,7 @@ #define DED_ERROR_INT_RX_RAM_DED_ERR_INT GENMASK(7, 4) #define DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT GENMASK(11, 8) #define DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT GENMASK(15, 12) +#define DED_ERROR_INT_ALL_RAM_DED_ERR_INT GENMASK(15, 0) #define NUM_DED_ERROR_INTS (4) #define DED_ERROR_INT_MASK 0x34 #define ECC_CONTROL 0x38 @@ -986,39 +988,73 @@ static int mc_pcie_setup_windows(struct platform_device *pdev, return 0; } -static int mc_platform_init(struct pci_config_window *cfg) +static inline void mc_clear_secs(struct mc_pcie *port) { - struct device *dev = cfg->parent; - struct platform_device *pdev = to_platform_device(dev); - struct mc_pcie *port; - void __iomem *bridge_base_addr; - void __iomem *ctrl_base_addr; - int ret; - int irq; - int i, intx_irq, msi_irq, event_irq; + void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; + + writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr + + SEC_ERROR_INT); + writel_relaxed(0, ctrl_base_addr + SEC_ERROR_EVENT_CNT); +} + +static inline void mc_clear_deds(struct mc_pcie *port) +{ + void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; + + writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr + + DED_ERROR_INT); + writel_relaxed(0, ctrl_base_addr + DED_ERROR_EVENT_CNT); +} + +static void mc_disable_interrupts(struct mc_pcie *port) +{ + void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; + void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; u32 val; - int err; - port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); - if (!port) - return -ENOMEM; - port->dev = dev; + /* Ensure ECC bypass is enabled */ + val = ECC_CONTROL_TX_RAM_ECC_BYPASS | + ECC_CONTROL_RX_RAM_ECC_BYPASS | + ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS | + ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS; + writel_relaxed(val, ctrl_base_addr + ECC_CONTROL); - ret = mc_pcie_init_clks(dev); - if (ret) { - dev_err(dev, "failed to get clock resources, error %d\n", ret); - return -ENODEV; - } + /* Disable SEC errors and clear any outstanding */ + writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr + + SEC_ERROR_INT_MASK); + mc_clear_secs(port); - port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(port->axi_base_addr)) - return PTR_ERR(port->axi_base_addr); + /* Disable DED errors and clear any outstanding */ + writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr + + DED_ERROR_INT_MASK); + mc_clear_deds(port); - bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; - ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; + /* Disable local interrupts and clear any outstanding */ + writel_relaxed(0, bridge_base_addr + IMASK_LOCAL); + writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_LOCAL); + writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_MSI); + + /* Disable PCIe events and clear any outstanding */ + val = PCIE_EVENT_INT_L2_EXIT_INT | + PCIE_EVENT_INT_HOTRST_EXIT_INT | + PCIE_EVENT_INT_DLUP_EXIT_INT | + PCIE_EVENT_INT_L2_EXIT_INT_MASK | + PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK | + PCIE_EVENT_INT_DLUP_EXIT_INT_MASK; + writel_relaxed(val, ctrl_base_addr + PCIE_EVENT_INT); + + /* Disable host interrupts and clear any outstanding */ + writel_relaxed(0, bridge_base_addr + IMASK_HOST); + writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST); +} + +static int mc_init_interrupts(struct platform_device *pdev, struct mc_pcie *port) +{ + struct device *dev = &pdev->dev; + int irq; + int i, intx_irq, msi_irq, event_irq; + int ret; - port->msi.vector_phy = MSI_ADDR; - port->msi.num_vectors = MC_NUM_MSI_IRQS; ret = mc_pcie_init_irq_domains(port); if (ret) { dev_err(dev, "failed creating IRQ domains\n"); @@ -1036,11 +1072,11 @@ static int mc_platform_init(struct pci_config_window *cfg) return -ENXIO; } - err = devm_request_irq(dev, event_irq, mc_event_handler, + ret = devm_request_irq(dev, event_irq, mc_event_handler, 0, event_cause[i].sym, port); - if (err) { + if (ret) { dev_err(dev, "failed to request IRQ %d\n", event_irq); - return err; + return ret; } } @@ -1065,44 +1101,52 @@ static int mc_platform_init(struct pci_config_window *cfg) /* Plug the main event chained handler */ irq_set_chained_handler_and_data(irq, mc_handle_event, port); - /* Hardware doesn't setup MSI by default */ - mc_pcie_enable_msi(port, cfg->win); + return 0; +} - val = readl_relaxed(bridge_base_addr + IMASK_LOCAL); - val |= PM_MSI_INT_INTX_MASK; - writel_relaxed(val, bridge_base_addr + IMASK_LOCAL); +static int mc_platform_init(struct pci_config_window *cfg) +{ + struct device *dev = cfg->parent; + struct platform_device *pdev = to_platform_device(dev); + struct mc_pcie *port; + void __iomem *bridge_base_addr; + int ret; - writel_relaxed(val, ctrl_base_addr + ECC_CONTROL); + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + port->dev = dev; - val = PCIE_EVENT_INT_L2_EXIT_INT | - PCIE_EVENT_INT_HOTRST_EXIT_INT | - PCIE_EVENT_INT_DLUP_EXIT_INT; - writel_relaxed(val, ctrl_base_addr + PCIE_EVENT_INT); + ret = mc_pcie_init_clks(dev); + if (ret) { + dev_err(dev, "failed to get clock resources, error %d\n", ret); + return -ENODEV; + } - val = SEC_ERROR_INT_TX_RAM_SEC_ERR_INT | - SEC_ERROR_INT_RX_RAM_SEC_ERR_INT | - SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT | - SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT; - writel_relaxed(val, ctrl_base_addr + SEC_ERROR_INT); - writel_relaxed(0, ctrl_base_addr + SEC_ERROR_INT_MASK); - writel_relaxed(0, ctrl_base_addr + SEC_ERROR_EVENT_CNT); + port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(port->axi_base_addr)) + return PTR_ERR(port->axi_base_addr); - val = DED_ERROR_INT_TX_RAM_DED_ERR_INT | - DED_ERROR_INT_RX_RAM_DED_ERR_INT | - DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT | - DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT; - writel_relaxed(val, ctrl_base_addr + DED_ERROR_INT); - writel_relaxed(0, ctrl_base_addr + DED_ERROR_INT_MASK); - writel_relaxed(0, ctrl_base_addr + DED_ERROR_EVENT_CNT); + mc_disable_interrupts(port); - writel_relaxed(0, bridge_base_addr + IMASK_HOST); - writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST); + bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; + + port->msi.vector_phy = MSI_ADDR; + port->msi.num_vectors = MC_NUM_MSI_IRQS; + + /* Hardware doesn't setup MSI by default */ + mc_pcie_enable_msi(port, cfg->win); /* Configure Address Translation Table 0 for PCIe config space */ mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start & 0xffffffff, cfg->res.start, resource_size(&cfg->res)); - return mc_pcie_setup_windows(pdev, port); + ret = mc_pcie_setup_windows(pdev, port); + if (ret) + return ret; + + /* Address translation is up; safe to enable interrupts */ + return mc_init_interrupts(pdev, port); } static const struct pci_ecam_ops mc_ecam_ops = { -- cgit v1.2.3 From 1abb722888fda4a03e211db9b361281f903375e1 Mon Sep 17 00:00:00 2001 From: Daire McNamara Date: Fri, 28 Jul 2023 14:14:00 +0100 Subject: PCI: microchip: Gather MSI information from hardware config registers The PCIe Root Complex on PolarFire SoC is configured at bitstream creation time using Libero. Key MSI-related parameters include the number of MSIs (1/2/4/8/16/32) and the MSI address. In the device driver, extract this information from hardware registers at init time, and use it to configure MSI system, including configuring MSI capability structure correctly in configuration space. Link: https://lore.kernel.org/r/20230728131401.1615724-7-daire.mcnamara@microchip.com Signed-off-by: Daire McNamara Signed-off-by: Lorenzo Pieralisi Reviewed-by: Conor Dooley --- drivers/pci/controller/pcie-microchip-host.c | 65 ++++++++++++++++------------ 1 file changed, 37 insertions(+), 28 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index 7b212eea42d2..ca13fd56a0d9 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -7,6 +7,7 @@ * Author: Daire McNamara */ +#include #include #include #include @@ -20,8 +21,7 @@ #include "../pci.h" /* Number of MSI IRQs */ -#define MC_NUM_MSI_IRQS 32 -#define MC_NUM_MSI_IRQS_CODED 5 +#define MC_MAX_NUM_MSI_IRQS 32 /* PCIe Bridge Phy and Controller Phy offsets */ #define MC_PCIE1_BRIDGE_ADDR 0x00008000u @@ -31,6 +31,11 @@ #define MC_PCIE_CTRL_ADDR (MC_PCIE1_CTRL_ADDR) /* PCIe Bridge Phy Regs */ +#define PCIE_PCI_IRQ_DW0 0xa8 +#define MSIX_CAP_MASK BIT(31) +#define NUM_MSI_MSGS_MASK GENMASK(6, 4) +#define NUM_MSI_MSGS_SHIFT 4 + #define IMASK_LOCAL 0x180 #define DMA_END_ENGINE_0_MASK 0x00000000u #define DMA_END_ENGINE_0_SHIFT 0 @@ -79,7 +84,6 @@ #define IMASK_HOST 0x188 #define ISTATUS_HOST 0x18c #define IMSI_ADDR 0x190 -#define MSI_ADDR 0x190 #define ISTATUS_MSI 0x194 /* PCIe Master table init defines */ @@ -158,8 +162,6 @@ /* PCIe Config space MSI capability structure */ #define MC_MSI_CAP_CTRL_OFFSET 0xe0u -#define MC_MSI_MAX_Q_AVAIL (MC_NUM_MSI_IRQS_CODED << 1) -#define MC_MSI_Q_SIZE (MC_NUM_MSI_IRQS_CODED << 4) /* Events */ #define EVENT_PCIE_L2_EXIT 0 @@ -259,7 +261,7 @@ struct mc_msi { struct irq_domain *dev_domain; u32 num_vectors; u64 vector_phy; - DECLARE_BITMAP(used, MC_NUM_MSI_IRQS); + DECLARE_BITMAP(used, MC_MAX_NUM_MSI_IRQS); }; struct mc_pcie { @@ -382,25 +384,27 @@ static struct { static char poss_clks[][5] = { "fic0", "fic1", "fic2", "fic3" }; -static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *base) +static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam) { struct mc_msi *msi = &port->msi; - u32 cap_offset = MC_MSI_CAP_CTRL_OFFSET; - u16 msg_ctrl = readw_relaxed(base + cap_offset + PCI_MSI_FLAGS); + u16 reg; + u8 queue_size; - msg_ctrl |= PCI_MSI_FLAGS_ENABLE; - msg_ctrl &= ~PCI_MSI_FLAGS_QMASK; - msg_ctrl |= MC_MSI_MAX_Q_AVAIL; - msg_ctrl &= ~PCI_MSI_FLAGS_QSIZE; - msg_ctrl |= MC_MSI_Q_SIZE; - msg_ctrl |= PCI_MSI_FLAGS_64BIT; + /* Fixup MSI enable flag */ + reg = readw_relaxed(ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS); + reg |= PCI_MSI_FLAGS_ENABLE; + writew_relaxed(reg, ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS); - writew_relaxed(msg_ctrl, base + cap_offset + PCI_MSI_FLAGS); + /* Fixup PCI MSI queue flags */ + queue_size = FIELD_GET(PCI_MSI_FLAGS_QMASK, reg); + reg |= FIELD_PREP(PCI_MSI_FLAGS_QSIZE, queue_size); + writew_relaxed(reg, ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS); + /* Fixup MSI addr fields */ writel_relaxed(lower_32_bits(msi->vector_phy), - base + cap_offset + PCI_MSI_ADDRESS_LO); + ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_LO); writel_relaxed(upper_32_bits(msi->vector_phy), - base + cap_offset + PCI_MSI_ADDRESS_HI); + ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI); } static void mc_handle_msi(struct irq_desc *desc) @@ -473,10 +477,7 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq, { struct mc_pcie *port = domain->host_data; struct mc_msi *msi = &port->msi; - void __iomem *bridge_base_addr = - port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; unsigned long bit; - u32 val; mutex_lock(&msi->lock); bit = find_first_zero_bit(msi->used, msi->num_vectors); @@ -490,11 +491,6 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_domain_set_info(domain, virq, bit, &mc_msi_bottom_irq_chip, domain->host_data, handle_edge_irq, NULL, NULL); - /* Enable MSI interrupts */ - val = readl_relaxed(bridge_base_addr + IMASK_LOCAL); - val |= PM_MSI_INT_MSI_MASK; - writel_relaxed(val, bridge_base_addr + IMASK_LOCAL); - mutex_unlock(&msi->lock); return 0; @@ -1111,6 +1107,7 @@ static int mc_platform_init(struct pci_config_window *cfg) struct mc_pcie *port; void __iomem *bridge_base_addr; int ret; + u32 val; port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); if (!port) @@ -1131,12 +1128,24 @@ static int mc_platform_init(struct pci_config_window *cfg) bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; - port->msi.vector_phy = MSI_ADDR; - port->msi.num_vectors = MC_NUM_MSI_IRQS; + /* Allow enabling MSI by disabling MSI-X */ + val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0); + val &= ~MSIX_CAP_MASK; + writel(val, bridge_base_addr + PCIE_PCI_IRQ_DW0); /* Hardware doesn't setup MSI by default */ mc_pcie_enable_msi(port, cfg->win); + /* Pick num vectors from bitfile programmed onto FPGA fabric */ + val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0); + val &= NUM_MSI_MSGS_MASK; + val >>= NUM_MSI_MSGS_SHIFT; + + port->msi.num_vectors = 1 << val; + + /* Pick vector address from design */ + port->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR); + /* Configure Address Translation Table 0 for PCIe config space */ mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start & 0xffffffff, cfg->res.start, resource_size(&cfg->res)); -- cgit v1.2.3 From bac406c34fbc906f09479af72cb6a908a5d1db1d Mon Sep 17 00:00:00 2001 From: Daire McNamara Date: Fri, 28 Jul 2023 14:14:01 +0100 Subject: PCI: microchip: Re-partition code between probe() and init() Continuing to use pci_host_common_probe() for the PCIe Root Complex on PolarFire SoC is leading to an extremely large _init() function and some unnatural code flow. Re-partition the code so that some tasks are done in a _probe() routine, which calls pci_host_common_probe() and then use a much smaller _init() function, mainly to enable interrupts after address translation tables are set up. Link: https://lore.kernel.org/r/20230728131401.1615724-8-daire.mcnamara@microchip.com Signed-off-by: Daire McNamara Signed-off-by: Lorenzo Pieralisi Reviewed-by: Conor Dooley --- drivers/pci/controller/pcie-microchip-host.c | 58 ++++++++++++++++++---------- 1 file changed, 38 insertions(+), 20 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c index ca13fd56a0d9..252aff180ca2 100644 --- a/drivers/pci/controller/pcie-microchip-host.c +++ b/drivers/pci/controller/pcie-microchip-host.c @@ -384,6 +384,8 @@ static struct { static char poss_clks[][5] = { "fic0", "fic1", "fic2", "fic3" }; +static struct mc_pcie *port; + static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam) { struct mc_msi *msi = &port->msi; @@ -1104,7 +1106,34 @@ static int mc_platform_init(struct pci_config_window *cfg) { struct device *dev = cfg->parent; struct platform_device *pdev = to_platform_device(dev); - struct mc_pcie *port; + void __iomem *bridge_base_addr = + port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; + int ret; + + /* Configure address translation table 0 for PCIe config space */ + mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start, + cfg->res.start, + resource_size(&cfg->res)); + + /* Need some fixups in config space */ + mc_pcie_enable_msi(port, cfg->win); + + /* Configure non-config space outbound ranges */ + ret = mc_pcie_setup_windows(pdev, port); + if (ret) + return ret; + + /* Address translation is up; safe to enable interrupts */ + ret = mc_init_interrupts(pdev, port); + if (ret) + return ret; + + return 0; +} + +static int mc_host_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; void __iomem *bridge_base_addr; int ret; u32 val; @@ -1112,13 +1141,8 @@ static int mc_platform_init(struct pci_config_window *cfg) port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; - port->dev = dev; - ret = mc_pcie_init_clks(dev); - if (ret) { - dev_err(dev, "failed to get clock resources, error %d\n", ret); - return -ENODEV; - } + port->dev = dev; port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(port->axi_base_addr)) @@ -1133,9 +1157,6 @@ static int mc_platform_init(struct pci_config_window *cfg) val &= ~MSIX_CAP_MASK; writel(val, bridge_base_addr + PCIE_PCI_IRQ_DW0); - /* Hardware doesn't setup MSI by default */ - mc_pcie_enable_msi(port, cfg->win); - /* Pick num vectors from bitfile programmed onto FPGA fabric */ val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0); val &= NUM_MSI_MSGS_MASK; @@ -1146,16 +1167,13 @@ static int mc_platform_init(struct pci_config_window *cfg) /* Pick vector address from design */ port->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR); - /* Configure Address Translation Table 0 for PCIe config space */ - mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start & 0xffffffff, - cfg->res.start, resource_size(&cfg->res)); - - ret = mc_pcie_setup_windows(pdev, port); - if (ret) - return ret; + ret = mc_pcie_init_clks(dev); + if (ret) { + dev_err(dev, "failed to get clock resources, error %d\n", ret); + return -ENODEV; + } - /* Address translation is up; safe to enable interrupts */ - return mc_init_interrupts(pdev, port); + return pci_host_common_probe(pdev); } static const struct pci_ecam_ops mc_ecam_ops = { @@ -1178,7 +1196,7 @@ static const struct of_device_id mc_pcie_of_match[] = { MODULE_DEVICE_TABLE(of, mc_pcie_of_match); static struct platform_driver mc_pcie_driver = { - .probe = pci_host_common_probe, + .probe = mc_host_probe, .driver = { .name = "microchip-pcie", .of_match_table = mc_pcie_of_match, -- cgit v1.2.3 From fc8b24c28bec19fc0621d108b9ee81ddfdedb25a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 Jul 2023 12:55:01 +0100 Subject: PCI: dwc: Provide deinit callback for i.MX The i.MX integration for the DesignWare PCI controller has a _host_exit() operation which undoes everything that the _host_init() operation does but does not wire this up as the host_deinit callback for the core, or call it in any path other than suspend. This means that if we ever unwind the initial probe of the device, for example because it fails, the regulator core complains that the regulators for the device were left enabled: imx6q-pcie 33800000.pcie: iATU: unroll T, 4 ob, 4 ib, align 64K, limit 16G imx6q-pcie 33800000.pcie: Phy link never came up imx6q-pcie 33800000.pcie: Phy link never came up imx6q-pcie: probe of 33800000.pcie failed with error -110 ------------[ cut here ]------------ WARNING: CPU: 2 PID: 46 at drivers/regulator/core.c:2396 _regulator_put+0x110/0x128 Wire up the callback so that the core can clean up after itself. Link: https://lore.kernel.org/r/20230731-pci-imx-regulator-cleanup-v2-1-fc8fa5c9893d@kernel.org Tested-by: Fabio Estevam Signed-off-by: Mark Brown Signed-off-by: Lorenzo Pieralisi Reviewed-by: Richard Zhu Acked-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pci-imx6.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 27aaa2a6bf39..a18c20085e94 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1040,6 +1040,7 @@ static void imx6_pcie_host_exit(struct dw_pcie_rp *pp) static const struct dw_pcie_host_ops imx6_pcie_host_ops = { .host_init = imx6_pcie_host_init, + .host_deinit = imx6_pcie_host_exit, }; static const struct dw_pcie_ops dw_pcie_ops = { -- cgit v1.2.3 From 846691f5483d61259db2f4d6a3dce8b98d518794 Mon Sep 17 00:00:00 2001 From: Kelvin Cao Date: Fri, 23 Jun 2023 17:00:02 -0700 Subject: PCI: switchtec: Use normal comment style Use normal comment style '/* */' for device ID description. Link: https://lore.kernel.org/r/20230624000003.2315364-2-kelvin.cao@microchip.com Signed-off-by: Kelvin Cao Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe --- drivers/pci/switch/switchtec.c | 114 ++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 57 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index d837da055921..941e8e9cff96 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1727,63 +1727,63 @@ static void switchtec_pci_remove(struct pci_dev *pdev) } static const struct pci_device_id switchtec_pci_tbl[] = { - SWITCHTEC_PCI_DEVICE(0x8531, SWITCHTEC_GEN3), //PFX 24xG3 - SWITCHTEC_PCI_DEVICE(0x8532, SWITCHTEC_GEN3), //PFX 32xG3 - SWITCHTEC_PCI_DEVICE(0x8533, SWITCHTEC_GEN3), //PFX 48xG3 - SWITCHTEC_PCI_DEVICE(0x8534, SWITCHTEC_GEN3), //PFX 64xG3 - SWITCHTEC_PCI_DEVICE(0x8535, SWITCHTEC_GEN3), //PFX 80xG3 - SWITCHTEC_PCI_DEVICE(0x8536, SWITCHTEC_GEN3), //PFX 96xG3 - SWITCHTEC_PCI_DEVICE(0x8541, SWITCHTEC_GEN3), //PSX 24xG3 - SWITCHTEC_PCI_DEVICE(0x8542, SWITCHTEC_GEN3), //PSX 32xG3 - SWITCHTEC_PCI_DEVICE(0x8543, SWITCHTEC_GEN3), //PSX 48xG3 - SWITCHTEC_PCI_DEVICE(0x8544, SWITCHTEC_GEN3), //PSX 64xG3 - SWITCHTEC_PCI_DEVICE(0x8545, SWITCHTEC_GEN3), //PSX 80xG3 - SWITCHTEC_PCI_DEVICE(0x8546, SWITCHTEC_GEN3), //PSX 96xG3 - SWITCHTEC_PCI_DEVICE(0x8551, SWITCHTEC_GEN3), //PAX 24XG3 - SWITCHTEC_PCI_DEVICE(0x8552, SWITCHTEC_GEN3), //PAX 32XG3 - SWITCHTEC_PCI_DEVICE(0x8553, SWITCHTEC_GEN3), //PAX 48XG3 - SWITCHTEC_PCI_DEVICE(0x8554, SWITCHTEC_GEN3), //PAX 64XG3 - SWITCHTEC_PCI_DEVICE(0x8555, SWITCHTEC_GEN3), //PAX 80XG3 - SWITCHTEC_PCI_DEVICE(0x8556, SWITCHTEC_GEN3), //PAX 96XG3 - SWITCHTEC_PCI_DEVICE(0x8561, SWITCHTEC_GEN3), //PFXL 24XG3 - SWITCHTEC_PCI_DEVICE(0x8562, SWITCHTEC_GEN3), //PFXL 32XG3 - SWITCHTEC_PCI_DEVICE(0x8563, SWITCHTEC_GEN3), //PFXL 48XG3 - SWITCHTEC_PCI_DEVICE(0x8564, SWITCHTEC_GEN3), //PFXL 64XG3 - SWITCHTEC_PCI_DEVICE(0x8565, SWITCHTEC_GEN3), //PFXL 80XG3 - SWITCHTEC_PCI_DEVICE(0x8566, SWITCHTEC_GEN3), //PFXL 96XG3 - SWITCHTEC_PCI_DEVICE(0x8571, SWITCHTEC_GEN3), //PFXI 24XG3 - SWITCHTEC_PCI_DEVICE(0x8572, SWITCHTEC_GEN3), //PFXI 32XG3 - SWITCHTEC_PCI_DEVICE(0x8573, SWITCHTEC_GEN3), //PFXI 48XG3 - SWITCHTEC_PCI_DEVICE(0x8574, SWITCHTEC_GEN3), //PFXI 64XG3 - SWITCHTEC_PCI_DEVICE(0x8575, SWITCHTEC_GEN3), //PFXI 80XG3 - SWITCHTEC_PCI_DEVICE(0x8576, SWITCHTEC_GEN3), //PFXI 96XG3 - SWITCHTEC_PCI_DEVICE(0x4000, SWITCHTEC_GEN4), //PFX 100XG4 - SWITCHTEC_PCI_DEVICE(0x4084, SWITCHTEC_GEN4), //PFX 84XG4 - SWITCHTEC_PCI_DEVICE(0x4068, SWITCHTEC_GEN4), //PFX 68XG4 - SWITCHTEC_PCI_DEVICE(0x4052, SWITCHTEC_GEN4), //PFX 52XG4 - SWITCHTEC_PCI_DEVICE(0x4036, SWITCHTEC_GEN4), //PFX 36XG4 - SWITCHTEC_PCI_DEVICE(0x4028, SWITCHTEC_GEN4), //PFX 28XG4 - SWITCHTEC_PCI_DEVICE(0x4100, SWITCHTEC_GEN4), //PSX 100XG4 - SWITCHTEC_PCI_DEVICE(0x4184, SWITCHTEC_GEN4), //PSX 84XG4 - SWITCHTEC_PCI_DEVICE(0x4168, SWITCHTEC_GEN4), //PSX 68XG4 - SWITCHTEC_PCI_DEVICE(0x4152, SWITCHTEC_GEN4), //PSX 52XG4 - SWITCHTEC_PCI_DEVICE(0x4136, SWITCHTEC_GEN4), //PSX 36XG4 - SWITCHTEC_PCI_DEVICE(0x4128, SWITCHTEC_GEN4), //PSX 28XG4 - SWITCHTEC_PCI_DEVICE(0x4200, SWITCHTEC_GEN4), //PAX 100XG4 - SWITCHTEC_PCI_DEVICE(0x4284, SWITCHTEC_GEN4), //PAX 84XG4 - SWITCHTEC_PCI_DEVICE(0x4268, SWITCHTEC_GEN4), //PAX 68XG4 - SWITCHTEC_PCI_DEVICE(0x4252, SWITCHTEC_GEN4), //PAX 52XG4 - SWITCHTEC_PCI_DEVICE(0x4236, SWITCHTEC_GEN4), //PAX 36XG4 - SWITCHTEC_PCI_DEVICE(0x4228, SWITCHTEC_GEN4), //PAX 28XG4 - SWITCHTEC_PCI_DEVICE(0x4352, SWITCHTEC_GEN4), //PFXA 52XG4 - SWITCHTEC_PCI_DEVICE(0x4336, SWITCHTEC_GEN4), //PFXA 36XG4 - SWITCHTEC_PCI_DEVICE(0x4328, SWITCHTEC_GEN4), //PFXA 28XG4 - SWITCHTEC_PCI_DEVICE(0x4452, SWITCHTEC_GEN4), //PSXA 52XG4 - SWITCHTEC_PCI_DEVICE(0x4436, SWITCHTEC_GEN4), //PSXA 36XG4 - SWITCHTEC_PCI_DEVICE(0x4428, SWITCHTEC_GEN4), //PSXA 28XG4 - SWITCHTEC_PCI_DEVICE(0x4552, SWITCHTEC_GEN4), //PAXA 52XG4 - SWITCHTEC_PCI_DEVICE(0x4536, SWITCHTEC_GEN4), //PAXA 36XG4 - SWITCHTEC_PCI_DEVICE(0x4528, SWITCHTEC_GEN4), //PAXA 28XG4 + SWITCHTEC_PCI_DEVICE(0x8531, SWITCHTEC_GEN3), /* PFX 24xG3 */ + SWITCHTEC_PCI_DEVICE(0x8532, SWITCHTEC_GEN3), /* PFX 32xG3 */ + SWITCHTEC_PCI_DEVICE(0x8533, SWITCHTEC_GEN3), /* PFX 48xG3 */ + SWITCHTEC_PCI_DEVICE(0x8534, SWITCHTEC_GEN3), /* PFX 64xG3 */ + SWITCHTEC_PCI_DEVICE(0x8535, SWITCHTEC_GEN3), /* PFX 80xG3 */ + SWITCHTEC_PCI_DEVICE(0x8536, SWITCHTEC_GEN3), /* PFX 96xG3 */ + SWITCHTEC_PCI_DEVICE(0x8541, SWITCHTEC_GEN3), /* PSX 24xG3 */ + SWITCHTEC_PCI_DEVICE(0x8542, SWITCHTEC_GEN3), /* PSX 32xG3 */ + SWITCHTEC_PCI_DEVICE(0x8543, SWITCHTEC_GEN3), /* PSX 48xG3 */ + SWITCHTEC_PCI_DEVICE(0x8544, SWITCHTEC_GEN3), /* PSX 64xG3 */ + SWITCHTEC_PCI_DEVICE(0x8545, SWITCHTEC_GEN3), /* PSX 80xG3 */ + SWITCHTEC_PCI_DEVICE(0x8546, SWITCHTEC_GEN3), /* PSX 96xG3 */ + SWITCHTEC_PCI_DEVICE(0x8551, SWITCHTEC_GEN3), /* PAX 24XG3 */ + SWITCHTEC_PCI_DEVICE(0x8552, SWITCHTEC_GEN3), /* PAX 32XG3 */ + SWITCHTEC_PCI_DEVICE(0x8553, SWITCHTEC_GEN3), /* PAX 48XG3 */ + SWITCHTEC_PCI_DEVICE(0x8554, SWITCHTEC_GEN3), /* PAX 64XG3 */ + SWITCHTEC_PCI_DEVICE(0x8555, SWITCHTEC_GEN3), /* PAX 80XG3 */ + SWITCHTEC_PCI_DEVICE(0x8556, SWITCHTEC_GEN3), /* PAX 96XG3 */ + SWITCHTEC_PCI_DEVICE(0x8561, SWITCHTEC_GEN3), /* PFXL 24XG3 */ + SWITCHTEC_PCI_DEVICE(0x8562, SWITCHTEC_GEN3), /* PFXL 32XG3 */ + SWITCHTEC_PCI_DEVICE(0x8563, SWITCHTEC_GEN3), /* PFXL 48XG3 */ + SWITCHTEC_PCI_DEVICE(0x8564, SWITCHTEC_GEN3), /* PFXL 64XG3 */ + SWITCHTEC_PCI_DEVICE(0x8565, SWITCHTEC_GEN3), /* PFXL 80XG3 */ + SWITCHTEC_PCI_DEVICE(0x8566, SWITCHTEC_GEN3), /* PFXL 96XG3 */ + SWITCHTEC_PCI_DEVICE(0x8571, SWITCHTEC_GEN3), /* PFXI 24XG3 */ + SWITCHTEC_PCI_DEVICE(0x8572, SWITCHTEC_GEN3), /* PFXI 32XG3 */ + SWITCHTEC_PCI_DEVICE(0x8573, SWITCHTEC_GEN3), /* PFXI 48XG3 */ + SWITCHTEC_PCI_DEVICE(0x8574, SWITCHTEC_GEN3), /* PFXI 64XG3 */ + SWITCHTEC_PCI_DEVICE(0x8575, SWITCHTEC_GEN3), /* PFXI 80XG3 */ + SWITCHTEC_PCI_DEVICE(0x8576, SWITCHTEC_GEN3), /* PFXI 96XG3 */ + SWITCHTEC_PCI_DEVICE(0x4000, SWITCHTEC_GEN4), /* PFX 100XG4 */ + SWITCHTEC_PCI_DEVICE(0x4084, SWITCHTEC_GEN4), /* PFX 84XG4 */ + SWITCHTEC_PCI_DEVICE(0x4068, SWITCHTEC_GEN4), /* PFX 68XG4 */ + SWITCHTEC_PCI_DEVICE(0x4052, SWITCHTEC_GEN4), /* PFX 52XG4 */ + SWITCHTEC_PCI_DEVICE(0x4036, SWITCHTEC_GEN4), /* PFX 36XG4 */ + SWITCHTEC_PCI_DEVICE(0x4028, SWITCHTEC_GEN4), /* PFX 28XG4 */ + SWITCHTEC_PCI_DEVICE(0x4100, SWITCHTEC_GEN4), /* PSX 100XG4 */ + SWITCHTEC_PCI_DEVICE(0x4184, SWITCHTEC_GEN4), /* PSX 84XG4 */ + SWITCHTEC_PCI_DEVICE(0x4168, SWITCHTEC_GEN4), /* PSX 68XG4 */ + SWITCHTEC_PCI_DEVICE(0x4152, SWITCHTEC_GEN4), /* PSX 52XG4 */ + SWITCHTEC_PCI_DEVICE(0x4136, SWITCHTEC_GEN4), /* PSX 36XG4 */ + SWITCHTEC_PCI_DEVICE(0x4128, SWITCHTEC_GEN4), /* PSX 28XG4 */ + SWITCHTEC_PCI_DEVICE(0x4200, SWITCHTEC_GEN4), /* PAX 100XG4 */ + SWITCHTEC_PCI_DEVICE(0x4284, SWITCHTEC_GEN4), /* PAX 84XG4 */ + SWITCHTEC_PCI_DEVICE(0x4268, SWITCHTEC_GEN4), /* PAX 68XG4 */ + SWITCHTEC_PCI_DEVICE(0x4252, SWITCHTEC_GEN4), /* PAX 52XG4 */ + SWITCHTEC_PCI_DEVICE(0x4236, SWITCHTEC_GEN4), /* PAX 36XG4 */ + SWITCHTEC_PCI_DEVICE(0x4228, SWITCHTEC_GEN4), /* PAX 28XG4 */ + SWITCHTEC_PCI_DEVICE(0x4352, SWITCHTEC_GEN4), /* PFXA 52XG4 */ + SWITCHTEC_PCI_DEVICE(0x4336, SWITCHTEC_GEN4), /* PFXA 36XG4 */ + SWITCHTEC_PCI_DEVICE(0x4328, SWITCHTEC_GEN4), /* PFXA 28XG4 */ + SWITCHTEC_PCI_DEVICE(0x4452, SWITCHTEC_GEN4), /* PSXA 52XG4 */ + SWITCHTEC_PCI_DEVICE(0x4436, SWITCHTEC_GEN4), /* PSXA 36XG4 */ + SWITCHTEC_PCI_DEVICE(0x4428, SWITCHTEC_GEN4), /* PSXA 28XG4 */ + SWITCHTEC_PCI_DEVICE(0x4552, SWITCHTEC_GEN4), /* PAXA 52XG4 */ + SWITCHTEC_PCI_DEVICE(0x4536, SWITCHTEC_GEN4), /* PAXA 36XG4 */ + SWITCHTEC_PCI_DEVICE(0x4528, SWITCHTEC_GEN4), /* PAXA 28XG4 */ {0} }; MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl); -- cgit v1.2.3 From 0fb53e64705ae0fabd9593102e0f0e6812968802 Mon Sep 17 00:00:00 2001 From: Kelvin Cao Date: Fri, 23 Jun 2023 17:00:03 -0700 Subject: PCI: switchtec: Add support for PCIe Gen5 devices Advertise support of Gen5 devices in the driver's device ID table and add the same IDs for the switchtec quirks. Also update driver code to accommodate them. Link: https://lore.kernel.org/r/20230624000003.2315364-3-kelvin.cao@microchip.com Signed-off-by: Kelvin Cao Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe --- drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++ drivers/pci/switch/switchtec.c | 44 ++++++++++++++++++++++++++++++++++++++---- include/linux/switchtec.h | 1 + 3 files changed, 77 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 321156ca273d..953dc56bbd68 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5867,6 +5867,42 @@ SWITCHTEC_QUIRK(0x4428); /* PSXA 28XG4 */ SWITCHTEC_QUIRK(0x4552); /* PAXA 52XG4 */ SWITCHTEC_QUIRK(0x4536); /* PAXA 36XG4 */ SWITCHTEC_QUIRK(0x4528); /* PAXA 28XG4 */ +SWITCHTEC_QUIRK(0x5000); /* PFX 100XG5 */ +SWITCHTEC_QUIRK(0x5084); /* PFX 84XG5 */ +SWITCHTEC_QUIRK(0x5068); /* PFX 68XG5 */ +SWITCHTEC_QUIRK(0x5052); /* PFX 52XG5 */ +SWITCHTEC_QUIRK(0x5036); /* PFX 36XG5 */ +SWITCHTEC_QUIRK(0x5028); /* PFX 28XG5 */ +SWITCHTEC_QUIRK(0x5100); /* PSX 100XG5 */ +SWITCHTEC_QUIRK(0x5184); /* PSX 84XG5 */ +SWITCHTEC_QUIRK(0x5168); /* PSX 68XG5 */ +SWITCHTEC_QUIRK(0x5152); /* PSX 52XG5 */ +SWITCHTEC_QUIRK(0x5136); /* PSX 36XG5 */ +SWITCHTEC_QUIRK(0x5128); /* PSX 28XG5 */ +SWITCHTEC_QUIRK(0x5200); /* PAX 100XG5 */ +SWITCHTEC_QUIRK(0x5284); /* PAX 84XG5 */ +SWITCHTEC_QUIRK(0x5268); /* PAX 68XG5 */ +SWITCHTEC_QUIRK(0x5252); /* PAX 52XG5 */ +SWITCHTEC_QUIRK(0x5236); /* PAX 36XG5 */ +SWITCHTEC_QUIRK(0x5228); /* PAX 28XG5 */ +SWITCHTEC_QUIRK(0x5300); /* PFXA 100XG5 */ +SWITCHTEC_QUIRK(0x5384); /* PFXA 84XG5 */ +SWITCHTEC_QUIRK(0x5368); /* PFXA 68XG5 */ +SWITCHTEC_QUIRK(0x5352); /* PFXA 52XG5 */ +SWITCHTEC_QUIRK(0x5336); /* PFXA 36XG5 */ +SWITCHTEC_QUIRK(0x5328); /* PFXA 28XG5 */ +SWITCHTEC_QUIRK(0x5400); /* PSXA 100XG5 */ +SWITCHTEC_QUIRK(0x5484); /* PSXA 84XG5 */ +SWITCHTEC_QUIRK(0x5468); /* PSXA 68XG5 */ +SWITCHTEC_QUIRK(0x5452); /* PSXA 52XG5 */ +SWITCHTEC_QUIRK(0x5436); /* PSXA 36XG5 */ +SWITCHTEC_QUIRK(0x5428); /* PSXA 28XG5 */ +SWITCHTEC_QUIRK(0x5500); /* PAXA 100XG5 */ +SWITCHTEC_QUIRK(0x5584); /* PAXA 84XG5 */ +SWITCHTEC_QUIRK(0x5568); /* PAXA 68XG5 */ +SWITCHTEC_QUIRK(0x5552); /* PAXA 52XG5 */ +SWITCHTEC_QUIRK(0x5536); /* PAXA 36XG5 */ +SWITCHTEC_QUIRK(0x5528); /* PAXA 28XG5 */ /* * The PLX NTB uses devfn proxy IDs to move TLPs between NT endpoints. diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 941e8e9cff96..5b921387eca6 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -372,7 +372,7 @@ static ssize_t field ## _show(struct device *dev, \ if (stdev->gen == SWITCHTEC_GEN3) \ return io_string_show(buf, &si->gen3.field, \ sizeof(si->gen3.field)); \ - else if (stdev->gen == SWITCHTEC_GEN4) \ + else if (stdev->gen >= SWITCHTEC_GEN4) \ return io_string_show(buf, &si->gen4.field, \ sizeof(si->gen4.field)); \ else \ @@ -663,7 +663,7 @@ static int ioctl_flash_info(struct switchtec_dev *stdev, if (stdev->gen == SWITCHTEC_GEN3) { info.flash_length = ioread32(&fi->gen3.flash_length); info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN3; - } else if (stdev->gen == SWITCHTEC_GEN4) { + } else if (stdev->gen >= SWITCHTEC_GEN4) { info.flash_length = ioread32(&fi->gen4.flash_length); info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN4; } else { @@ -870,7 +870,7 @@ static int ioctl_flash_part_info(struct switchtec_dev *stdev, ret = flash_part_info_gen3(stdev, &info); if (ret) return ret; - } else if (stdev->gen == SWITCHTEC_GEN4) { + } else if (stdev->gen >= SWITCHTEC_GEN4) { ret = flash_part_info_gen4(stdev, &info); if (ret) return ret; @@ -1610,7 +1610,7 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, if (stdev->gen == SWITCHTEC_GEN3) part_id = &stdev->mmio_sys_info->gen3.partition_id; - else if (stdev->gen == SWITCHTEC_GEN4) + else if (stdev->gen >= SWITCHTEC_GEN4) part_id = &stdev->mmio_sys_info->gen4.partition_id; else return -EOPNOTSUPP; @@ -1784,6 +1784,42 @@ static const struct pci_device_id switchtec_pci_tbl[] = { SWITCHTEC_PCI_DEVICE(0x4552, SWITCHTEC_GEN4), /* PAXA 52XG4 */ SWITCHTEC_PCI_DEVICE(0x4536, SWITCHTEC_GEN4), /* PAXA 36XG4 */ SWITCHTEC_PCI_DEVICE(0x4528, SWITCHTEC_GEN4), /* PAXA 28XG4 */ + SWITCHTEC_PCI_DEVICE(0x5000, SWITCHTEC_GEN5), /* PFX 100XG5 */ + SWITCHTEC_PCI_DEVICE(0x5084, SWITCHTEC_GEN5), /* PFX 84XG5 */ + SWITCHTEC_PCI_DEVICE(0x5068, SWITCHTEC_GEN5), /* PFX 68XG5 */ + SWITCHTEC_PCI_DEVICE(0x5052, SWITCHTEC_GEN5), /* PFX 52XG5 */ + SWITCHTEC_PCI_DEVICE(0x5036, SWITCHTEC_GEN5), /* PFX 36XG5 */ + SWITCHTEC_PCI_DEVICE(0x5028, SWITCHTEC_GEN5), /* PFX 28XG5 */ + SWITCHTEC_PCI_DEVICE(0x5100, SWITCHTEC_GEN5), /* PSX 100XG5 */ + SWITCHTEC_PCI_DEVICE(0x5184, SWITCHTEC_GEN5), /* PSX 84XG5 */ + SWITCHTEC_PCI_DEVICE(0x5168, SWITCHTEC_GEN5), /* PSX 68XG5 */ + SWITCHTEC_PCI_DEVICE(0x5152, SWITCHTEC_GEN5), /* PSX 52XG5 */ + SWITCHTEC_PCI_DEVICE(0x5136, SWITCHTEC_GEN5), /* PSX 36XG5 */ + SWITCHTEC_PCI_DEVICE(0x5128, SWITCHTEC_GEN5), /* PSX 28XG5 */ + SWITCHTEC_PCI_DEVICE(0x5200, SWITCHTEC_GEN5), /* PAX 100XG5 */ + SWITCHTEC_PCI_DEVICE(0x5284, SWITCHTEC_GEN5), /* PAX 84XG5 */ + SWITCHTEC_PCI_DEVICE(0x5268, SWITCHTEC_GEN5), /* PAX 68XG5 */ + SWITCHTEC_PCI_DEVICE(0x5252, SWITCHTEC_GEN5), /* PAX 52XG5 */ + SWITCHTEC_PCI_DEVICE(0x5236, SWITCHTEC_GEN5), /* PAX 36XG5 */ + SWITCHTEC_PCI_DEVICE(0x5228, SWITCHTEC_GEN5), /* PAX 28XG5 */ + SWITCHTEC_PCI_DEVICE(0x5300, SWITCHTEC_GEN5), /* PFXA 100XG5 */ + SWITCHTEC_PCI_DEVICE(0x5384, SWITCHTEC_GEN5), /* PFXA 84XG5 */ + SWITCHTEC_PCI_DEVICE(0x5368, SWITCHTEC_GEN5), /* PFXA 68XG5 */ + SWITCHTEC_PCI_DEVICE(0x5352, SWITCHTEC_GEN5), /* PFXA 52XG5 */ + SWITCHTEC_PCI_DEVICE(0x5336, SWITCHTEC_GEN5), /* PFXA 36XG5 */ + SWITCHTEC_PCI_DEVICE(0x5328, SWITCHTEC_GEN5), /* PFXA 28XG5 */ + SWITCHTEC_PCI_DEVICE(0x5400, SWITCHTEC_GEN5), /* PSXA 100XG5 */ + SWITCHTEC_PCI_DEVICE(0x5484, SWITCHTEC_GEN5), /* PSXA 84XG5 */ + SWITCHTEC_PCI_DEVICE(0x5468, SWITCHTEC_GEN5), /* PSXA 68XG5 */ + SWITCHTEC_PCI_DEVICE(0x5452, SWITCHTEC_GEN5), /* PSXA 52XG5 */ + SWITCHTEC_PCI_DEVICE(0x5436, SWITCHTEC_GEN5), /* PSXA 36XG5 */ + SWITCHTEC_PCI_DEVICE(0x5428, SWITCHTEC_GEN5), /* PSXA 28XG5 */ + SWITCHTEC_PCI_DEVICE(0x5500, SWITCHTEC_GEN5), /* PAXA 100XG5 */ + SWITCHTEC_PCI_DEVICE(0x5584, SWITCHTEC_GEN5), /* PAXA 84XG5 */ + SWITCHTEC_PCI_DEVICE(0x5568, SWITCHTEC_GEN5), /* PAXA 68XG5 */ + SWITCHTEC_PCI_DEVICE(0x5552, SWITCHTEC_GEN5), /* PAXA 52XG5 */ + SWITCHTEC_PCI_DEVICE(0x5536, SWITCHTEC_GEN5), /* PAXA 36XG5 */ + SWITCHTEC_PCI_DEVICE(0x5528, SWITCHTEC_GEN5), /* PAXA 28XG5 */ {0} }; MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl); diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index 48fabe36509e..8d8fac1626bd 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -41,6 +41,7 @@ enum { enum switchtec_gen { SWITCHTEC_GEN3, SWITCHTEC_GEN4, + SWITCHTEC_GEN5, }; struct mrpc_regs { -- cgit v1.2.3 From d5af729dc2071273f14cbb94abbc60608142fd83 Mon Sep 17 00:00:00 2001 From: Wu Zongyong Date: Mon, 10 Apr 2023 20:34:11 +0800 Subject: PCI: Mark NVIDIA T4 GPUs to avoid bus reset NVIDIA T4 GPUs do not work with SBR. This problem is found when the T4 card is direct attached to a Root Port only. Avoid bus reset by marking T4 GPUs PCI_DEV_FLAGS_NO_BUS_RESET. Fixes: 4c207e7121fa ("PCI: Mark some NVIDIA GPUs to avoid bus reset") Link: https://lore.kernel.org/r/2dcebea53a6eb9bd212ec6d8974af2e5e0333ef6.1681129861.git.wuzongyong@linux.alibaba.com Signed-off-by: Wu Zongyong Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 321156ca273d..dc96a126aad4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3724,7 +3724,7 @@ static void quirk_no_bus_reset(struct pci_dev *dev) */ static void quirk_nvidia_no_bus_reset(struct pci_dev *dev) { - if ((dev->device & 0xffc0) == 0x2340) + if ((dev->device & 0xffc0) == 0x2340 || dev->device == 0x1eb8) quirk_no_bus_reset(dev); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, -- cgit v1.2.3 From 5e70d0acf0825f439079736080350371f8d6699a Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 17 Jul 2023 15:04:53 +0300 Subject: PCI: Add locking to RMW PCI Express Capability Register accessors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many places in the kernel write the Link Control and Root Control PCI Express Capability Registers without proper concurrency control and this could result in losing the changes one of the writers intended to make. Add pcie_cap_lock spinlock into the struct pci_dev and use it to protect bit changes made in the RMW capability accessors. Protect only a selected set of registers by differentiating the RMW accessor internally to locked/unlocked variants using a wrapper which has the same signature as pcie_capability_clear_and_set_word(). As the Capability Register (pos) given to the wrapper is always a constant, the compiler should be able to simplify all the dead-code away. So far only the Link Control Register (ASPM, hotplug, link retraining, various drivers) and the Root Control Register (AER & PME) seem to require RMW locking. Suggested-by: Lukas Wunner Fixes: c7f486567c1d ("PCI PM: PCIe PME root port service driver") Fixes: f12eb72a268b ("PCI/ASPM: Use PCI Express Capability accessors") Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") Fixes: affa48de8417 ("staging/rdma/hfi1: Add support for enabling/disabling PCIe ASPM") Fixes: 849a9366cba9 ("misc: rtsx: Add support new chip rts5228 mmc: rtsx: Add support MMC_CAP2_NO_MMC") Fixes: 3d1e7aa80d1c ("misc: rtsx: Use pcie_capability_clear_and_set_word() for PCI_EXP_LNKCTL") Fixes: c0e5f4e73a71 ("misc: rtsx: Add support for RTS5261") Fixes: 3df4fce739e2 ("misc: rtsx: separate aspm mode into MODE_REG and MODE_CFG") Fixes: 121e9c6b5c4c ("misc: rtsx: modify and fix init_hw function") Fixes: 19f3bd548f27 ("mfd: rtsx: Remove LCTLR defination") Fixes: 773ccdfd9cc6 ("mfd: rtsx: Read vendor setting from config space") Fixes: 8275b77a1513 ("mfd: rts5249: Add support for RTS5250S power saving") Fixes: 5da4e04ae480 ("misc: rtsx: Add support for RTS5260") Fixes: 0f49bfbd0f2e ("tg3: Use PCI Express Capability accessors") Fixes: 5e7dfd0fb94a ("tg3: Prevent corruption at 10 / 100Mbps w CLKREQ") Fixes: b726e493e8dc ("r8169: sync existing 8168 device hardware start sequences with vendor driver") Fixes: e6de30d63eb1 ("r8169: more 8168dp support.") Fixes: 8a06127602de ("Bluetooth: hci_bcm4377: Add new driver for BCM4377 PCIe boards") Fixes: 6f461f6c7c96 ("e1000e: enable/disable ASPM L0s and L1 and ERT according to hardware errata") Fixes: 1eae4eb2a1c7 ("e1000e: Disable L1 ASPM power savings for 82573 mobile variants") Fixes: 8060e169e02f ("ath9k: Enable extended synch for AR9485 to fix L0s recovery issue") Fixes: 69ce674bfa69 ("ath9k: do btcoex ASPM disabling at initialization time") Fixes: f37f05503575 ("mt76: mt76x2e: disable pcie_aspm by default") Link: https://lore.kernel.org/r/20230717120503.15276-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Reviewed-by: "Rafael J. Wysocki" --- drivers/pci/access.c | 20 +++++++++++++++++--- drivers/pci/probe.c | 1 + include/linux/pci.h | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 3c230ca3de58..0b2e90d2f04f 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -497,8 +497,8 @@ int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val) } EXPORT_SYMBOL(pcie_capability_write_dword); -int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, - u16 clear, u16 set) +int pcie_capability_clear_and_set_word_unlocked(struct pci_dev *dev, int pos, + u16 clear, u16 set) { int ret; u16 val; @@ -512,7 +512,21 @@ int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, return ret; } -EXPORT_SYMBOL(pcie_capability_clear_and_set_word); +EXPORT_SYMBOL(pcie_capability_clear_and_set_word_unlocked); + +int pcie_capability_clear_and_set_word_locked(struct pci_dev *dev, int pos, + u16 clear, u16 set) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&dev->pcie_cap_lock, flags); + ret = pcie_capability_clear_and_set_word_unlocked(dev, pos, clear, set); + spin_unlock_irqrestore(&dev->pcie_cap_lock, flags); + + return ret; +} +EXPORT_SYMBOL(pcie_capability_clear_and_set_word_locked); int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, u32 clear, u32 set) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8bac3ce02609..f1587fb0ba71 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2324,6 +2324,7 @@ struct pci_dev *pci_alloc_dev(struct pci_bus *bus) .end = -1, }; + spin_lock_init(&dev->pcie_cap_lock); #ifdef CONFIG_PCI_MSI raw_spin_lock_init(&dev->msi_lock); #endif diff --git a/include/linux/pci.h b/include/linux/pci.h index c69a2cc1f412..7ee498cd1f37 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -467,6 +467,7 @@ struct pci_dev { pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ + spinlock_t pcie_cap_lock; /* Protects RMW ops in capability accessors */ u32 saved_config_space[16]; /* Config space saved at suspend time */ struct hlist_head saved_cap_space; int rom_attr_enabled; /* Display of ROM attribute enabled? */ @@ -1217,11 +1218,40 @@ int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val); int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val); int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val); int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val); -int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, - u16 clear, u16 set); +int pcie_capability_clear_and_set_word_unlocked(struct pci_dev *dev, int pos, + u16 clear, u16 set); +int pcie_capability_clear_and_set_word_locked(struct pci_dev *dev, int pos, + u16 clear, u16 set); int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, u32 clear, u32 set); +/** + * pcie_capability_clear_and_set_word - RMW accessor for PCI Express Capability Registers + * @dev: PCI device structure of the PCI Express device + * @pos: PCI Express Capability Register + * @clear: Clear bitmask + * @set: Set bitmask + * + * Perform a Read-Modify-Write (RMW) operation using @clear and @set + * bitmasks on PCI Express Capability Register at @pos. Certain PCI Express + * Capability Registers are accessed concurrently in RMW fashion, hence + * require locking which is handled transparently to the caller. + */ +static inline int pcie_capability_clear_and_set_word(struct pci_dev *dev, + int pos, + u16 clear, u16 set) +{ + switch (pos) { + case PCI_EXP_LNKCTL: + case PCI_EXP_RTCTL: + return pcie_capability_clear_and_set_word_locked(dev, pos, + clear, set); + default: + return pcie_capability_clear_and_set_word_unlocked(dev, pos, + clear, set); + } +} + static inline int pcie_capability_set_word(struct pci_dev *dev, int pos, u16 set) { -- cgit v1.2.3 From fb0171a4c01b4825e36a5584eaa84291179c64ce Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 17 Jul 2023 15:04:54 +0300 Subject: PCI: Make link retraining use RMW accessors for changing LNKCTL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't assume that the device is fully under the control of PCI core. Use RMW capability accessors in link retraining which do proper locking to avoid losing concurrent updates to the register values. Suggested-by: Lukas Wunner Fixes: 4ec73791a64b ("PCI: Work around Pericom PCIe-to-PCI bridge Retrain Link erratum") Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") Link: https://lore.kernel.org/r/20230717120503.15276-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Acked-by: "Rafael J. Wysocki" --- drivers/pci/pci.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 60230da957e0..f7315b13bb82 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4927,7 +4927,6 @@ static int pcie_wait_for_link_status(struct pci_dev *pdev, int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) { int rc; - u16 lnkctl; /* * Ensure the updated LNKCTL parameters are used during link @@ -4939,17 +4938,14 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) if (rc) return rc; - pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnkctl); - lnkctl |= PCI_EXP_LNKCTL_RL; - pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl); + pcie_capability_set_word(pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RL); if (pdev->clear_retrain_link) { /* * Due to an erratum in some devices the Retrain Link bit * needs to be cleared again manually to allow the link * training to succeed. */ - lnkctl &= ~PCI_EXP_LNKCTL_RL; - pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnkctl); + pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_RL); } return pcie_wait_for_link_status(pdev, use_lt, !use_lt); -- cgit v1.2.3 From 5f75f96c61039151c193775d776fde42477eace1 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 17 Jul 2023 15:04:55 +0300 Subject: PCI: pciehp: Use RMW accessors for changing LNKCTL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As hotplug is not the only driver touching LNKCTL, use the RMW capability accessor which handles concurrent changes correctly. Suggested-by: Lukas Wunner Fixes: 7f822999e12a ("PCI: pciehp: Add Disable/enable link functions") Link: https://lore.kernel.org/r/20230717120503.15276-4-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Acked-by: "Rafael J. Wysocki" --- drivers/pci/hotplug/pciehp_hpc.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 8711325605f0..fd713abdfb9f 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -332,17 +332,11 @@ int pciehp_check_link_status(struct controller *ctrl) static int __pciehp_link_set(struct controller *ctrl, bool enable) { struct pci_dev *pdev = ctrl_dev(ctrl); - u16 lnk_ctrl; - pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnk_ctrl); + pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_LD, + enable ? 0 : PCI_EXP_LNKCTL_LD); - if (enable) - lnk_ctrl &= ~PCI_EXP_LNKCTL_LD; - else - lnk_ctrl |= PCI_EXP_LNKCTL_LD; - - pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnk_ctrl); - ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl); return 0; } -- cgit v1.2.3 From e09060b3b6b4661278ff8e1b7b81a37d5ea86eae Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 17 Jul 2023 15:04:56 +0300 Subject: PCI/ASPM: Use RMW accessors for changing LNKCTL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't assume that the device is fully under the control of ASPM and use RMW capability accessors which do proper locking to avoid losing concurrent updates to the register values. If configuration fails in pcie_aspm_configure_common_clock(), the function attempts to restore the old PCI_EXP_LNKCTL_CCC settings. Store only the old PCI_EXP_LNKCTL_CCC bit for the relevant devices rather than the content of the whole LNKCTL registers. It aligns better with how pcie_lnkctl_clear_and_set() expects its parameter and makes the code more obvious to understand. Suggested-by: Lukas Wunner Fixes: 2a42d9dba784 ("PCIe: ASPM: Break out of endless loop waiting for PCI config bits to switch") Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") Link: https://lore.kernel.org/r/20230717120503.15276-5-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Acked-by: "Rafael J. Wysocki" --- drivers/pci/pcie/aspm.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 3dafba0b5f41..1bf630059264 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -199,7 +199,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) { int same_clock = 1; - u16 reg16, parent_reg, child_reg[8]; + u16 reg16, ccc, parent_old_ccc, child_old_ccc[8]; struct pci_dev *child, *parent = link->pdev; struct pci_bus *linkbus = parent->subordinate; /* @@ -221,6 +221,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) /* Port might be already in common clock mode */ pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); + parent_old_ccc = reg16 & PCI_EXP_LNKCTL_CCC; if (same_clock && (reg16 & PCI_EXP_LNKCTL_CCC)) { bool consistent = true; @@ -237,34 +238,29 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) pci_info(parent, "ASPM: current common clock configuration is inconsistent, reconfiguring\n"); } + ccc = same_clock ? PCI_EXP_LNKCTL_CCC : 0; /* Configure downstream component, all functions */ list_for_each_entry(child, &linkbus->devices, bus_list) { pcie_capability_read_word(child, PCI_EXP_LNKCTL, ®16); - child_reg[PCI_FUNC(child->devfn)] = reg16; - if (same_clock) - reg16 |= PCI_EXP_LNKCTL_CCC; - else - reg16 &= ~PCI_EXP_LNKCTL_CCC; - pcie_capability_write_word(child, PCI_EXP_LNKCTL, reg16); + child_old_ccc[PCI_FUNC(child->devfn)] = reg16 & PCI_EXP_LNKCTL_CCC; + pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_CCC, ccc); } /* Configure upstream component */ - pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); - parent_reg = reg16; - if (same_clock) - reg16 |= PCI_EXP_LNKCTL_CCC; - else - reg16 &= ~PCI_EXP_LNKCTL_CCC; - pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); + pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_CCC, ccc); if (pcie_retrain_link(link->pdev, true)) { /* Training failed. Restore common clock configurations */ pci_err(parent, "ASPM: Could not configure common clock\n"); list_for_each_entry(child, &linkbus->devices, bus_list) - pcie_capability_write_word(child, PCI_EXP_LNKCTL, - child_reg[PCI_FUNC(child->devfn)]); - pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg); + pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_CCC, + child_old_ccc[PCI_FUNC(child->devfn)]); + pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_CCC, parent_old_ccc); } } -- cgit v1.2.3 From 5cd903bce9ddd234d76e67d0dfaf0aab0f11a2e0 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 3 Aug 2023 11:12:32 -0600 Subject: PCI/VPD: Add runtime power management to sysfs interface Unlike default access to config space through sysfs, the VPD read and write functions don't actively manage the runtime power management state of the device during access. Since commit 7ab5e10eda02 ("vfio/pci: Move the unused device into low power state with runtime PM"), the vfio-pci driver will use runtime power management and release unused devices to make use of low power states. Attempting to access VPD information in D3cold can result in incorrect information or kernel crashes depending on the system behavior. Wrap the VPD read/write bin attribute handlers in runtime PM and take into account the potential quirk to select the correct device to wake. Link: https://lore.kernel.org/r/20230803171233.3810944-2-alex.williamson@redhat.com Signed-off-by: Alex Williamson [bhelgaas: tweak pci_dev_put() test to match the pci_get_func0_dev() test] Signed-off-by: Bjorn Helgaas --- drivers/pci/vpd.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/vpd.c b/drivers/pci/vpd.c index a4fc4d0690fe..485a642b9304 100644 --- a/drivers/pci/vpd.c +++ b/drivers/pci/vpd.c @@ -275,8 +275,23 @@ static ssize_t vpd_read(struct file *filp, struct kobject *kobj, size_t count) { struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj)); + struct pci_dev *vpd_dev = dev; + ssize_t ret; + + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) { + vpd_dev = pci_get_func0_dev(dev); + if (!vpd_dev) + return -ENODEV; + } + + pci_config_pm_runtime_get(vpd_dev); + ret = pci_read_vpd(vpd_dev, off, count, buf); + pci_config_pm_runtime_put(vpd_dev); + + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) + pci_dev_put(vpd_dev); - return pci_read_vpd(dev, off, count, buf); + return ret; } static ssize_t vpd_write(struct file *filp, struct kobject *kobj, @@ -284,8 +299,23 @@ static ssize_t vpd_write(struct file *filp, struct kobject *kobj, size_t count) { struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj)); + struct pci_dev *vpd_dev = dev; + ssize_t ret; + + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) { + vpd_dev = pci_get_func0_dev(dev); + if (!vpd_dev) + return -ENODEV; + } + + pci_config_pm_runtime_get(vpd_dev); + ret = pci_write_vpd(vpd_dev, off, count, buf); + pci_config_pm_runtime_put(vpd_dev); + + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) + pci_dev_put(vpd_dev); - return pci_write_vpd(dev, off, count, buf); + return ret; } static BIN_ATTR(vpd, 0600, vpd_read, vpd_write, 0); -- cgit v1.2.3 From d3fcd7360338358aa0036bec6d2cf0e37a0ca624 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 3 Aug 2023 11:12:33 -0600 Subject: PCI: Fix runtime PM race with PME polling Testing that a device is not currently in a low power state provides no guarantees that the device is not imminently transitioning to such a state. Increment the PM usage counter before accessing the device. Since we don't wish to wake the device for PME polling, do so only if the device is already active by using pm_runtime_get_if_active(). Link: https://lore.kernel.org/r/20230803171233.3810944-3-alex.williamson@redhat.com Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 60230da957e0..bc266f290b2c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2415,10 +2415,13 @@ static void pci_pme_list_scan(struct work_struct *work) mutex_lock(&pci_pme_list_mutex); list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) { - if (pme_dev->dev->pme_poll) { - struct pci_dev *bridge; + struct pci_dev *pdev = pme_dev->dev; + + if (pdev->pme_poll) { + struct pci_dev *bridge = pdev->bus->self; + struct device *dev = &pdev->dev; + int pm_status; - bridge = pme_dev->dev->bus->self; /* * If bridge is in low power state, the * configuration space of subordinate devices @@ -2426,14 +2429,20 @@ static void pci_pme_list_scan(struct work_struct *work) */ if (bridge && bridge->current_state != PCI_D0) continue; + /* - * If the device is in D3cold it should not be - * polled either. + * If the device is in a low power state it + * should not be polled either. */ - if (pme_dev->dev->current_state == PCI_D3cold) + pm_status = pm_runtime_get_if_active(dev, true); + if (!pm_status) continue; - pci_pme_wakeup(pme_dev->dev, NULL); + if (pdev->current_state != PCI_D3cold) + pci_pme_wakeup(pdev, NULL); + + if (pm_status > 0) + pm_runtime_put(dev); } else { list_del(&pme_dev->list); kfree(pme_dev); -- cgit v1.2.3 From 0e8207f54cf5902367080a0e648d3adae6c019a1 Mon Sep 17 00:00:00 2001 From: Zheng Zengkai Date: Fri, 11 Aug 2023 19:10:57 +0800 Subject: PCI/P2PDMA: Use pci_dev_id() to simplify the code When we have a struct pci_dev *, use pci_dev_id() instead of manually composing the ID from dev->bus->number and dev->devfn. [bhelgaas: commit log] Link: https://lore.kernel.org/r/20230811111057.31900-1-zhengzengkai@huawei.com Signed-off-by: Zheng Zengkai Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe --- drivers/pci/p2pdma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 6cd98ffca198..ec04d0ed157b 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -532,8 +532,7 @@ static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b, static unsigned long map_types_idx(struct pci_dev *client) { - return (pci_domain_nr(client->bus) << 16) | - (client->bus->number << 8) | client->devfn; + return (pci_domain_nr(client->bus) << 16) | pci_dev_id(client); } /* -- cgit v1.2.3 From f73eedc90bf73d48e8368e6b0b4ad76a7fffaef7 Mon Sep 17 00:00:00 2001 From: Nirmal Patel Date: Thu, 10 Aug 2023 17:50:29 -0400 Subject: PCI: vmd: Disable bridge window for domain reset During domain reset process vmd_domain_reset() clears PCI configuration space of VMD root ports. But certain platform has observed following errors and failed to boot. ... DMAR: VT-d detected Invalidation Queue Error: Reason f DMAR: VT-d detected Invalidation Time-out Error: SID ffff DMAR: VT-d detected Invalidation Completion Error: SID ffff DMAR: QI HEAD: UNKNOWN qw0 = 0x0, qw1 = 0x0 DMAR: QI PRIOR: UNKNOWN qw0 = 0x0, qw1 = 0x0 DMAR: Invalidation Time-out Error (ITE) cleared The root cause is that memset_io() clears prefetchable memory base/limit registers and prefetchable base/limit 32 bits registers sequentially. This seems to be enabling prefetchable memory if the device disabled prefetchable memory originally. Here is an example (before memset_io()): PCI configuration space for 10000:00:00.0: 86 80 30 20 06 00 10 00 04 00 04 06 00 00 01 00 00 00 00 00 00 00 00 00 00 01 01 00 00 00 00 20 00 00 00 00 01 00 01 00 ff ff ff ff 75 05 00 00 ... So, prefetchable memory is ffffffff00000000-575000fffff, which is disabled. When memset_io() clears prefetchable base 32 bits register, the prefetchable memory becomes 0000000000000000-575000fffff, which is enabled and incorrect. Here is the quote from section 7.5.1.3.9 of PCI Express Base 6.0 spec: The Prefetchable Memory Limit register must be programmed to a smaller value than the Prefetchable Memory Base register if there is no prefetchable memory on the secondary side of the bridge. This is believed to be the reason for the failure and in addition the sequence of operation in vmd_domain_reset() is not following the PCIe specs. Disable the bridge window by executing a sequence of operations borrowed from pci_disable_bridge_window() and pci_setup_bridge_io(), that comply with the PCI specifications. Link: https://lore.kernel.org/r/20230810215029.1177379-1-nirmal.patel@linux.intel.com Signed-off-by: Nirmal Patel Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/vmd.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index e718a816d481..ad56df98b8e6 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -541,8 +541,23 @@ static void vmd_domain_reset(struct vmd_dev *vmd) PCI_CLASS_BRIDGE_PCI)) continue; - memset_io(base + PCI_IO_BASE, 0, - PCI_ROM_ADDRESS1 - PCI_IO_BASE); + /* + * Temporarily disable the I/O range before updating + * PCI_IO_BASE. + */ + writel(0x0000ffff, base + PCI_IO_BASE_UPPER16); + /* Update lower 16 bits of I/O base/limit */ + writew(0x00f0, base + PCI_IO_BASE); + /* Update upper 16 bits of I/O base/limit */ + writel(0, base + PCI_IO_BASE_UPPER16); + + /* MMIO Base/Limit */ + writel(0x0000fff0, base + PCI_MEMORY_BASE); + + /* Prefetchable MMIO Base/Limit */ + writel(0, base + PCI_PREF_LIMIT_UPPER32); + writel(0x0000fff0, base + PCI_PREF_MEMORY_BASE); + writel(0xffffffff, base + PCI_PREF_BASE_UPPER32); } } } -- cgit v1.2.3 From 04bbe863241a9be7d57fb4cf217ee4a72f480e70 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 16 Aug 2023 10:59:39 -0700 Subject: PCI: hv: Fix a crash in hv_pci_restore_msi_msg() during hibernation When a Linux VM with an assigned PCI device runs on Hyper-V, if the PCI device driver is not loaded yet (i.e. MSI-X/MSI is not enabled on the device yet), doing a VM hibernation triggers a panic in hv_pci_restore_msi_msg() -> msi_lock_descs(&pdev->dev), because pdev->dev.msi.data is still NULL. Avoid the panic by checking if MSI-X/MSI is enabled. Link: https://lore.kernel.org/r/20230816175939.21566-1-decui@microsoft.com Fixes: dc2b453290c4 ("PCI: hv: Rework MSI handling") Signed-off-by: Dexuan Cui Signed-off-by: Lorenzo Pieralisi Reviewed-by: sathyanarayanan.kuppuswamy@linux.intel.com Reviewed-by: Michael Kelley Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-hyperv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 2d93d0c4f10d..bed3cefdaf19 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -3983,6 +3983,9 @@ static int hv_pci_restore_msi_msg(struct pci_dev *pdev, void *arg) struct msi_desc *entry; int ret = 0; + if (!pdev->msi_enabled && !pdev->msix_enabled) + return 0; + msi_lock_descs(&pdev->dev); msi_for_each_desc(entry, &pdev->dev, MSI_DESC_ASSOCIATED) { irq_data = irq_get_irq_data(entry->irq); -- cgit v1.2.3 From 551a60e1225e71fff8efd9390204c505b0870e0f Mon Sep 17 00:00:00 2001 From: Yong-Xuan Wang Date: Mon, 7 Aug 2023 05:56:21 +0000 Subject: PCI: fu740: Set the number of MSI vectors The iMSI-RX module of the DW PCIe controller provides multiple sets of MSI_CTRL_INT_i_* registers, and each set is capable of handling 32 MSI interrupts. However, the fu740 PCIe controller driver only enabled one set of MSI_CTRL_INT_i_* registers, as the total number of supported interrupts was not specified. Set the supported number of MSI vectors to enable all the MSI_CTRL_INT_i_* registers on the fu740 PCIe core, allowing the system to fully utilize the available MSI interrupts. Link: https://lore.kernel.org/r/20230807055621.2431-1-yongxuan.wang@sifive.com Signed-off-by: Yong-Xuan Wang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Serge Semin --- drivers/pci/controller/dwc/pcie-fu740.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c index 0c90583c078b..1e9b44b8bba4 100644 --- a/drivers/pci/controller/dwc/pcie-fu740.c +++ b/drivers/pci/controller/dwc/pcie-fu740.c @@ -299,6 +299,7 @@ static int fu740_pcie_probe(struct platform_device *pdev) pci->dev = dev; pci->ops = &dw_pcie_ops; pci->pp.ops = &fu740_pcie_host_ops; + pci->pp.num_vectors = MAX_MSI_IRQS; /* SiFive specific region: mgmt */ afp->mgmt_base = devm_platform_ioremap_resource_byname(pdev, "mgmt"); -- cgit v1.2.3 From 04c1c3c4e62a22b424c07d8b03ca6f6aac2dfa7f Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Wed, 9 Aug 2023 06:34:02 +0800 Subject: PCI/VGA: Correct vga_str_to_iostate() io_state parameter type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously vga_str_to_iostate() took "int *io_state", but vga_arb_write() is the only caller and it passes "unsigned int *". Make the vga_str_to_iostate() parameter type "unsigned int *" to match. [bhelgaas: commit log] Link: https://lore.kernel.org/r/20230808223412.1743176-2-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas Reviewed-by: Andi Shyti Reviewed-by: Ilpo Järvinen --- drivers/pci/vgaarb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index 5a696078b382..c1bc6c983932 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -77,7 +77,7 @@ static const char *vga_iostate_to_str(unsigned int iostate) return "none"; } -static int vga_str_to_iostate(char *buf, int str_size, int *io_state) +static int vga_str_to_iostate(char *buf, int str_size, unsigned int *io_state) { /* we could in theory hand out locks on IO and mem * separately to userspace but it can cause deadlocks */ -- cgit v1.2.3 From 60b4925d1aeaf0c46e540949c50818b9be2c896a Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Wed, 9 Aug 2023 06:34:05 +0800 Subject: PCI/VGA: Correct vga_update_device_decodes() parameter type Previously vga_update_device_decodes() took "int new_decodes", but the callers pass "unsigned int new_decodes". Correct the vga_update_device_decodes() parameter type to "unsigned int" to match. In vga_arbiter_notify_clients(), the return from vgadev->set_decode() is "unsigned int" but was stored as "uint32_t new_decodes". Correct the new_decodes type to "unsigned int". [bhelgaas: use correct type for ->set_decode() return, commit log] Link: https://lore.kernel.org/r/20230808223412.1743176-5-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas --- drivers/pci/vgaarb.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index c1bc6c983932..443cf1a74c0b 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -864,24 +864,23 @@ bail: return ret; } -/* this is called with the lock */ -static inline void vga_update_device_decodes(struct vga_device *vgadev, - int new_decodes) +/* This is called with the lock */ +static void vga_update_device_decodes(struct vga_device *vgadev, + unsigned int new_decodes) { struct device *dev = &vgadev->pdev->dev; - int old_decodes, decodes_removed, decodes_unlocked; + unsigned int old_decodes = vgadev->decodes; + unsigned int decodes_removed = ~new_decodes & old_decodes; + unsigned int decodes_unlocked = vgadev->locks & decodes_removed; - old_decodes = vgadev->decodes; - decodes_removed = ~new_decodes & old_decodes; - decodes_unlocked = vgadev->locks & decodes_removed; vgadev->decodes = new_decodes; - vgaarb_info(dev, "changed VGA decodes: olddecodes=%s,decodes=%s:owns=%s\n", - vga_iostate_to_str(old_decodes), - vga_iostate_to_str(vgadev->decodes), - vga_iostate_to_str(vgadev->owns)); + vgaarb_info(dev, "VGA decodes changed: olddecodes=%s,decodes=%s:owns=%s\n", + vga_iostate_to_str(old_decodes), + vga_iostate_to_str(vgadev->decodes), + vga_iostate_to_str(vgadev->owns)); - /* if we removed locked decodes, lock count goes to zero, and release */ + /* If we removed locked decodes, lock count goes to zero, and release */ if (decodes_unlocked) { if (decodes_unlocked & VGA_RSRC_LEGACY_IO) vgadev->io_lock_cnt = 0; @@ -1472,7 +1471,7 @@ static void vga_arbiter_notify_clients(void) { struct vga_device *vgadev; unsigned long flags; - uint32_t new_decodes; + unsigned int new_decodes; bool new_state; if (!vga_arbiter_used) -- cgit v1.2.3 From b421364a905e05d62f889786d25954c5a4128c80 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Wed, 9 Aug 2023 06:34:06 +0800 Subject: PCI/VGA: Simplify vga_arbiter_notify_clients() In vga_arbiter_notify_clients(), "new_state" was computed during every loop iteration even though it doesn't depend on anything that changes during the loop. Move the computation outside the loop. [bhelgaas: drop renames that obscure the purpose, commit log] Link: https://lore.kernel.org/r/20230808223412.1743176-6-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas --- drivers/pci/vgaarb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index 443cf1a74c0b..685681b0e5af 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -1477,12 +1477,10 @@ static void vga_arbiter_notify_clients(void) if (!vga_arbiter_used) return; + new_state = (vga_count > 1) ? false : true; + spin_lock_irqsave(&vga_lock, flags); list_for_each_entry(vgadev, &vga_list, list) { - if (vga_count > 1) - new_state = false; - else - new_state = true; if (vgadev->set_decode) { new_decodes = vgadev->set_decode(vgadev->pdev, new_state); -- cgit v1.2.3 From 4582db1d0a41ed07de140a8bfe8e802749579563 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Wed, 9 Aug 2023 06:34:08 +0800 Subject: PCI/VGA: Simplify vga_client_register() Reorganize vga_client_register() to avoid the goto and the need to save the return value. Update the kernel-doc to reflect -ENODEV on failure. No functional change intended. [bhelgaas: drop "ret" variable, commit log] Link: https://lore.kernel.org/r/20230808223412.1743176-8-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas --- drivers/pci/vgaarb.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index 685681b0e5af..93e15dab5501 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -967,27 +967,22 @@ EXPORT_SYMBOL(vga_set_legacy_decoding); * * To unregister just call vga_client_unregister(). * - * Returns: 0 on success, -1 on failure + * Returns: 0 on success, -ENODEV on failure */ int vga_client_register(struct pci_dev *pdev, unsigned int (*set_decode)(struct pci_dev *pdev, bool decode)) { - int ret = -ENODEV; - struct vga_device *vgadev; unsigned long flags; + struct vga_device *vgadev; spin_lock_irqsave(&vga_lock, flags); vgadev = vgadev_find(pdev); - if (!vgadev) - goto bail; - - vgadev->set_decode = set_decode; - ret = 0; - -bail: + if (vgadev) + vgadev->set_decode = set_decode; spin_unlock_irqrestore(&vga_lock, flags); - return ret; - + if (!vgadev) + return -ENODEV; + return 0; } EXPORT_SYMBOL(vga_client_register); -- cgit v1.2.3 From d28c0d84ca40e8cbc5c9f4e94f4ec78469d6c07b Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 20 Jul 2023 09:58:33 -0400 Subject: PCI: layerscape: Add support for link-down notification Add support to pass link-down notification to the endpoint function driver so that it can process the LINK_DOWN event. Link: https://lore.kernel.org/r/20230720135834.1977616-1-Frank.Li@nxp.com Signed-off-by: Frank Li Signed-off-by: Lorenzo Pieralisi Acked-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pci-layerscape-ep.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index de4c1758a6c3..e0969ff2ddf7 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -89,6 +89,7 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id) dev_dbg(pci->dev, "Link up\n"); } else if (val & PEX_PF0_PME_MES_DR_LDD) { dev_dbg(pci->dev, "Link down\n"); + pci_epc_linkdown(pci->ep.epc); } else if (val & PEX_PF0_PME_MES_DR_HRD) { dev_dbg(pci->dev, "Hot reset\n"); } -- cgit v1.2.3 From 17cf8661ee0f065c08152e611a568dd1fb0285f1 Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Thu, 20 Jul 2023 09:58:34 -0400 Subject: PCI: layerscape: Add workaround for lost link capabilities during reset The endpoint controller loses the Maximum Link Width and Supported Link Speed value from the Link Capabilities Register - initially configured by the Reset Configuration Word (RCW) - during a link-down or hot reset event. Address this issue in the endpoint event handler. Link: https://lore.kernel.org/r/20230720135834.1977616-2-Frank.Li@nxp.com Fixes: a805770d8a22 ("PCI: layerscape: Add EP mode support") Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Signed-off-by: Frank Li Signed-off-by: Lorenzo Pieralisi Acked-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pci-layerscape-ep.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index e0969ff2ddf7..b1faf41a2fae 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -45,6 +45,7 @@ struct ls_pcie_ep { struct pci_epc_features *ls_epc; const struct ls_pcie_ep_drvdata *drvdata; int irq; + u32 lnkcap; bool big_endian; }; @@ -73,6 +74,7 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id) struct ls_pcie_ep *pcie = dev_id; struct dw_pcie *pci = pcie->pci; u32 val, cfg; + u8 offset; val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR); ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val); @@ -81,6 +83,19 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id) return IRQ_NONE; if (val & PEX_PF0_PME_MES_DR_LUD) { + + offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + + /* + * The values of the Maximum Link Width and Supported Link + * Speed from the Link Capabilities Register will be lost + * during link down or hot reset. Restore initial value + * that configured by the Reset Configuration Word (RCW). + */ + dw_pcie_dbi_ro_wr_en(pci); + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, pcie->lnkcap); + dw_pcie_dbi_ro_wr_dis(pci); + cfg = ls_lut_readl(pcie, PEX_PF0_CONFIG); cfg |= PEX_PF0_CFG_READY; ls_lut_writel(pcie, PEX_PF0_CONFIG, cfg); @@ -216,6 +231,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) struct ls_pcie_ep *pcie; struct pci_epc_features *ls_epc; struct resource *dbi_base; + u8 offset; int ret; pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); @@ -252,6 +268,9 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pcie); + offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + pcie->lnkcap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); + ret = dw_pcie_ep_init(&pci->ep); if (ret) return ret; -- cgit v1.2.3 From e78bd50b4078b3b2d9f85d97796b7c271e7860ca Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 21 Aug 2023 14:48:13 -0400 Subject: PCI: Add PCIE_PME_TO_L2_TIMEOUT_US L2 ready timeout value Add the PCIE_PME_TO_L2_TIMEOUT_US macro to define the L2 ready timeout as described in the PCI specifications. Link: https://lore.kernel.org/r/20230821184815.2167131-2-Frank.Li@nxp.com Signed-off-by: Frank Li Signed-off-by: Lorenzo Pieralisi Acked-by: Manivannan Sadhasivam --- drivers/pci/pci.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a4c397434057..da8156663c82 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -13,6 +13,12 @@ #define PCIE_LINK_RETRAIN_TIMEOUT_MS 1000 +/* + * PCIe r6.0, sec 5.3.3.2.1 + * Recommends 1ms to 10ms timeout to check L2 ready. + */ +#define PCIE_PME_TO_L2_TIMEOUT_US 10000 + extern const unsigned char pcie_link_speed[]; extern bool pci_early_dump; -- cgit v1.2.3 From 4774faf854f53461fd22daa73f3881fe11b6b755 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 21 Aug 2023 14:48:14 -0400 Subject: PCI: dwc: Implement generic suspend/resume functionality Introduce an helper function (dw_pcie_get_ltssm()) to retrieve SMLH_LTSS_STATE. Add common dw_pcie_suspend(resume)_noirq() API to implement the DWC controller generic suspend/resume functionality. Add a controller specific callback to send the PME_Turn_Off message (ie .pme_turn_off) for controller platform specific PME handling. Link: https://lore.kernel.org/r/20230821184815.2167131-3-Frank.Li@nxp.com Signed-off-by: Frank Li [lpieralisi@kernel.org: commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-designware-host.c | 71 +++++++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 28 +++++++++ 2 files changed, 99 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index cf61733bf78d..5c8cbc3afae4 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -8,6 +8,7 @@ * Author: Jingoo Han */ +#include #include #include #include @@ -16,6 +17,7 @@ #include #include +#include "../../pci.h" #include "pcie-designware.h" static struct pci_ops dw_pcie_ops; @@ -812,3 +814,72 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) return 0; } EXPORT_SYMBOL_GPL(dw_pcie_setup_rc); + +int dw_pcie_suspend_noirq(struct dw_pcie *pci) +{ + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 val; + int ret; + + /* + * If L1SS is supported, then do not put the link into L2 as some + * devices such as NVMe expect low resume latency. + */ + if (dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKCTL) & PCI_EXP_LNKCTL_ASPM_L1) + return 0; + + if (dw_pcie_get_ltssm(pci) <= DW_PCIE_LTSSM_DETECT_ACT) + return 0; + + if (!pci->pp.ops->pme_turn_off) + return 0; + + pci->pp.ops->pme_turn_off(&pci->pp); + + ret = read_poll_timeout(dw_pcie_get_ltssm, val, val == DW_PCIE_LTSSM_L2_IDLE, + PCIE_PME_TO_L2_TIMEOUT_US/10, + PCIE_PME_TO_L2_TIMEOUT_US, false, pci); + if (ret) { + dev_err(pci->dev, "Timeout waiting for L2 entry! LTSSM: 0x%x\n", val); + return ret; + } + + if (pci->pp.ops->host_deinit) + pci->pp.ops->host_deinit(&pci->pp); + + pci->suspended = true; + + return ret; +} +EXPORT_SYMBOL_GPL(dw_pcie_suspend_noirq); + +int dw_pcie_resume_noirq(struct dw_pcie *pci) +{ + int ret; + + if (!pci->suspended) + return 0; + + pci->suspended = false; + + if (pci->pp.ops->host_init) { + ret = pci->pp.ops->host_init(&pci->pp); + if (ret) { + dev_err(pci->dev, "Host init failed: %d\n", ret); + return ret; + } + } + + dw_pcie_setup_rc(&pci->pp); + + ret = dw_pcie_start_link(pci); + if (ret) + return ret; + + ret = dw_pcie_wait_for_link(pci); + if (ret) + return ret; + + return ret; +} +EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 615660640801..91d13f9b21b1 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -288,10 +288,21 @@ enum dw_pcie_core_rst { DW_PCIE_NUM_CORE_RSTS }; +enum dw_pcie_ltssm { + /* Need to align with PCIE_PORT_DEBUG0 bits 0:5 */ + DW_PCIE_LTSSM_DETECT_QUIET = 0x0, + DW_PCIE_LTSSM_DETECT_ACT = 0x1, + DW_PCIE_LTSSM_L0 = 0x11, + DW_PCIE_LTSSM_L2_IDLE = 0x15, + + DW_PCIE_LTSSM_UNKNOWN = 0xFFFFFFFF, +}; + struct dw_pcie_host_ops { int (*host_init)(struct dw_pcie_rp *pp); void (*host_deinit)(struct dw_pcie_rp *pp); int (*msi_host_init)(struct dw_pcie_rp *pp); + void (*pme_turn_off)(struct dw_pcie_rp *pp); }; struct dw_pcie_rp { @@ -364,6 +375,7 @@ struct dw_pcie_ops { void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, size_t size, u32 val); int (*link_up)(struct dw_pcie *pcie); + enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); }; @@ -393,6 +405,7 @@ struct dw_pcie { struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS]; struct reset_control_bulk_data core_rsts[DW_PCIE_NUM_CORE_RSTS]; struct gpio_desc *pe_rst; + bool suspended; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) @@ -431,6 +444,9 @@ int dw_pcie_edma_detect(struct dw_pcie *pci); void dw_pcie_edma_remove(struct dw_pcie *pci); void dw_pcie_print_link_status(struct dw_pcie *pci); +int dw_pcie_suspend_noirq(struct dw_pcie *pci); +int dw_pcie_resume_noirq(struct dw_pcie *pci); + static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) { dw_pcie_write_dbi(pci, reg, 0x4, val); @@ -502,6 +518,18 @@ static inline void dw_pcie_stop_link(struct dw_pcie *pci) pci->ops->stop_link(pci); } +static inline enum dw_pcie_ltssm dw_pcie_get_ltssm(struct dw_pcie *pci) +{ + u32 val; + + if (pci->ops && pci->ops->get_ltssm) + return pci->ops->get_ltssm(pci); + + val = dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0); + + return (enum dw_pcie_ltssm)FIELD_GET(PORT_LOGIC_LTSSM_STATE_MASK, val); +} + #ifdef CONFIG_PCIE_DW_HOST irqreturn_t dw_handle_msi_irq(struct dw_pcie_rp *pp); int dw_pcie_setup_rc(struct dw_pcie_rp *pp); -- cgit v1.2.3 From 9fda4d09905db9ecae17ad741924a7530aa3c96e Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Mon, 21 Aug 2023 14:48:15 -0400 Subject: PCI: layerscape: Add power management support for ls1028a Add PME_Turn_off/PME_TO_Ack handshake sequence for ls1028a platform. Implemented on top of common dwc dw_pcie_suspend(resume)_noirq() functions to handle system enter/exit suspend states. Link: https://lore.kernel.org/r/20230821184815.2167131-4-Frank.Li@nxp.com Signed-off-by: Hou Zhiqiang Signed-off-by: Frank Li Signed-off-by: Lorenzo Pieralisi Acked-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pci-layerscape.c | 140 ++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 9 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index ed5fb492fe08..b931d597656f 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -8,9 +8,11 @@ * Author: Minghuan Lian */ +#include #include #include #include +#include #include #include #include @@ -20,6 +22,7 @@ #include #include +#include "../../pci.h" #include "pcie-designware.h" /* PEX Internal Configuration Registers */ @@ -27,12 +30,26 @@ #define PCIE_ABSERR 0x8d0 /* Bridge Slave Error Response Register */ #define PCIE_ABSERR_SETTING 0x9401 /* Forward error of non-posted request */ +/* PF Message Command Register */ +#define LS_PCIE_PF_MCR 0x2c +#define PF_MCR_PTOMR BIT(0) +#define PF_MCR_EXL2S BIT(1) + #define PCIE_IATU_NUM 6 +struct ls_pcie_drvdata { + const u32 pf_off; + bool pm_support; +}; + struct ls_pcie { struct dw_pcie *pci; + const struct ls_pcie_drvdata *drvdata; + void __iomem *pf_base; + bool big_endian; }; +#define ls_pcie_pf_readl_addr(addr) ls_pcie_pf_readl(pcie, addr) #define to_ls_pcie(x) dev_get_drvdata((x)->dev) static bool ls_pcie_is_bridge(struct ls_pcie *pcie) @@ -73,6 +90,68 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR); } +static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->pf_base + off); + + return ioread32(pcie->pf_base + off); +} + +static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + iowrite32be(val, pcie->pf_base + off); + else + iowrite32(val, pcie->pf_base + off); +} + +static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct ls_pcie *pcie = to_ls_pcie(pci); + u32 val; + int ret; + + val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR); + val |= PF_MCR_PTOMR; + ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val); + + ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR, + val, !(val & PF_MCR_PTOMR), + PCIE_PME_TO_L2_TIMEOUT_US/10, + PCIE_PME_TO_L2_TIMEOUT_US); + if (ret) + dev_err(pcie->pci->dev, "PME_Turn_off timeout\n"); +} + +static void ls_pcie_exit_from_l2(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct ls_pcie *pcie = to_ls_pcie(pci); + u32 val; + int ret; + + /* + * Set PF_MCR_EXL2S bit in LS_PCIE_PF_MCR register for the link + * to exit L2 state. + */ + val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR); + val |= PF_MCR_EXL2S; + ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val); + + /* + * L2 exit timeout of 10ms is not defined in the specifications, + * it was chosen based on empirical observations. + */ + ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR, + val, !(val & PF_MCR_EXL2S), + 1000, + 10000); + if (ret) + dev_err(pcie->pci->dev, "L2 exit timeout\n"); +} + static int ls_pcie_host_init(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -91,18 +170,28 @@ static int ls_pcie_host_init(struct dw_pcie_rp *pp) static const struct dw_pcie_host_ops ls_pcie_host_ops = { .host_init = ls_pcie_host_init, + .pme_turn_off = ls_pcie_send_turnoff_msg, +}; + +static const struct ls_pcie_drvdata ls1021a_drvdata = { + .pm_support = false, +}; + +static const struct ls_pcie_drvdata layerscape_drvdata = { + .pf_off = 0xc0000, + .pm_support = true, }; static const struct of_device_id ls_pcie_of_match[] = { - { .compatible = "fsl,ls1012a-pcie", }, - { .compatible = "fsl,ls1021a-pcie", }, - { .compatible = "fsl,ls1028a-pcie", }, - { .compatible = "fsl,ls1043a-pcie", }, - { .compatible = "fsl,ls1046a-pcie", }, - { .compatible = "fsl,ls2080a-pcie", }, - { .compatible = "fsl,ls2085a-pcie", }, - { .compatible = "fsl,ls2088a-pcie", }, - { .compatible = "fsl,ls1088a-pcie", }, + { .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata }, + { .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata }, + { .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata }, + { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata }, + { .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata }, + { .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata }, + { .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata }, + { .compatible = "fsl,ls2088a-pcie", .data = &layerscape_drvdata }, + { .compatible = "fsl,ls1088a-pcie", .data = &layerscape_drvdata }, { }, }; @@ -121,6 +210,8 @@ static int ls_pcie_probe(struct platform_device *pdev) if (!pci) return -ENOMEM; + pcie->drvdata = of_device_get_match_data(dev); + pci->dev = dev; pci->pp.ops = &ls_pcie_host_ops; @@ -131,6 +222,10 @@ static int ls_pcie_probe(struct platform_device *pdev) if (IS_ERR(pci->dbi_base)) return PTR_ERR(pci->dbi_base); + pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian"); + + pcie->pf_base = pci->dbi_base + pcie->drvdata->pf_off; + if (!ls_pcie_is_bridge(pcie)) return -ENODEV; @@ -139,12 +234,39 @@ static int ls_pcie_probe(struct platform_device *pdev) return dw_pcie_host_init(&pci->pp); } +static int ls_pcie_suspend_noirq(struct device *dev) +{ + struct ls_pcie *pcie = dev_get_drvdata(dev); + + if (!pcie->drvdata->pm_support) + return 0; + + return dw_pcie_suspend_noirq(pcie->pci); +} + +static int ls_pcie_resume_noirq(struct device *dev) +{ + struct ls_pcie *pcie = dev_get_drvdata(dev); + + if (!pcie->drvdata->pm_support) + return 0; + + ls_pcie_exit_from_l2(&pcie->pci->pp); + + return dw_pcie_resume_noirq(pcie->pci); +} + +static const struct dev_pm_ops ls_pcie_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(ls_pcie_suspend_noirq, ls_pcie_resume_noirq) +}; + static struct platform_driver ls_pcie_driver = { .probe = ls_pcie_probe, .driver = { .name = "layerscape-pcie", .of_match_table = ls_pcie_of_match, .suppress_bind_attrs = true, + .pm = &ls_pcie_pm_ops, }, }; builtin_platform_driver(ls_pcie_driver); -- cgit v1.2.3 From 8eb8c2735306526929141052c82bd118a7a2119b Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 23 Jun 2023 10:40:57 -0400 Subject: PCI: brcmstb: Assert PERST# on BCM2711 The current PCIe driver assumes PERST# is asserted when probe() is invoked. Some older versions of the 2711/RPi bootloader left PERST# unasserted, as the Raspian OS does assert PERST# on probe(). For this reason, we assert PERST# for BCM2711 SOCs (i.e. RPi). Link: https://lore.kernel.org/r/20230623144100.34196-5-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pcie-brcmstb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index f593a422bd63..74808e9b41e7 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -874,6 +874,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) /* Reset the bridge */ pcie->bridge_sw_init_set(pcie, 1); + + /* Ensure that PERST# is asserted; some bootloaders may deassert it. */ + if (pcie->type == BCM2711) + pcie->perst_set(pcie, 1); + usleep_range(100, 200); /* Take the bridge out of reset */ -- cgit v1.2.3 From 6dac1507a654f897ae98d7ec1a12b712c3ec4d47 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 23 Jun 2023 10:40:58 -0400 Subject: PCI: brcmstb: Remove stale comment A comment says that Multi-MSI is not supported by the driver. A past commit [1] added this feature, so the comment is incorrect and is removed. [1] commit 198acab1772f22f2 ("PCI: brcmstb: Enable Multi-MSI") Link: https://lore.kernel.org/r/20230623144100.34196-6-james.quinlan@broadcom.com Signed-off-by: Jim Quinlan Signed-off-by: Lorenzo Pieralisi Acked-by: Florian Fainelli --- drivers/pci/controller/pcie-brcmstb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 74808e9b41e7..f9dd6622fe10 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -439,7 +439,6 @@ static struct irq_chip brcm_msi_irq_chip = { }; static struct msi_domain_info brcm_msi_domain_info = { - /* Multi MSI is supported by the controller, but not by this driver */ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI), .chip = &brcm_msi_irq_chip, -- cgit v1.2.3 From cc64ca4b62f5035c87e955f256b338c32dfdbb19 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Wed, 9 Aug 2023 06:34:07 +0800 Subject: PCI/VGA: Fix typos Fix typos, rewrap to fill 78 columns, convert to conventional multi-line style. [bhelgaas: squash and add more fixes] Link: https://lore.kernel.org/r/20230808223412.1743176-7-sui.jingfeng@linux.dev Link: https://lore.kernel.org/r/20230808223412.1743176-9-sui.jingfeng@linux.dev Link: https://lore.kernel.org/r/20230808223412.1743176-10-sui.jingfeng@linux.dev Link: https://lore.kernel.org/r/20230808223412.1743176-11-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas --- drivers/pci/vgaarb.c | 308 +++++++++++++++++++++++++------------------------ include/linux/vgaarb.h | 4 +- 2 files changed, 161 insertions(+), 151 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index 93e15dab5501..5e6b1eb54c64 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT /* - * vgaarb.c: Implements the VGA arbitration. For details refer to + * vgaarb.c: Implements VGA arbitration. For details refer to * Documentation/gpu/vgaarbiter.rst * * (C) Copyright 2005 Benjamin Herrenschmidt @@ -30,22 +30,21 @@ #include #include #include - #include - #include static void vga_arbiter_notify_clients(void); + /* - * We keep a list of all vga devices in the system to speed + * We keep a list of all VGA devices in the system to speed * up the various operations of the arbiter */ struct vga_device { struct list_head list; struct pci_dev *pdev; - unsigned int decodes; /* what does it decodes */ - unsigned int owns; /* what does it owns */ - unsigned int locks; /* what does it locks */ + unsigned int decodes; /* what it decodes */ + unsigned int owns; /* what it owns */ + unsigned int locks; /* what it locks */ unsigned int io_lock_cnt; /* legacy IO lock count */ unsigned int mem_lock_cnt; /* legacy MEM lock count */ unsigned int io_norm_cnt; /* normal IO count */ @@ -61,7 +60,6 @@ static bool vga_arbiter_used; static DEFINE_SPINLOCK(vga_lock); static DECLARE_WAIT_QUEUE_HEAD(vga_wait_queue); - static const char *vga_iostate_to_str(unsigned int iostate) { /* Ignore VGA_RSRC_IO and VGA_RSRC_MEM */ @@ -79,14 +77,16 @@ static const char *vga_iostate_to_str(unsigned int iostate) static int vga_str_to_iostate(char *buf, int str_size, unsigned int *io_state) { - /* we could in theory hand out locks on IO and mem - * separately to userspace but it can cause deadlocks */ + /* + * In theory, we could hand out locks on IO and MEM separately to + * userspace, but this can cause deadlocks. + */ if (strncmp(buf, "none", 4) == 0) { *io_state = VGA_RSRC_NONE; return 1; } - /* XXX We're not chekcing the str_size! */ + /* XXX We're not checking the str_size! */ if (strncmp(buf, "io+mem", 6) == 0) goto both; else if (strncmp(buf, "io", 2) == 0) @@ -99,7 +99,7 @@ both: return 1; } -/* this is only used a cookie - it should not be dereferenced */ +/* This is only used as a cookie, it should not be dereferenced */ static struct pci_dev *vga_default; /* Find somebody in our list */ @@ -116,20 +116,18 @@ static struct vga_device *vgadev_find(struct pci_dev *pdev) /** * vga_default_device - return the default VGA device, for vgacon * - * This can be defined by the platform. The default implementation - * is rather dumb and will probably only work properly on single - * vga card setups and/or x86 platforms. + * This can be defined by the platform. The default implementation is + * rather dumb and will probably only work properly on single VGA card + * setups and/or x86 platforms. * - * If your VGA default device is not PCI, you'll have to return - * NULL here. In this case, I assume it will not conflict with - * any PCI card. If this is not true, I'll have to define two archs - * hooks for enabling/disabling the VGA default device if that is - * possible. This may be a problem with real _ISA_ VGA cards, in - * addition to a PCI one. I don't know at this point how to deal - * with that card. Can theirs IOs be disabled at all ? If not, then - * I suppose it's a matter of having the proper arch hook telling - * us about it, so we basically never allow anybody to succeed a - * vga_get()... + * If your VGA default device is not PCI, you'll have to return NULL here. + * In this case, I assume it will not conflict with any PCI card. If this + * is not true, I'll have to define two arch hooks for enabling/disabling + * the VGA default device if that is possible. This may be a problem with + * real _ISA_ VGA cards, in addition to a PCI one. I don't know at this + * point how to deal with that card. Can their IOs be disabled at all? If + * not, then I suppose it's a matter of having the proper arch hook telling + * us about it, so we basically never allow anybody to succeed a vga_get(). */ struct pci_dev *vga_default_device(void) { @@ -147,14 +145,13 @@ void vga_set_default_device(struct pci_dev *pdev) } /** - * vga_remove_vgacon - deactivete vga console + * vga_remove_vgacon - deactivate VGA console * - * Unbind and unregister vgacon in case pdev is the default vga - * device. Can be called by gpu drivers on initialization to make - * sure vga register access done by vgacon will not disturb the - * device. + * Unbind and unregister vgacon in case pdev is the default VGA device. + * Can be called by GPU drivers on initialization to make sure VGA register + * access done by vgacon will not disturb the device. * - * @pdev: pci device. + * @pdev: PCI device. */ #if !defined(CONFIG_VGA_CONSOLE) int vga_remove_vgacon(struct pci_dev *pdev) @@ -193,14 +190,17 @@ int vga_remove_vgacon(struct pci_dev *pdev) #endif EXPORT_SYMBOL(vga_remove_vgacon); -/* If we don't ever use VGA arb we should avoid - turning off anything anywhere due to old X servers getting - confused about the boot device not being VGA */ +/* + * If we don't ever use VGA arbitration, we should avoid turning off + * anything anywhere due to old X servers getting confused about the boot + * device not being VGA. + */ static void vga_check_first_use(void) { - /* we should inform all GPUs in the system that - * VGA arb has occurred and to try and disable resources - * if they can */ + /* + * Inform all GPUs in the system that VGA arbitration has occurred + * so they can disable resources if possible. + */ if (!vga_arbiter_used) { vga_arbiter_used = true; vga_arbiter_notify_clients(); @@ -216,7 +216,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, unsigned int pci_bits; u32 flags = 0; - /* Account for "normal" resources to lock. If we decode the legacy, + /* + * Account for "normal" resources to lock. If we decode the legacy, * counterpart, we need to request it as well */ if ((rsrc & VGA_RSRC_NORMAL_IO) && @@ -236,14 +237,15 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, if (wants == 0) goto lock_them; - /* We don't need to request a legacy resource, we just enable - * appropriate decoding and go + /* + * We don't need to request a legacy resource, we just enable + * appropriate decoding and go. */ legacy_wants = wants & VGA_RSRC_LEGACY_MASK; if (legacy_wants == 0) goto enable_them; - /* Ok, we don't, let's find out how we need to kick off */ + /* Ok, we don't, let's find out who we need to kick off */ list_for_each_entry(conflict, &vga_list, list) { unsigned int lwants = legacy_wants; unsigned int change_bridge = 0; @@ -252,39 +254,44 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, if (vgadev == conflict) continue; - /* We have a possible conflict. before we go further, we must + /* + * We have a possible conflict. Before we go further, we must * check if we sit on the same bus as the conflicting device. - * if we don't, then we must tie both IO and MEM resources + * If we don't, then we must tie both IO and MEM resources * together since there is only a single bit controlling - * VGA forwarding on P2P bridges + * VGA forwarding on P2P bridges. */ if (vgadev->pdev->bus != conflict->pdev->bus) { change_bridge = 1; lwants = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; } - /* Check if the guy has a lock on the resource. If he does, - * return the conflicting entry + /* + * Check if the guy has a lock on the resource. If he does, + * return the conflicting entry. */ if (conflict->locks & lwants) return conflict; - /* Ok, now check if it owns the resource we want. We can - * lock resources that are not decoded, therefore a device + /* + * Ok, now check if it owns the resource we want. We can + * lock resources that are not decoded; therefore a device * can own resources it doesn't decode. */ match = lwants & conflict->owns; if (!match) continue; - /* looks like he doesn't have a lock, we can steal - * them from him + /* + * Looks like he doesn't have a lock, we can steal them + * from him. */ flags = 0; pci_bits = 0; - /* If we can't control legacy resources via the bridge, we + /* + * If we can't control legacy resources via the bridge, we * also need to disable normal decoding. */ if (!conflict->bridge_has_one_vga) { @@ -311,7 +318,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, } enable_them: - /* ok dude, we got it, everybody conflicting has been disabled, let's + /* + * Ok, we got it, everybody conflicting has been disabled, let's * enable us. Mark any bits in "owns" regardless of whether we * decoded them. We can lock resources we don't decode, therefore * we must track them via "owns". @@ -353,8 +361,9 @@ static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) vgaarb_dbg(dev, "%s\n", __func__); - /* Update our counters, and account for equivalent legacy resources - * if we decode them + /* + * Update our counters and account for equivalent legacy resources + * if we decode them. */ if ((rsrc & VGA_RSRC_NORMAL_IO) && vgadev->io_norm_cnt > 0) { vgadev->io_norm_cnt--; @@ -371,32 +380,34 @@ static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) if ((rsrc & VGA_RSRC_LEGACY_MEM) && vgadev->mem_lock_cnt > 0) vgadev->mem_lock_cnt--; - /* Just clear lock bits, we do lazy operations so we don't really - * have to bother about anything else at this point + /* + * Just clear lock bits, we do lazy operations so we don't really + * have to bother about anything else at this point. */ if (vgadev->io_lock_cnt == 0) vgadev->locks &= ~VGA_RSRC_LEGACY_IO; if (vgadev->mem_lock_cnt == 0) vgadev->locks &= ~VGA_RSRC_LEGACY_MEM; - /* Kick the wait queue in case somebody was waiting if we actually - * released something + /* + * Kick the wait queue in case somebody was waiting if we actually + * released something. */ if (old_locks != vgadev->locks) wake_up_all(&vga_wait_queue); } /** - * vga_get - acquire & locks VGA resources - * @pdev: pci device of the VGA card or NULL for the system default + * vga_get - acquire & lock VGA resources + * @pdev: PCI device of the VGA card or NULL for the system default * @rsrc: bit mask of resources to acquire and lock * @interruptible: blocking should be interruptible by signals ? * - * This function acquires VGA resources for the given card and mark those - * resources locked. If the resource requested are "normal" (and not legacy) + * Acquire VGA resources for the given card and mark those resources + * locked. If the resources requested are "normal" (and not legacy) * resources, the arbiter will first check whether the card is doing legacy - * decoding for that type of resource. If yes, the lock is "converted" into a - * legacy resource lock. + * decoding for that type of resource. If yes, the lock is "converted" into + * a legacy resource lock. * * The arbiter will first look for all VGA cards that might conflict and disable * their IOs and/or Memory access, including VGA forwarding on P2P bridges if @@ -428,7 +439,7 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) int rc = 0; vga_check_first_use(); - /* The one who calls us should check for this, but lets be sure... */ + /* The caller should check for this, but let's be sure */ if (pdev == NULL) pdev = vga_default_device(); if (pdev == NULL) @@ -447,12 +458,12 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) if (conflict == NULL) break; - - /* We have a conflict, we wait until somebody kicks the + /* + * We have a conflict; we wait until somebody kicks the * work queue. Currently we have one work queue that we * kick each time some resources are released, but it would - * be fairly easy to have a per device one so that we only - * need to attach to the conflicting device + * be fairly easy to have a per-device one so that we only + * need to attach to the conflicting device. */ init_waitqueue_entry(&wait, current); add_wait_queue(&vga_wait_queue, &wait); @@ -474,12 +485,12 @@ EXPORT_SYMBOL(vga_get); /** * vga_tryget - try to acquire & lock legacy VGA resources - * @pdev: pci devivce of VGA card or NULL for system default + * @pdev: PCI device of VGA card or NULL for system default * @rsrc: bit mask of resources to acquire and lock * - * This function performs the same operation as vga_get(), but will return an - * error (-EBUSY) instead of blocking if the resources are already locked by - * another card. It can be called in any context + * Perform the same operation as vga_get(), but return an error (-EBUSY) + * instead of blocking if the resources are already locked by another card. + * Can be called in any context. * * On success, release the VGA resource again with vga_put(). * @@ -495,7 +506,7 @@ static int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) vga_check_first_use(); - /* The one who calls us should check for this, but lets be sure... */ + /* The caller should check for this, but let's be sure */ if (pdev == NULL) pdev = vga_default_device(); if (pdev == NULL) @@ -515,20 +526,20 @@ bail: /** * vga_put - release lock on legacy VGA resources - * @pdev: pci device of VGA card or NULL for system default - * @rsrc: but mask of resource to release + * @pdev: PCI device of VGA card or NULL for system default + * @rsrc: bit mask of resource to release * - * This fuction releases resources previously locked by vga_get() or - * vga_tryget(). The resources aren't disabled right away, so that a subsequence - * vga_get() on the same card will succeed immediately. Resources have a - * counter, so locks are only released if the counter reaches 0. + * Release resources previously locked by vga_get() or vga_tryget(). The + * resources aren't disabled right away, so that a subsequent vga_get() on + * the same card will succeed immediately. Resources have a counter, so + * locks are only released if the counter reaches 0. */ void vga_put(struct pci_dev *pdev, unsigned int rsrc) { struct vga_device *vgadev; unsigned long flags; - /* The one who calls us should check for this, but lets be sure... */ + /* The caller should check for this, but let's be sure */ if (pdev == NULL) pdev = vga_default_device(); if (pdev == NULL) @@ -665,7 +676,7 @@ static bool vga_is_boot_device(struct vga_device *vgadev) } /* - * vgadev has neither IO nor MEM enabled. If we haven't found any + * Vgadev has neither IO nor MEM enabled. If we haven't found any * other VGA devices, it is the best candidate so far. */ if (!boot_vga) @@ -696,20 +707,20 @@ static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev) return; } - /* okay iterate the new devices bridge hierarachy */ + /* Iterate the new device's bridge hierarchy */ new_bus = vgadev->pdev->bus; while (new_bus) { new_bridge = new_bus->self; - /* go through list of devices already registered */ + /* Go through list of devices already registered */ list_for_each_entry(same_bridge_vgadev, &vga_list, list) { bus = same_bridge_vgadev->pdev->bus; bridge = bus->self; - /* see if the share a bridge with this device */ + /* See if it shares a bridge with this device */ if (new_bridge == bridge) { /* - * If their direct parent bridge is the same + * If its direct parent bridge is the same * as any bridge of this device then it can't * be used for that device. */ @@ -717,10 +728,10 @@ static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev) } /* - * Now iterate the previous devices bridge hierarchy. - * If the new devices parent bridge is in the other - * devices hierarchy then we can't use it to control - * this device + * Now iterate the previous device's bridge hierarchy. + * If the new device's parent bridge is in the other + * device's hierarchy, we can't use it to control this + * device. */ while (bus) { bridge = bus->self; @@ -741,10 +752,9 @@ static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev) } /* - * Currently, we assume that the "initial" setup of the system is - * not sane, that is we come up with conflicting devices and let - * the arbiter's client decides if devices decodes or not legacy - * things. + * Currently, we assume that the "initial" setup of the system is not sane, + * that is, we come up with conflicting devices and let the arbiter's + * client decide if devices decodes legacy things or not. */ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) { @@ -763,7 +773,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) if (vgadev == NULL) { vgaarb_err(&pdev->dev, "failed to allocate VGA arbiter data\n"); /* - * What to do on allocation failure ? For now, let's just do + * What to do on allocation failure? For now, let's just do * nothing, I'm not sure there is anything saner to be done. */ return false; @@ -781,10 +791,12 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) vgadev->decodes = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; - /* by default mark it as decoding */ + /* By default, mark it as decoding */ vga_decode_count++; - /* Mark that we "own" resources based on our enables, we will - * clear that below if the bridge isn't forwarding + + /* + * Mark that we "own" resources based on our enables, we will + * clear that below if the bridge isn't forwarding. */ pci_read_config_word(pdev, PCI_COMMAND, &cmd); if (cmd & PCI_COMMAND_IO) @@ -864,7 +876,7 @@ bail: return ret; } -/* This is called with the lock */ +/* Called with the lock */ static void vga_update_device_decodes(struct vga_device *vgadev, unsigned int new_decodes) { @@ -889,7 +901,7 @@ static void vga_update_device_decodes(struct vga_device *vgadev, __vga_put(vgadev, decodes_unlocked); } - /* change decodes counter */ + /* Change decodes counter */ if (old_decodes & VGA_RSRC_LEGACY_MASK && !(new_decodes & VGA_RSRC_LEGACY_MASK)) vga_decode_count--; @@ -913,16 +925,17 @@ static void __vga_set_legacy_decoding(struct pci_dev *pdev, if (vgadev == NULL) goto bail; - /* don't let userspace futz with kernel driver decodes */ + /* Don't let userspace futz with kernel driver decodes */ if (userspace && vgadev->set_decode) goto bail; - /* update the device decodes + counter */ + /* Update the device decodes + counter */ vga_update_device_decodes(vgadev, decodes); - /* XXX if somebody is going from "doesn't decode" to "decodes" state - * here, additional care must be taken as we may have pending owner - * ship of non-legacy region ... + /* + * XXX If somebody is going from "doesn't decode" to "decodes" + * state here, additional care must be taken as we may have pending + * ownership of non-legacy region. */ bail: spin_unlock_irqrestore(&vga_lock, flags); @@ -930,10 +943,10 @@ bail: /** * vga_set_legacy_decoding - * @pdev: pci device of the VGA card + * @pdev: PCI device of the VGA card * @decodes: bit mask of what legacy regions the card decodes * - * Indicates to the arbiter if the card decodes legacy VGA IOs, legacy VGA + * Indicate to the arbiter if the card decodes legacy VGA IOs, legacy VGA * Memory, both, or none. All cards default to both, the card driver (fbdev for * example) should tell the arbiter if it has disabled legacy decoding, so the * card can be left out of the arbitration process (and can be safe to take @@ -947,25 +960,25 @@ EXPORT_SYMBOL(vga_set_legacy_decoding); /** * vga_client_register - register or unregister a VGA arbitration client - * @pdev: pci device of the VGA client - * @set_decode: vga decode change callback + * @pdev: PCI device of the VGA client + * @set_decode: VGA decode change callback * * Clients have two callback mechanisms they can use. * * @set_decode callback: If a client can disable its GPU VGA resource, it * will get a callback from this to set the encode/decode state. * - * Rationale: we cannot disable VGA decode resources unconditionally some single - * GPU laptops seem to require ACPI or BIOS access to the VGA registers to - * control things like backlights etc. Hopefully newer multi-GPU laptops do - * something saner, and desktops won't have any special ACPI for this. The - * driver will get a callback when VGA arbitration is first used by userspace - * since some older X servers have issues. + * Rationale: we cannot disable VGA decode resources unconditionally + * because some single GPU laptops seem to require ACPI or BIOS access to + * the VGA registers to control things like backlights etc. Hopefully newer + * multi-GPU laptops do something saner, and desktops won't have any + * special ACPI for this. The driver will get a callback when VGA + * arbitration is first used by userspace since some older X servers have + * issues. * - * This function does not check whether a client for @pdev has been registered - * already. + * Does not check whether a client for @pdev has been registered already. * - * To unregister just call vga_client_unregister(). + * To unregister, call vga_client_unregister(). * * Returns: 0 on success, -ENODEV on failure */ @@ -991,13 +1004,13 @@ EXPORT_SYMBOL(vga_client_register); * * Semantics is: * - * open : open user instance of the arbitrer. by default, it's + * open : Open user instance of the arbiter. By default, it's * attached to the default VGA device of the system. * - * close : close user instance, release locks + * close : Close user instance, release locks * - * read : return a string indicating the status of the target. - * an IO state string is of the form {io,mem,io+mem,none}, + * read : Return a string indicating the status of the target. + * An IO state string is of the form {io,mem,io+mem,none}, * mc and ic are respectively mem and io lock counts (for * debugging/diagnostic only). "decodes" indicate what the * card currently decodes, "owns" indicates what is currently @@ -1011,7 +1024,7 @@ EXPORT_SYMBOL(vga_client_register); * write : write a command to the arbiter. List of commands is: * * target : switch target to card (see below) - * lock : acquires locks on target ("none" is invalid io_state) + * lock : acquire locks on target ("none" is invalid io_state) * trylock : non-blocking acquire locks on target * unlock : release locks on target * unlock all : release all locks on target held by this user @@ -1028,23 +1041,21 @@ EXPORT_SYMBOL(vga_client_register); * Note about locks: * * The driver keeps track of which user has what locks on which card. It - * supports stacking, like the kernel one. This complexifies the implementation + * supports stacking, like the kernel one. This complicates the implementation * a bit, but makes the arbiter more tolerant to userspace problems and able * to properly cleanup in all cases when a process dies. * Currently, a max of 16 cards simultaneously can have locks issued from * userspace for a given user (file descriptor instance) of the arbiter. * * If the device is hot-unplugged, there is a hook inside the module to notify - * they being added/removed in the system and automatically added/removed in + * it being added/removed in the system and automatically added/removed in * the arbiter. */ #define MAX_USER_CARDS CONFIG_VGA_ARB_MAX_GPUS #define PCI_INVALID_CARD ((struct pci_dev *)-1UL) -/* - * Each user has an array of these, tracking which cards have locks - */ +/* Each user has an array of these, tracking which cards have locks */ struct vga_arb_user_card { struct pci_dev *pdev; unsigned int mem_cnt; @@ -1063,9 +1074,8 @@ static DEFINE_SPINLOCK(vga_user_lock); /* - * This function gets a string in the format: "PCI:domain:bus:dev.fn" and - * returns the respective values. If the string is not in this format, - * it returns 0. + * Take a string in the format: "PCI:domain:bus:dev.fn" and return the + * respective values. If the string is not in this format, return 0. */ static int vga_pci_str_to_vars(char *buf, int count, unsigned int *domain, unsigned int *bus, unsigned int *devfn) @@ -1073,7 +1083,6 @@ static int vga_pci_str_to_vars(char *buf, int count, unsigned int *domain, int n; unsigned int slot, func; - n = sscanf(buf, "PCI:%x:%x:%x.%x", domain, bus, &slot, &func); if (n != 4) return 0; @@ -1098,7 +1107,7 @@ static ssize_t vga_arb_read(struct file *file, char __user *buf, if (lbuf == NULL) return -ENOMEM; - /* Protects vga_list */ + /* Protect vga_list */ spin_lock_irqsave(&vga_lock, flags); /* If we are targeting the default, use it */ @@ -1112,15 +1121,16 @@ static ssize_t vga_arb_read(struct file *file, char __user *buf, /* Find card vgadev structure */ vgadev = vgadev_find(pdev); if (vgadev == NULL) { - /* Wow, it's not in the list, that shouldn't happen, - * let's fix us up and return invalid card + /* + * Wow, it's not in the list, that shouldn't happen, let's + * fix us up and return invalid card. */ spin_unlock_irqrestore(&vga_lock, flags); len = sprintf(lbuf, "invalid"); goto done; } - /* Fill the buffer with infos */ + /* Fill the buffer with info */ len = snprintf(lbuf, 1024, "count:%d,PCI:%s,decodes=%s,owns=%s,locks=%s(%u:%u)\n", vga_decode_count, pci_name(pdev), @@ -1166,7 +1176,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, if (copy_from_user(kbuf, buf, count)) return -EFAULT; curr_pos = kbuf; - kbuf[count] = '\0'; /* Just to make sure... */ + kbuf[count] = '\0'; if (strncmp(curr_pos, "lock ", 5) == 0) { curr_pos += 5; @@ -1191,7 +1201,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, vga_get_uninterruptible(pdev, io_state); - /* Update the client's locks lists... */ + /* Update the client's locks lists */ for (i = 0; i < MAX_USER_CARDS; i++) { if (priv->cards[i].pdev == pdev) { if (io_state & VGA_RSRC_LEGACY_IO) @@ -1308,7 +1318,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, curr_pos += 7; remaining -= 7; pr_debug("client 0x%p called 'target'\n", priv); - /* if target is default */ + /* If target is default */ if (!strncmp(curr_pos, "default", 7)) pdev = pci_dev_get(vga_default_device()); else { @@ -1358,7 +1368,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, vgaarb_dbg(&pdev->dev, "maximum user cards (%d) number reached, ignoring this one!\n", MAX_USER_CARDS); pci_dev_put(pdev); - /* XXX: which value to return? */ + /* XXX: Which value to return? */ ret_val = -ENOMEM; goto done; } @@ -1419,13 +1429,12 @@ static int vga_arb_open(struct inode *inode, struct file *file) list_add(&priv->list, &vga_user_list); spin_unlock_irqrestore(&vga_user_lock, flags); - /* Set the client' lists of locks */ + /* Set the client's lists of locks */ priv->target = vga_default_device(); /* Maybe this is still null! */ priv->cards[0].pdev = priv->target; priv->cards[0].io_cnt = 0; priv->cards[0].mem_cnt = 0; - return 0; } @@ -1459,8 +1468,8 @@ static int vga_arb_release(struct inode *inode, struct file *file) } /* - * callback any registered clients to let them know we have a - * change in VGA cards + * Callback any registered clients to let them know we have a change in VGA + * cards. */ static void vga_arbiter_notify_clients(void) { @@ -1494,9 +1503,11 @@ static int pci_notify(struct notifier_block *nb, unsigned long action, vgaarb_dbg(dev, "%s\n", __func__); - /* For now we're only intereted in devices added and removed. I didn't - * test this thing here, so someone needs to double check for the - * cases of hotplugable vga cards. */ + /* + * For now, we're only interested in devices added and removed. + * I didn't test this thing here, so someone needs to double check + * for the cases of hot-pluggable VGA cards. + */ if (action == BUS_NOTIFY_ADD_DEVICE) notify = vga_arbiter_add_pci_device(pdev); else if (action == BUS_NOTIFY_DEL_DEVICE) @@ -1535,8 +1546,7 @@ static int __init vga_arb_device_init(void) bus_register_notifier(&pci_bus_type, &pci_notifier); - /* We add all PCI devices satisfying VGA class in the arbiter by - * default */ + /* Add all VGA class PCI devices by default */ pdev = NULL; while ((pdev = pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h index ed5e5462f1d2..97129a1bbb7d 100644 --- a/include/linux/vgaarb.h +++ b/include/linux/vgaarb.h @@ -77,7 +77,7 @@ static inline int vga_client_register(struct pci_dev *pdev, static inline int vga_get_interruptible(struct pci_dev *pdev, unsigned int rsrc) { - return vga_get(pdev, rsrc, 1); + return vga_get(pdev, rsrc, 1); } /** @@ -92,7 +92,7 @@ static inline int vga_get_interruptible(struct pci_dev *pdev, static inline int vga_get_uninterruptible(struct pci_dev *pdev, unsigned int rsrc) { - return vga_get(pdev, rsrc, 0); + return vga_get(pdev, rsrc, 0); } static inline void vga_client_unregister(struct pci_dev *pdev) -- cgit v1.2.3 From ea91512ded9963d8ca98eab67d7d182a989813d9 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Fri, 11 Aug 2023 17:59:33 +0800 Subject: PCI: Remove unused function declarations The following declarations have never been implemented since the beginning of git history, so remove them: u8 acpiphp_get_attention_status(struct acpiphp_slot *slot); u8 cpci_get_latch_status(struct slot *slot); u8 cpci_get_adapter_status(struct slot *slot); int ibmphp_get_total_hp_slots(void); void ibmphp_free_ibm_slot(struct slot *); void pdev_enable_device(struct pci_dev *); Link: https://lore.kernel.org/r/20230811095933.28652-1-yuehaibing@huawei.com Signed-off-by: Yue Haibing Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/cpci_hotplug.h | 2 -- drivers/pci/hotplug/ibmphp.h | 2 -- include/linux/pci.h | 1 - 4 files changed, 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 1f8ab4377ad8..5745be6018e1 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -178,7 +178,6 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); int acpiphp_enable_slot(struct acpiphp_slot *slot); int acpiphp_disable_slot(struct acpiphp_slot *slot); u8 acpiphp_get_power_status(struct acpiphp_slot *slot); -u8 acpiphp_get_attention_status(struct acpiphp_slot *slot); u8 acpiphp_get_latch_status(struct acpiphp_slot *slot); u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot); diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index 3fdd1b9bd8c3..6d8970d8c3f2 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -83,8 +83,6 @@ extern int cpci_debug; * board/chassis drivers. */ u8 cpci_get_attention_status(struct slot *slot); -u8 cpci_get_latch_status(struct slot *slot); -u8 cpci_get_adapter_status(struct slot *slot); u16 cpci_get_hs_csr(struct slot *slot); int cpci_set_attention_status(struct slot *slot, int status); int cpci_check_and_clear_ins(struct slot *slot); diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index 0399c60d2ec1..41eafe511210 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -264,8 +264,6 @@ extern struct list_head ibmphp_slot_head; void ibmphp_free_ebda_hpc_queue(void); int ibmphp_access_ebda(void); struct slot *ibmphp_get_slot_from_physical_num(u8); -int ibmphp_get_total_hp_slots(void); -void ibmphp_free_ibm_slot(struct slot *); void ibmphp_free_bus_info_queue(void); void ibmphp_free_ebda_pci_rsrc_queue(void); struct bus_info *ibmphp_find_same_bus_num(u32); diff --git a/include/linux/pci.h b/include/linux/pci.h index b4eae9f2e1fc..7d81aff09153 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1403,7 +1403,6 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); void pci_assign_unassigned_bus_resources(struct pci_bus *bus); void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus); int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type); -void pdev_enable_device(struct pci_dev *); int pci_enable_resources(struct pci_dev *, int mask); void pci_assign_irq(struct pci_dev *dev); struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res); -- cgit v1.2.3 From e8c81fc72232c4a82257745bd5ebf5b79929a613 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Thu, 24 Aug 2023 14:01:42 -0500 Subject: PCI: mvebu: Remove unused busn member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The busn member of struct mvebu_pcie is unused, so drop it. Link: https://lore.kernel.org/r/20220905192310.22786-5-pali@kernel.org Signed-off-by: Pali Rohár Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Cc: Thomas Petazzoni --- drivers/pci/controller/pci-mvebu.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index c931b1b07b1d..60810a1fbfb7 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -87,7 +87,6 @@ struct mvebu_pcie { struct resource io; struct resource realio; struct resource mem; - struct resource busn; int nports; }; -- cgit v1.2.3 From ecfea5dfca147a14c47539014ca24a80a469e08f Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 9 Jun 2020 15:27:35 -0500 Subject: PCI: Unexport pcie_port_bus_type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pcie_port_bus_type is used only in pci-driver.c and pcie/portdrv_core.c and pcie/portdrv_pci.c. None of these can be built as modules, so pcie_port_bus_type doesn't need to be exported. Unexport it. Link: https://lore.kernel.org/r/20230824193712.542167-3-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/pci-driver.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index ae9baf801681..1f9845377eff 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1705,7 +1705,6 @@ struct bus_type pcie_port_bus_type = { .name = "pci_express", .match = pcie_port_bus_match, }; -EXPORT_SYMBOL_GPL(pcie_port_bus_type); #endif static int __init pci_driver_init(void) -- cgit v1.2.3 From a49287d32d57b1bae7d53c2e6fba1b729e782568 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 6 Oct 2020 16:54:39 -0500 Subject: PCI: Remove unnecessary initializations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We always assign "fields" immediately, so remove the unnecessary initializations. No functional change intended. Link: https://lore.kernel.org/r/20230824193712.542167-4-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/pci-driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 1f9845377eff..a44ecf6bf5d2 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -193,7 +193,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, u32 vendor, device, subvendor = PCI_ANY_ID, subdevice = PCI_ANY_ID, class = 0, class_mask = 0; unsigned long driver_data = 0; - int fields = 0; + int fields; int retval = 0; fields = sscanf(buf, "%x %x %x %x %x %x %lx", @@ -260,7 +260,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf, struct pci_driver *pdrv = to_pci_driver(driver); u32 vendor, device, subvendor = PCI_ANY_ID, subdevice = PCI_ANY_ID, class = 0, class_mask = 0; - int fields = 0; + int fields; size_t retval = -ENODEV; fields = sscanf(buf, "%x %x %x %x %x %x", -- cgit v1.2.3 From 62008578b73f16e274070a232b939ba5933bb8ba Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 15 Jan 2021 17:18:36 -0600 Subject: PCI: Fix printk field formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we used "%#08x" to print a 32-bit value. This fills an 8-character field with "0x...", but of course many 32-bit values require a 10-character field "0x12345678" for this format. Fix the formats to avoid confusion. Link: https://lore.kernel.org/r/20230824193712.542167-5-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/setup-res.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 967f9a758923..ceaa69491f5e 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -104,7 +104,7 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno) pci_read_config_dword(dev, reg, &check); if ((new ^ check) & mask) { - pci_err(dev, "BAR %d: error updating (%#08x != %#08x)\n", + pci_err(dev, "BAR %d: error updating (%#010x != %#010x)\n", resno, new, check); } @@ -113,7 +113,7 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno) pci_write_config_dword(dev, reg + 4, new); pci_read_config_dword(dev, reg + 4, &check); if (check != new) { - pci_err(dev, "BAR %d: error updating (high %#08x != %#08x)\n", + pci_err(dev, "BAR %d: error updating (high %#010x != %#010x)\n", resno, new, check); } } -- cgit v1.2.3 From 32e2a3f938f6a170dec86acca5fa9810d33552f8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 25 Jan 2021 11:57:38 -0600 Subject: PCI: Use consistent put_user() pointer types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used u8, u16, and u32 for get_user() pointer types, but "unsigned char", "unsigned short", and "unsigned int" for put_user(). Use u8, u16, and u32 for put_user() for consistency. No functional change intended. Link: https://lore.kernel.org/r/20230824193712.542167-6-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/syscall.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index 61a6fe3cde21..803acbf33eb2 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -52,13 +52,13 @@ SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn, switch (len) { case 1: - err = put_user(byte, (unsigned char __user *)buf); + err = put_user(byte, (u8 __user *)buf); break; case 2: - err = put_user(word, (unsigned short __user *)buf); + err = put_user(word, (u16 __user *)buf); break; case 4: - err = put_user(dword, (unsigned int __user *)buf); + err = put_user(dword, (u32 __user *)buf); break; } pci_dev_put(dev); @@ -70,13 +70,13 @@ error: they get instead of a machine check on x86. */ switch (len) { case 1: - put_user(-1, (unsigned char __user *)buf); + put_user(-1, (u8 __user *)buf); break; case 2: - put_user(-1, (unsigned short __user *)buf); + put_user(-1, (u16 __user *)buf); break; case 4: - put_user(-1, (unsigned int __user *)buf); + put_user(-1, (u32 __user *)buf); break; } pci_dev_put(dev); -- cgit v1.2.3 From 95881c86c987eb73936e5eb3cf93b9b17d137d5a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 27 May 2020 16:01:48 -0500 Subject: PCI/AER: Simplify AER_RECOVER_RING_SIZE definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACPI Platform Error Interfaces (APEI) convey error information to the OS. If the APEI GHES driver receives information about PCI errors, it queues it in aer_recover_ring for processing by the PCI AER code. AER_RECOVER_RING_SIZE is the size of the aer_recover_ring FIFO and is arbitrary, with no direct connection to hardware. AER_RECOVER_RING_ORDER was only used to compute AER_RECOVER_RING_SIZE. Remove it and define AER_RECOVER_RING_SIZE directly. No functional change intended. Link: https://lore.kernel.org/r/20230824193712.542167-7-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/pcie/aer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 2bc03937452b..a30784dabdd7 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -981,8 +981,7 @@ static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info) #ifdef CONFIG_ACPI_APEI_PCIEAER -#define AER_RECOVER_RING_ORDER 4 -#define AER_RECOVER_RING_SIZE (1 << AER_RECOVER_RING_ORDER) +#define AER_RECOVER_RING_SIZE 16 struct aer_recover_entry { u8 bus; -- cgit v1.2.3 From 3b59ca944687b8651849f51b15c23e3fdbf07394 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 7 Dec 2020 13:55:06 -0600 Subject: PCI: Simplify pci_pio_to_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify pci_pio_to_address() by removing an unnecessary local variable. No functional change intended. Link: https://lore.kernel.org/r/20230824193712.542167-8-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/pci.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 60230da957e0..4d2b11c71e62 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4191,16 +4191,12 @@ int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr, phys_addr_t pci_pio_to_address(unsigned long pio) { - phys_addr_t address = (phys_addr_t)OF_BAD_ADDR; - #ifdef PCI_IOBASE - if (pio >= MMIO_UPPER_LIMIT) - return address; - - address = logic_pio_to_hwaddr(pio); + if (pio < MMIO_UPPER_LIMIT) + return logic_pio_to_hwaddr(pio); #endif - return address; + return (phys_addr_t) OF_BAD_ADDR; } EXPORT_SYMBOL_GPL(pci_pio_to_address); -- cgit v1.2.3 From 1ec09529bd19d8052655c12c3466ee5f5fe9f7f7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 6 Oct 2020 16:49:17 -0500 Subject: PCI: Simplify pci_dev_driver() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify pci_dev_driver() by removing the "else". The "if" case always returns, so the "else" is superfluous. No functional change intended. Link: https://lore.kernel.org/r/20230824193712.542167-9-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/pci-driver.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index a44ecf6bf5d2..a79c110c7e51 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1474,14 +1474,15 @@ static struct pci_driver pci_compat_driver = { */ struct pci_driver *pci_dev_driver(const struct pci_dev *dev) { + int i; + if (dev->driver) return dev->driver; - else { - int i; - for (i = 0; i <= PCI_ROM_RESOURCE; i++) - if (dev->resource[i].flags & IORESOURCE_BUSY) - return &pci_compat_driver; - } + + for (i = 0; i <= PCI_ROM_RESOURCE; i++) + if (dev->resource[i].flags & IORESOURCE_BUSY) + return &pci_compat_driver; + return NULL; } EXPORT_SYMBOL(pci_dev_driver); -- cgit v1.2.3 From 2b4af4b3988a6c0175af3c9a65c87d97e94dc34e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 24 Aug 2023 12:02:32 -0500 Subject: PCI: Fix pci_bus_resetable(), pci_slot_resetable() name typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix typos in the pci_bus_resetable() and pci_slot_resetable() function names. No functional change intended. Link: https://lore.kernel.org/r/20230824193712.542167-10-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/pci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4d2b11c71e62..6b62795425a7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5627,7 +5627,7 @@ int pci_try_reset_function(struct pci_dev *dev) EXPORT_SYMBOL_GPL(pci_try_reset_function); /* Do any devices on or below this bus prevent a bus reset? */ -static bool pci_bus_resetable(struct pci_bus *bus) +static bool pci_bus_resettable(struct pci_bus *bus) { struct pci_dev *dev; @@ -5637,7 +5637,7 @@ static bool pci_bus_resetable(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || - (dev->subordinate && !pci_bus_resetable(dev->subordinate))) + (dev->subordinate && !pci_bus_resettable(dev->subordinate))) return false; } @@ -5695,7 +5695,7 @@ unlock: } /* Do any devices on or below this slot prevent a bus reset? */ -static bool pci_slot_resetable(struct pci_slot *slot) +static bool pci_slot_resettable(struct pci_slot *slot) { struct pci_dev *dev; @@ -5707,7 +5707,7 @@ static bool pci_slot_resetable(struct pci_slot *slot) if (!dev->slot || dev->slot != slot) continue; if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || - (dev->subordinate && !pci_bus_resetable(dev->subordinate))) + (dev->subordinate && !pci_bus_resettable(dev->subordinate))) return false; } @@ -5843,7 +5843,7 @@ static int pci_slot_reset(struct pci_slot *slot, bool probe) { int rc; - if (!slot || !pci_slot_resetable(slot)) + if (!slot || !pci_slot_resettable(slot)) return -ENOTTY; if (!probe) @@ -5910,7 +5910,7 @@ static int pci_bus_reset(struct pci_bus *bus, bool probe) { int ret; - if (!bus->self || !pci_bus_resetable(bus)) + if (!bus->self || !pci_bus_resettable(bus)) return -ENOTTY; if (probe) -- cgit v1.2.3 From 86b4ad7d67b26973838b7f1d4428aba9483cb5ce Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 24 Aug 2023 11:44:32 -0500 Subject: PCI: Fix typos in docs and comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix typos in docs and comments. Link: https://lore.kernel.org/r/20230824193712.542167-11-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Randy Dunlap Reviewed-by: Ilpo Järvinen --- Documentation/PCI/pci-error-recovery.rst | 12 +++++----- drivers/pci/controller/cadence/pcie-cadence.h | 2 +- drivers/pci/endpoint/functions/pci-epf-vntb.c | 32 +++++++++++++-------------- drivers/pci/msi/irqdomain.c | 4 ++-- drivers/pci/p2pdma.c | 2 +- drivers/pci/pci.c | 2 +- drivers/pci/probe.c | 2 +- drivers/pci/quirks.c | 8 +++---- drivers/pci/setup-bus.c | 2 +- 9 files changed, 33 insertions(+), 33 deletions(-) (limited to 'drivers/pci') diff --git a/Documentation/PCI/pci-error-recovery.rst b/Documentation/PCI/pci-error-recovery.rst index c237596f67e3..0c7552a00c8c 100644 --- a/Documentation/PCI/pci-error-recovery.rst +++ b/Documentation/PCI/pci-error-recovery.rst @@ -17,7 +17,7 @@ chipsets are able to deal with these errors; these include PCI-E chipsets, and the PCI-host bridges found on IBM Power4, Power5 and Power6-based pSeries boxes. A typical action taken is to disconnect the affected device, halting all I/O to it. The goal of a disconnection is to avoid system -corruption; for example, to halt system memory corruption due to DMA's +corruption; for example, to halt system memory corruption due to DMAs to "wild" addresses. Typically, a reconnection mechanism is also offered, so that the affected PCI device(s) are reset and put back into working condition. The reset phase requires coordination @@ -178,9 +178,9 @@ is STEP 6 (Permanent Failure). complex and not worth implementing. The current powerpc implementation doesn't much care if the device - attempts I/O at this point, or not. I/O's will fail, returning + attempts I/O at this point, or not. I/Os will fail, returning a value of 0xff on read, and writes will be dropped. If more than - EEH_MAX_FAILS I/O's are attempted to a frozen adapter, EEH + EEH_MAX_FAILS I/Os are attempted to a frozen adapter, EEH assumes that the device driver has gone into an infinite loop and prints an error to syslog. A reboot is then required to get the device working again. @@ -204,7 +204,7 @@ instead will have gone directly to STEP 3 (Link Reset) or STEP 4 (Slot Reset) .. note:: The following is proposed; no platform implements this yet: - Proposal: All I/O's should be done _synchronously_ from within + Proposal: All I/Os should be done _synchronously_ from within this callback, errors triggered by them will be returned via the normal pci_check_whatever() API, no new error_detected() callback will be issued due to an error happening here. However, @@ -258,7 +258,7 @@ Powerpc platforms implement two levels of slot reset: soft reset(default) and fundamental(optional) reset. Powerpc soft reset consists of asserting the adapter #RST line and then -restoring the PCI BAR's and PCI configuration header to a state +restoring the PCI BARs and PCI configuration header to a state that is equivalent to what it would be after a fresh system power-on followed by power-on BIOS/system firmware initialization. Soft reset is also known as hot-reset. @@ -362,7 +362,7 @@ permanent failure in some way. If the device is hotplug-capable, the operator will probably want to remove and replace the device. Note, however, not all failures are truly "permanent". Some are caused by over-heating, some by a poorly seated card. Many -PCI error events are caused by software bugs, e.g. DMA's to +PCI error events are caused by software bugs, e.g. DMAs to wild addresses or bogus split transactions due to programming errors. See the discussion in Documentation/powerpc/eeh-pci-error-recovery.rst for additional detail on real-life experience of the causes of diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 190786e47df9..373cb50fcd15 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -32,7 +32,7 @@ #define CDNS_PCIE_LM_ID_SUBSYS(sub) \ (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK) -/* Root Port Requestor ID Register */ +/* Root Port Requester ID Register */ #define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228) #define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0) #define CDNS_PCIE_LM_RP_RID_SHIFT 0 diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c index c8b423c3c26e..3f60128560ed 100644 --- a/drivers/pci/endpoint/functions/pci-epf-vntb.c +++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c @@ -986,22 +986,22 @@ static struct config_group *epf_ntb_add_cfs(struct pci_epf *epf, /*==== virtual PCI bus driver, which only load virtual NTB PCI driver ====*/ static u32 pci_space[] = { - 0xffffffff, /*DeviceID, Vendor ID*/ - 0, /*Status, Command*/ - 0xffffffff, /*Class code, subclass, prog if, revision id*/ - 0x40, /*bist, header type, latency Timer, cache line size*/ - 0, /*BAR 0*/ - 0, /*BAR 1*/ - 0, /*BAR 2*/ - 0, /*BAR 3*/ - 0, /*BAR 4*/ - 0, /*BAR 5*/ - 0, /*Cardbus cis point*/ - 0, /*Subsystem ID Subystem vendor id*/ - 0, /*ROM Base Address*/ - 0, /*Reserved, Cap. Point*/ - 0, /*Reserved,*/ - 0, /*Max Lat, Min Gnt, interrupt pin, interrupt line*/ + 0xffffffff, /* Device ID, Vendor ID */ + 0, /* Status, Command */ + 0xffffffff, /* Base Class, Subclass, Prog Intf, Revision ID */ + 0x40, /* BIST, Header Type, Latency Timer, Cache Line Size */ + 0, /* BAR 0 */ + 0, /* BAR 1 */ + 0, /* BAR 2 */ + 0, /* BAR 3 */ + 0, /* BAR 4 */ + 0, /* BAR 5 */ + 0, /* Cardbus CIS Pointer */ + 0, /* Subsystem ID, Subsystem Vendor ID */ + 0, /* ROM Base Address */ + 0, /* Reserved, Capabilities Pointer */ + 0, /* Reserved */ + 0, /* Max_Lat, Min_Gnt, Interrupt Pin, Interrupt Line */ }; static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c index e33bcc872699..c8be056c248d 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -336,7 +336,7 @@ bool pci_msi_domain_supports(struct pci_dev *pdev, unsigned int feature_mask, if (!irq_domain_is_msi_parent(domain)) { /* * For "global" PCI/MSI interrupt domains the associated - * msi_domain_info::flags is the authoritive source of + * msi_domain_info::flags is the authoritative source of * information. */ info = domain->host_data; @@ -344,7 +344,7 @@ bool pci_msi_domain_supports(struct pci_dev *pdev, unsigned int feature_mask, } else { /* * For MSI parent domains the supported feature set - * is avaliable in the parent ops. This makes checks + * is available in the parent ops. This makes checks * possible before actually instantiating the * per device domain because the parent is never * expanding the PCI/MSI functionality. diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index ec04d0ed157b..fa7370f9561a 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -435,7 +435,7 @@ static const struct pci_p2pdma_whitelist_entry { /* Intel Xeon E7 v3/Xeon E5 v3/Core i7 */ {PCI_VENDOR_ID_INTEL, 0x2f00, REQ_SAME_HOST_BRIDGE}, {PCI_VENDOR_ID_INTEL, 0x2f01, REQ_SAME_HOST_BRIDGE}, - /* Intel SkyLake-E */ + /* Intel Skylake-E */ {PCI_VENDOR_ID_INTEL, 0x2030, 0}, {PCI_VENDOR_ID_INTEL, 0x2031, 0}, {PCI_VENDOR_ID_INTEL, 0x2032, 0}, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6b62795425a7..749ef90c623d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1290,7 +1290,7 @@ end: * * Call pci_power_up() to put @dev into D0, read from its PCI_PM_CTRL register * to confirm the state change, restore its BARs if they might be lost and - * reconfigure ASPM in acordance with the new power state. + * reconfigure ASPM in accordance with the new power state. * * If pci_restore_state() is going to be called right after a power state change * to D0, it is more efficient to use pci_power_up() directly instead of this diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 31fb02fbb2cc..deb5286f8533 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2136,7 +2136,7 @@ static void pci_configure_relaxed_ordering(struct pci_dev *dev) { struct pci_dev *root; - /* PCI_EXP_DEVICE_RELAX_EN is RsvdP in VFs */ + /* PCI_EXP_DEVCTL_RELAX_EN is RsvdP in VFs */ if (dev->is_virtfn) return; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 321156ca273d..e2afa3918367 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -362,7 +362,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_d #endif /* - * Intel NM10 "TigerPoint" LPC PM1a_STS.BM_STS must be clear + * Intel NM10 "Tiger Point" LPC PM1a_STS.BM_STS must be clear * for some HT machines to use C4 w/o hanging. */ static void quirk_tigerpoint_bm_sts(struct pci_dev *dev) @@ -375,7 +375,7 @@ static void quirk_tigerpoint_bm_sts(struct pci_dev *dev) pm1a = inw(pmbase); if (pm1a & 0x10) { - pci_info(dev, FW_BUG "TigerPoint LPC.BM_STS cleared\n"); + pci_info(dev, FW_BUG "Tiger Point LPC.BM_STS cleared\n"); outw(0x10, pmbase); } } @@ -3073,7 +3073,7 @@ static void __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all) /* * HT MSI mapping should be disabled on devices that are below - * a non-Hypertransport host bridge. Locate the host bridge... + * a non-HyperTransport host bridge. Locate the host bridge. */ host_bridge = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus), 0, PCI_DEVFN(0, 0)); @@ -5729,7 +5729,7 @@ int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout) /* * Microsemi Switchtec NTB uses devfn proxy IDs to move TLPs between * NT endpoints via the internal switch fabric. These IDs replace the - * originating requestor ID TLPs which access host memory on peer NTB + * originating Requester ID TLPs which access host memory on peer NTB * ports. Therefore, all proxy IDs must be aliased to the NTB device * to permit access when the IOMMU is turned on. */ diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index fdeb121e9175..dae490f25641 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1799,7 +1799,7 @@ static void remove_dev_resources(struct pci_dev *dev, struct resource *io, * Make sure prefetchable memory is reduced from * the correct resource. Specifically we put 32-bit * prefetchable memory in non-prefetchable window - * if there is an 64-bit pretchable window. + * if there is an 64-bit prefetchable window. * * See comments in __pci_bus_size_bridges() for * more information. -- cgit v1.2.3 From eb6723b40d1766cfbbbc0aa11690da03c339184f Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 24 Aug 2023 13:33:05 -0500 Subject: PCI: Fix code formatting inconsistencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary "return;" in void functions and format consistently. No functional change intended. Link: https://lore.kernel.org/r/20230824193712.542167-12-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/pci.h | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a4c397434057..096fa6834f3b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -147,8 +147,8 @@ int pci_hp_add_bridge(struct pci_dev *dev); void pci_create_legacy_files(struct pci_bus *bus); void pci_remove_legacy_files(struct pci_bus *bus); #else -static inline void pci_create_legacy_files(struct pci_bus *bus) { return; } -static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; } +static inline void pci_create_legacy_files(struct pci_bus *bus) { } +static inline void pci_remove_legacy_files(struct pci_bus *bus) { } #endif /* Lock for read/write access to pci device and bus lists */ @@ -422,9 +422,9 @@ void dpc_process_error(struct pci_dev *pdev); pci_ers_result_t dpc_reset_link(struct pci_dev *pdev); bool pci_dpc_recovered(struct pci_dev *pdev); #else -static inline void pci_save_dpc_state(struct pci_dev *dev) {} -static inline void pci_restore_dpc_state(struct pci_dev *dev) {} -static inline void pci_dpc_init(struct pci_dev *pdev) {} +static inline void pci_save_dpc_state(struct pci_dev *dev) { } +static inline void pci_restore_dpc_state(struct pci_dev *dev) { } +static inline void pci_dpc_init(struct pci_dev *pdev) { } static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; } #endif @@ -436,12 +436,12 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *), void *userdata); #else -static inline void pci_rcec_init(struct pci_dev *dev) {} -static inline void pci_rcec_exit(struct pci_dev *dev) {} -static inline void pcie_link_rcec(struct pci_dev *rcec) {} +static inline void pci_rcec_init(struct pci_dev *dev) { } +static inline void pci_rcec_exit(struct pci_dev *dev) { } +static inline void pcie_link_rcec(struct pci_dev *rcec) { } static inline void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *), - void *userdata) {} + void *userdata) { } #endif #ifdef CONFIG_PCI_ATS @@ -484,16 +484,9 @@ static inline int pci_iov_init(struct pci_dev *dev) { return -ENODEV; } -static inline void pci_iov_release(struct pci_dev *dev) - -{ -} -static inline void pci_iov_remove(struct pci_dev *dev) -{ -} -static inline void pci_restore_iov_state(struct pci_dev *dev) -{ -} +static inline void pci_iov_release(struct pci_dev *dev) { } +static inline void pci_iov_remove(struct pci_dev *dev) { } +static inline void pci_restore_iov_state(struct pci_dev *dev) { } static inline int pci_iov_bus_range(struct pci_bus *bus) { return 0; @@ -718,7 +711,7 @@ static inline int pci_dev_acpi_reset(struct pci_dev *dev, bool probe) { return -ENOTTY; } -static inline void pci_set_acpi_fwnode(struct pci_dev *dev) {} +static inline void pci_set_acpi_fwnode(struct pci_dev *dev) { } static inline int pci_acpi_program_hp_params(struct pci_dev *dev) { return -ENODEV; @@ -739,7 +732,7 @@ static inline pci_power_t acpi_pci_get_power_state(struct pci_dev *dev) { return PCI_UNKNOWN; } -static inline void acpi_pci_refresh_power_state(struct pci_dev *dev) {} +static inline void acpi_pci_refresh_power_state(struct pci_dev *dev) { } static inline int acpi_pci_wakeup(struct pci_dev *dev, bool enable) { return -ENODEV; -- cgit v1.2.3 From 1856d1a036dcd1835ce35957ca65c00cf350daf4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 14 Dec 2022 11:21:37 -0600 Subject: PCI: Tidy config space save/restore messages Update config space save/restore debug messages so they line up better. Previously: nvme 0000:05:00.0: saving config space at offset 0x4 (reading 0x20100006) nvme 0000:05:00.0: saving config space at offset 0x8 (reading 0x1080200) nvme 0000:05:00.0: saving config space at offset 0xc (reading 0x0) nvme 0000:05:00.0: restoring config space at offset 0x4 (was 0x0, writing 0x20100006) Now: nvme 0000:05:00.0: save config 0x04: 0x20100006 nvme 0000:05:00.0: save config 0x08: 0x01080200 nvme 0000:05:00.0: save config 0x0c: 0x00000000 nvme 0000:05:00.0: restore config 0x04: 0x00000000 -> 0x20100006 No functional change intended. Enable these messages by setting CONFIG_DYNAMIC_DEBUG=y and adding 'dyndbg="file drivers/pci/* +p"' to kernel parameters. Link: https://lore.kernel.org/r/20230823191831.476579-1-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 749ef90c623d..ea3dcab0978c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1681,7 +1681,7 @@ int pci_save_state(struct pci_dev *dev) /* XXX: 100% dword access ok here? */ for (i = 0; i < 16; i++) { pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]); - pci_dbg(dev, "saving config space at offset %#x (reading %#x)\n", + pci_dbg(dev, "save config %#04x: %#010x\n", i * 4, dev->saved_config_space[i]); } dev->state_saved = true; @@ -1712,7 +1712,7 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset, return; for (;;) { - pci_dbg(pdev, "restoring config space at offset %#x (was %#x, writing %#x)\n", + pci_dbg(pdev, "restore config %#04x: %#010x -> %#010x\n", offset, val, saved_val); pci_write_config_dword(pdev, offset, saved_val); if (retry-- <= 0) -- cgit v1.2.3 From 294c1e4fa73f545c7e1ac7e90a447c18094b318b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 24 Aug 2023 13:40:29 -0500 Subject: PCI: Simplify pcie_capability_clear_and_set_word() control flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return early for errors in pcie_capability_clear_and_set_word_unlocked() and pcie_capability_clear_and_set_dword() to simplify the control flow. No functional change intended. Link: https://lore.kernel.org/r/20230824193712.542167-13-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/access.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 0b2e90d2f04f..6554a2e89d36 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -504,13 +504,12 @@ int pcie_capability_clear_and_set_word_unlocked(struct pci_dev *dev, int pos, u16 val; ret = pcie_capability_read_word(dev, pos, &val); - if (!ret) { - val &= ~clear; - val |= set; - ret = pcie_capability_write_word(dev, pos, val); - } + if (ret) + return ret; - return ret; + val &= ~clear; + val |= set; + return pcie_capability_write_word(dev, pos, val); } EXPORT_SYMBOL(pcie_capability_clear_and_set_word_unlocked); @@ -535,13 +534,12 @@ int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, u32 val; ret = pcie_capability_read_dword(dev, pos, &val); - if (!ret) { - val &= ~clear; - val |= set; - ret = pcie_capability_write_dword(dev, pos, val); - } + if (ret) + return ret; - return ret; + val &= ~clear; + val |= set; + return pcie_capability_write_dword(dev, pos, val); } EXPORT_SYMBOL(pcie_capability_clear_and_set_dword); -- cgit v1.2.3 From 8cd2b8ce48e52bfda76a04be9aef8c1b176693d9 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 17 Jul 2023 12:24:53 +0530 Subject: PCI: qcom-ep: Pass alignment restriction to the EPF core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Qcom PCIe EP controllers have 4K alignment restriction for the outbound window address. Hence, pass this info to the EPF core so that the EPF drivers can make use of this info. Link: https://lore.kernel.org/linux-pci/20230717065459.14138-2-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 0fe7f06f2102..736be5bee458 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -706,6 +706,7 @@ static const struct pci_epc_features qcom_pcie_epc_features = { .core_init_notifier = true, .msi_capable = true, .msix_capable = false, + .align = SZ_4K, }; static const struct pci_epc_features * -- cgit v1.2.3 From d60379d65d2b908818d99541753d74f99645da51 Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Fri, 21 Jul 2023 22:54:33 +0530 Subject: PCI: qcom: Add support for sa8775p SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for sa8775p SoC that uses controller version 5.90 reusing the 1.9.0 config. Link: https://lore.kernel.org/linux-pci/1689960276-29266-3-git-send-email-quic_msarkar@quicinc.com Signed-off-by: Mrinmay Sarkar Signed-off-by: Krzysztof Wilczyński Reviewed-by: Bjorn Andersson Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 7a87a47eb7ed..3c3de787f5a3 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1613,6 +1613,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-msm8996", .data = &cfg_2_3_2 }, { .compatible = "qcom,pcie-qcs404", .data = &cfg_2_4_0 }, { .compatible = "qcom,pcie-sa8540p", .data = &cfg_1_9_0 }, + { .compatible = "qcom,pcie-sa8775p", .data = &cfg_1_9_0}, { .compatible = "qcom,pcie-sc7280", .data = &cfg_1_9_0 }, { .compatible = "qcom,pcie-sc8180x", .data = &cfg_1_9_0 }, { .compatible = "qcom,pcie-sc8280xp", .data = &cfg_1_9_0 }, -- cgit v1.2.3 From 5694ba13b004eea683c6d4faeb6d6e7a9636bda0 Mon Sep 17 00:00:00 2001 From: Feiyang Chen Date: Thu, 24 Aug 2023 09:37:38 +0800 Subject: PCI/PM: Only read PCI_PM_CTRL register when available For a device with no Power Management Capability, pci_power_up() previously returned 0 (success) if the platform was able to put the device in D0, which led to pci_set_full_power_state() trying to read PCI_PM_CTRL, even though it doesn't exist. Since dev->pm_cap == 0 in this case, pci_set_full_power_state() actually read the wrong register, interpreted it as PCI_PM_CTRL, and corrupted dev->current_state. This led to messages like this in some cases: pci 0000:01:00.0: Refused to change power state from D3hot to D0 To prevent this, make pci_power_up() always return a negative failure code if the device lacks a Power Management Capability, even if non-PCI platform power management has been able to put the device in D0. The failure will prevent pci_set_full_power_state() from trying to access PCI_PM_CTRL. Fixes: e200904b275c ("PCI/PM: Split pci_power_up()") Link: https://lore.kernel.org/r/20230824013738.1894965-1-chenfeiyang@loongson.cn Signed-off-by: Feiyang Chen Signed-off-by: Bjorn Helgaas Reviewed-by: "Rafael J. Wysocki" Cc: stable@vger.kernel.org # v5.19+ --- drivers/pci/pci.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 60230da957e0..39728196e295 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1226,6 +1226,10 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) * * On success, return 0 or 1, depending on whether or not it is necessary to * restore the device's BARs subsequently (1 is returned in that case). + * + * On failure, return a negative error code. Always return failure if @dev + * lacks a Power Management Capability, even if the platform was able to + * put the device in D0 via non-PCI means. */ int pci_power_up(struct pci_dev *dev) { @@ -1242,9 +1246,6 @@ int pci_power_up(struct pci_dev *dev) else dev->current_state = state; - if (state == PCI_D0) - return 0; - return -EIO; } @@ -1302,8 +1303,12 @@ static int pci_set_full_power_state(struct pci_dev *dev) int ret; ret = pci_power_up(dev); - if (ret < 0) + if (ret < 0) { + if (dev->current_state == PCI_D0) + return 0; + return ret; + } pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); dev->current_state = pmcsr & PCI_PM_CTRL_STATE_MASK; -- cgit v1.2.3 From d9d9f26f1666b8e4052b7b40b2f17c456da0fba3 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 17 Jul 2023 12:24:54 +0530 Subject: PCI: epf-mhi: Make use of the alignment restriction from EPF core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of hardcoding the alignment restriction in the EPF_MHI driver, make use of the info available from the EPF core that reflects the alignment restriction of the endpoint controller. For this purpose, let's introduce the get_align_offset() static function. [kwilczynski: update get_align_offset() to avoid issues on 32-bit architectures] Link: https://lore.kernel.org/linux-pci/20230717065459.14138-3-manivannan.sadhasivam@linaro.org Link: https://lore.kernel.org/linux-pci/20230826150626.23309-1-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński --- drivers/pci/endpoint/functions/pci-epf-mhi.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c index 9c1f5a154fbd..ffab56afa2f6 100644 --- a/drivers/pci/endpoint/functions/pci-epf-mhi.c +++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c @@ -92,6 +92,7 @@ static const struct pci_epf_mhi_ep_info sdx55_info = { }; struct pci_epf_mhi { + const struct pci_epc_features *epc_features; const struct pci_epf_mhi_ep_info *info; struct mhi_ep_cntrl mhi_cntrl; struct pci_epf *epf; @@ -102,6 +103,11 @@ struct pci_epf_mhi { int irq; }; +static size_t get_align_offset(struct pci_epf_mhi *epf_mhi, u64 addr) +{ + return addr & (epf_mhi->epc_features->align -1); +} + static int __pci_epf_mhi_alloc_map(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, phys_addr_t *paddr, void __iomem **vaddr, size_t offset, size_t size) @@ -133,8 +139,7 @@ static int pci_epf_mhi_alloc_map(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, size_t size) { struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); - struct pci_epc *epc = epf_mhi->epf->epc; - size_t offset = pci_addr & (epc->mem->window.page_size - 1); + size_t offset = get_align_offset(epf_mhi, pci_addr); return __pci_epf_mhi_alloc_map(mhi_cntrl, pci_addr, paddr, vaddr, offset, size); @@ -159,9 +164,7 @@ static void pci_epf_mhi_unmap_free(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, size_t size) { struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); - struct pci_epf *epf = epf_mhi->epf; - struct pci_epc *epc = epf->epc; - size_t offset = pci_addr & (epc->mem->window.page_size - 1); + size_t offset = get_align_offset(epf_mhi, pci_addr); __pci_epf_mhi_unmap_free(mhi_cntrl, pci_addr, paddr, vaddr, offset, size); @@ -185,7 +188,7 @@ static int pci_epf_mhi_read_from_host(struct mhi_ep_cntrl *mhi_cntrl, u64 from, void *to, size_t size) { struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); - size_t offset = from % SZ_4K; + size_t offset = get_align_offset(epf_mhi, from); void __iomem *tre_buf; phys_addr_t tre_phys; int ret; @@ -213,7 +216,7 @@ static int pci_epf_mhi_write_to_host(struct mhi_ep_cntrl *mhi_cntrl, void *from, u64 to, size_t size) { struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); - size_t offset = to % SZ_4K; + size_t offset = get_align_offset(epf_mhi, to); void __iomem *tre_buf; phys_addr_t tre_phys; int ret; @@ -270,6 +273,10 @@ static int pci_epf_mhi_core_init(struct pci_epf *epf) return ret; } + epf_mhi->epc_features = pci_epc_get_features(epc, epf->func_no, epf->vfunc_no); + if (!epf_mhi->epc_features) + return -ENODATA; + return 0; } -- cgit v1.2.3 From ff8d92038cf92c886873c0e0628ba1272e6a087c Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 17 Jul 2023 12:24:55 +0530 Subject: PCI: qcom-ep: Add eDMA support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Qualcomm PCIe Endpoint controllers have the in-built Embedded DMA (eDMA) peripheral for offloading the data transfer between the PCIe bus and memory. Let's add support for it by enabling the eDMA IRQ in the driver. The eDMA DMA Engine driver will handle the rest of the functionality. Since the eDMA on Qualcomm platforms only uses a single IRQ for all channels, use 1 for edma.nr_irqs. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230717065459.14138-4-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 736be5bee458..1baec81183b6 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -74,6 +74,7 @@ #define PARF_INT_ALL_PLS_ERR BIT(15) #define PARF_INT_ALL_PME_LEGACY BIT(16) #define PARF_INT_ALL_PLS_PME BIT(17) +#define PARF_INT_ALL_EDMA BIT(22) /* PARF_BDF_TO_SID_CFG register fields */ #define PARF_BDF_TO_SID_BYPASS BIT(0) @@ -395,7 +396,7 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) writel_relaxed(0, pcie_ep->parf + PARF_INT_ALL_MASK); val = PARF_INT_ALL_LINK_DOWN | PARF_INT_ALL_BME | PARF_INT_ALL_PM_TURNOFF | PARF_INT_ALL_DSTATE_CHANGE | - PARF_INT_ALL_LINK_UP; + PARF_INT_ALL_LINK_UP | PARF_INT_ALL_EDMA; writel_relaxed(val, pcie_ep->parf + PARF_INT_ALL_MASK); ret = dw_pcie_ep_init_complete(&pcie_ep->pci.ep); @@ -744,6 +745,7 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) pcie_ep->pci.dev = dev; pcie_ep->pci.ops = &pci_ops; pcie_ep->pci.ep.ops = &pci_ep_ops; + pcie_ep->pci.edma.nr_irqs = 1; platform_set_drvdata(pdev, pcie_ep); ret = qcom_pcie_ep_get_resources(pdev, pcie_ep); -- cgit v1.2.3 From 7b99aaaddabba18ba13d74e3c17a8cc094cf6707 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 17 Jul 2023 12:24:56 +0530 Subject: PCI: epf-mhi: Add eDMA support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Embedded DMA (eDMA) available in the DesignWare PCIe IP to transfer the MHI buffers between the host and the endpoint. The eDMA use helps achieve greater throughput as the transfers are offloaded from CPUs. For differentiating the iATU and eDMA APIs, the pci_epf_mhi_{read/write} APIs are renamed to pci_epf_mhi_iatu_{read/write} and separate eDMA specific APIs pci_epf_mhi_edma_{read/write} are introduced. Platforms that require eDMA support can pass the MHI_EPF_USE_DMA flag through pci_epf_mhi_ep_info. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230717065459.14138-5-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński --- drivers/pci/endpoint/functions/pci-epf-mhi.c | 237 ++++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c index ffab56afa2f6..272eabc255fc 100644 --- a/drivers/pci/endpoint/functions/pci-epf-mhi.c +++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c @@ -6,8 +6,10 @@ * Author: Manivannan Sadhasivam */ +#include #include #include +#include #include #include #include @@ -16,6 +18,9 @@ #define to_epf_mhi(cntrl) container_of(cntrl, struct pci_epf_mhi, cntrl) +/* Platform specific flags */ +#define MHI_EPF_USE_DMA BIT(0) + struct pci_epf_mhi_ep_info { const struct mhi_ep_cntrl_config *config; struct pci_epf_header *epf_header; @@ -23,6 +28,7 @@ struct pci_epf_mhi_ep_info { u32 epf_flags; u32 msi_count; u32 mru; + u32 flags; }; #define MHI_EP_CHANNEL_CONFIG(ch_num, ch_name, direction) \ @@ -99,6 +105,8 @@ struct pci_epf_mhi { struct mutex lock; void __iomem *mmio; resource_size_t mmio_phys; + struct dma_chan *dma_chan_tx; + struct dma_chan *dma_chan_rx; u32 mmio_size; int irq; }; @@ -184,8 +192,8 @@ static void pci_epf_mhi_raise_irq(struct mhi_ep_cntrl *mhi_cntrl, u32 vector) vector + 1); } -static int pci_epf_mhi_read_from_host(struct mhi_ep_cntrl *mhi_cntrl, u64 from, - void *to, size_t size) +static int pci_epf_mhi_iatu_read(struct mhi_ep_cntrl *mhi_cntrl, u64 from, + void *to, size_t size) { struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); size_t offset = get_align_offset(epf_mhi, from); @@ -212,8 +220,8 @@ static int pci_epf_mhi_read_from_host(struct mhi_ep_cntrl *mhi_cntrl, u64 from, return 0; } -static int pci_epf_mhi_write_to_host(struct mhi_ep_cntrl *mhi_cntrl, - void *from, u64 to, size_t size) +static int pci_epf_mhi_iatu_write(struct mhi_ep_cntrl *mhi_cntrl, + void *from, u64 to, size_t size) { struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); size_t offset = get_align_offset(epf_mhi, to); @@ -240,6 +248,200 @@ static int pci_epf_mhi_write_to_host(struct mhi_ep_cntrl *mhi_cntrl, return 0; } +static void pci_epf_mhi_dma_callback(void *param) +{ + complete(param); +} + +static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl, u64 from, + void *to, size_t size) +{ + struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); + struct device *dma_dev = epf_mhi->epf->epc->dev.parent; + struct dma_chan *chan = epf_mhi->dma_chan_rx; + struct device *dev = &epf_mhi->epf->dev; + DECLARE_COMPLETION_ONSTACK(complete); + struct dma_async_tx_descriptor *desc; + struct dma_slave_config config = {}; + dma_cookie_t cookie; + dma_addr_t dst_addr; + int ret; + + mutex_lock(&epf_mhi->lock); + + config.direction = DMA_DEV_TO_MEM; + config.src_addr = from; + + ret = dmaengine_slave_config(chan, &config); + if (ret) { + dev_err(dev, "Failed to configure DMA channel\n"); + goto err_unlock; + } + + dst_addr = dma_map_single(dma_dev, to, size, DMA_FROM_DEVICE); + ret = dma_mapping_error(dma_dev, dst_addr); + if (ret) { + dev_err(dev, "Failed to map remote memory\n"); + goto err_unlock; + } + + desc = dmaengine_prep_slave_single(chan, dst_addr, size, DMA_DEV_TO_MEM, + DMA_CTRL_ACK | DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(dev, "Failed to prepare DMA\n"); + ret = -EIO; + goto err_unmap; + } + + desc->callback = pci_epf_mhi_dma_callback; + desc->callback_param = &complete; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) { + dev_err(dev, "Failed to do DMA submit\n"); + goto err_unmap; + } + + dma_async_issue_pending(chan); + ret = wait_for_completion_timeout(&complete, msecs_to_jiffies(1000)); + if (!ret) { + dev_err(dev, "DMA transfer timeout\n"); + dmaengine_terminate_sync(chan); + ret = -ETIMEDOUT; + } + +err_unmap: + dma_unmap_single(dma_dev, dst_addr, size, DMA_FROM_DEVICE); +err_unlock: + mutex_unlock(&epf_mhi->lock); + + return ret; +} + +static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl, void *from, + u64 to, size_t size) +{ + struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); + struct device *dma_dev = epf_mhi->epf->epc->dev.parent; + struct dma_chan *chan = epf_mhi->dma_chan_tx; + struct device *dev = &epf_mhi->epf->dev; + DECLARE_COMPLETION_ONSTACK(complete); + struct dma_async_tx_descriptor *desc; + struct dma_slave_config config = {}; + dma_cookie_t cookie; + dma_addr_t src_addr; + int ret; + + mutex_lock(&epf_mhi->lock); + + config.direction = DMA_MEM_TO_DEV; + config.dst_addr = to; + + ret = dmaengine_slave_config(chan, &config); + if (ret) { + dev_err(dev, "Failed to configure DMA channel\n"); + goto err_unlock; + } + + src_addr = dma_map_single(dma_dev, from, size, DMA_TO_DEVICE); + ret = dma_mapping_error(dma_dev, src_addr); + if (ret) { + dev_err(dev, "Failed to map remote memory\n"); + goto err_unlock; + } + + desc = dmaengine_prep_slave_single(chan, src_addr, size, DMA_MEM_TO_DEV, + DMA_CTRL_ACK | DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(dev, "Failed to prepare DMA\n"); + ret = -EIO; + goto err_unmap; + } + + desc->callback = pci_epf_mhi_dma_callback; + desc->callback_param = &complete; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) { + dev_err(dev, "Failed to do DMA submit\n"); + goto err_unmap; + } + + dma_async_issue_pending(chan); + ret = wait_for_completion_timeout(&complete, msecs_to_jiffies(1000)); + if (!ret) { + dev_err(dev, "DMA transfer timeout\n"); + dmaengine_terminate_sync(chan); + ret = -ETIMEDOUT; + } + +err_unmap: + dma_unmap_single(dma_dev, src_addr, size, DMA_FROM_DEVICE); +err_unlock: + mutex_unlock(&epf_mhi->lock); + + return ret; +} + +struct epf_dma_filter { + struct device *dev; + u32 dma_mask; +}; + +static bool pci_epf_mhi_filter(struct dma_chan *chan, void *node) +{ + struct epf_dma_filter *filter = node; + struct dma_slave_caps caps; + + memset(&caps, 0, sizeof(caps)); + dma_get_slave_caps(chan, &caps); + + return chan->device->dev == filter->dev && filter->dma_mask & + caps.directions; +} + +static int pci_epf_mhi_dma_init(struct pci_epf_mhi *epf_mhi) +{ + struct device *dma_dev = epf_mhi->epf->epc->dev.parent; + struct device *dev = &epf_mhi->epf->dev; + struct epf_dma_filter filter; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + filter.dev = dma_dev; + filter.dma_mask = BIT(DMA_MEM_TO_DEV); + epf_mhi->dma_chan_tx = dma_request_channel(mask, pci_epf_mhi_filter, + &filter); + if (IS_ERR_OR_NULL(epf_mhi->dma_chan_tx)) { + dev_err(dev, "Failed to request tx channel\n"); + return -ENODEV; + } + + filter.dma_mask = BIT(DMA_DEV_TO_MEM); + epf_mhi->dma_chan_rx = dma_request_channel(mask, pci_epf_mhi_filter, + &filter); + if (IS_ERR_OR_NULL(epf_mhi->dma_chan_rx)) { + dev_err(dev, "Failed to request rx channel\n"); + dma_release_channel(epf_mhi->dma_chan_tx); + epf_mhi->dma_chan_tx = NULL; + return -ENODEV; + } + + return 0; +} + +static void pci_epf_mhi_dma_deinit(struct pci_epf_mhi *epf_mhi) +{ + dma_release_channel(epf_mhi->dma_chan_tx); + dma_release_channel(epf_mhi->dma_chan_rx); + epf_mhi->dma_chan_tx = NULL; + epf_mhi->dma_chan_rx = NULL; +} + static int pci_epf_mhi_core_init(struct pci_epf *epf) { struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); @@ -289,6 +491,14 @@ static int pci_epf_mhi_link_up(struct pci_epf *epf) struct device *dev = &epf->dev; int ret; + if (info->flags & MHI_EPF_USE_DMA) { + ret = pci_epf_mhi_dma_init(epf_mhi); + if (ret) { + dev_err(dev, "Failed to initialize DMA: %d\n", ret); + return ret; + } + } + mhi_cntrl->mmio = epf_mhi->mmio; mhi_cntrl->irq = epf_mhi->irq; mhi_cntrl->mru = info->mru; @@ -298,13 +508,20 @@ static int pci_epf_mhi_link_up(struct pci_epf *epf) mhi_cntrl->raise_irq = pci_epf_mhi_raise_irq; mhi_cntrl->alloc_map = pci_epf_mhi_alloc_map; mhi_cntrl->unmap_free = pci_epf_mhi_unmap_free; - mhi_cntrl->read_from_host = pci_epf_mhi_read_from_host; - mhi_cntrl->write_to_host = pci_epf_mhi_write_to_host; + if (info->flags & MHI_EPF_USE_DMA) { + mhi_cntrl->read_from_host = pci_epf_mhi_edma_read; + mhi_cntrl->write_to_host = pci_epf_mhi_edma_write; + } else { + mhi_cntrl->read_from_host = pci_epf_mhi_iatu_read; + mhi_cntrl->write_to_host = pci_epf_mhi_iatu_write; + } /* Register the MHI EP controller */ ret = mhi_ep_register_controller(mhi_cntrl, info->config); if (ret) { dev_err(dev, "Failed to register MHI EP controller: %d\n", ret); + if (info->flags & MHI_EPF_USE_DMA) + pci_epf_mhi_dma_deinit(epf_mhi); return ret; } @@ -314,10 +531,13 @@ static int pci_epf_mhi_link_up(struct pci_epf *epf) static int pci_epf_mhi_link_down(struct pci_epf *epf) { struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); + const struct pci_epf_mhi_ep_info *info = epf_mhi->info; struct mhi_ep_cntrl *mhi_cntrl = &epf_mhi->mhi_cntrl; if (mhi_cntrl->mhi_dev) { mhi_ep_power_down(mhi_cntrl); + if (info->flags & MHI_EPF_USE_DMA) + pci_epf_mhi_dma_deinit(epf_mhi); mhi_ep_unregister_controller(mhi_cntrl); } @@ -327,6 +547,7 @@ static int pci_epf_mhi_link_down(struct pci_epf *epf) static int pci_epf_mhi_bme(struct pci_epf *epf) { struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); + const struct pci_epf_mhi_ep_info *info = epf_mhi->info; struct mhi_ep_cntrl *mhi_cntrl = &epf_mhi->mhi_cntrl; struct device *dev = &epf->dev; int ret; @@ -339,6 +560,8 @@ static int pci_epf_mhi_bme(struct pci_epf *epf) ret = mhi_ep_power_up(mhi_cntrl); if (ret) { dev_err(dev, "Failed to power up MHI EP: %d\n", ret); + if (info->flags & MHI_EPF_USE_DMA) + pci_epf_mhi_dma_deinit(epf_mhi); mhi_ep_unregister_controller(mhi_cntrl); } } @@ -389,6 +612,8 @@ static void pci_epf_mhi_unbind(struct pci_epf *epf) */ if (mhi_cntrl->mhi_dev) { mhi_ep_power_down(mhi_cntrl); + if (info->flags & MHI_EPF_USE_DMA) + pci_epf_mhi_dma_deinit(epf_mhi); mhi_ep_unregister_controller(mhi_cntrl); } -- cgit v1.2.3 From 8ab8a31645b83c6446da6254c099032bab871b23 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 17 Jul 2023 12:24:57 +0530 Subject: PCI: epf-mhi: Add support for SM8450 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Qualcomm Snapdragon SM8450 SoC to the EPF driver. SM8450 has the dedicated PID (0x0306) and supports eDMA. Currently, it has no fixed PCI class, so it is being advertised as "PCI_CLASS_OTHERS". Link: https://lore.kernel.org/linux-pci/20230717065459.14138-6-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński --- drivers/pci/endpoint/functions/pci-epf-mhi.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c index 272eabc255fc..fec9743a63f0 100644 --- a/drivers/pci/endpoint/functions/pci-epf-mhi.c +++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c @@ -97,6 +97,23 @@ static const struct pci_epf_mhi_ep_info sdx55_info = { .mru = 0x8000, }; +static struct pci_epf_header sm8450_header = { + .vendorid = PCI_VENDOR_ID_QCOM, + .deviceid = 0x0306, + .baseclass_code = PCI_CLASS_OTHERS, + .interrupt_pin = PCI_INTERRUPT_INTA, +}; + +static const struct pci_epf_mhi_ep_info sm8450_info = { + .config = &mhi_v1_config, + .epf_header = &sm8450_header, + .bar_num = BAR_0, + .epf_flags = PCI_BASE_ADDRESS_MEM_TYPE_32, + .msi_count = 32, + .mru = 0x8000, + .flags = MHI_EPF_USE_DMA, +}; + struct pci_epf_mhi { const struct pci_epc_features *epc_features; const struct pci_epf_mhi_ep_info *info; @@ -654,9 +671,8 @@ static int pci_epf_mhi_probe(struct pci_epf *epf, } static const struct pci_epf_device_id pci_epf_mhi_ids[] = { - { - .name = "sdx55", .driver_data = (kernel_ulong_t)&sdx55_info, - }, + { .name = "sdx55", .driver_data = (kernel_ulong_t)&sdx55_info }, + { .name = "sm8450", .driver_data = (kernel_ulong_t)&sm8450_info }, {}, }; -- cgit v1.2.3 From 127c66c3b95feddda664d1d76cae424a592ceac5 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 17 Jul 2023 12:24:58 +0530 Subject: PCI: epf-mhi: Use iATU for small transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For transfers below 4K, let's use iATU since using eDMA for such small transfers is inefficient. This is mainly because setting up an eDMA transfer and waiting for completion adds some latency. This latency is negligible for large transfers but not for the smaller ones. With using iATU, there is an increase in ~50Mbps throughput on both MHI UL (Uplink) and DL (Downlink) channels. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230717065459.14138-7-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński --- drivers/pci/endpoint/functions/pci-epf-mhi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c index fec9743a63f0..b7b9d3e21f97 100644 --- a/drivers/pci/endpoint/functions/pci-epf-mhi.c +++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c @@ -284,6 +284,9 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl, u64 from, dma_addr_t dst_addr; int ret; + if (size < SZ_4K) + return pci_epf_mhi_iatu_read(mhi_cntrl, from, to, size); + mutex_lock(&epf_mhi->lock); config.direction = DMA_DEV_TO_MEM; @@ -350,6 +353,9 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl, void *from, dma_addr_t src_addr; int ret; + if (size < SZ_4K) + return pci_epf_mhi_iatu_write(mhi_cntrl, from, to, size); + mutex_lock(&epf_mhi->lock); config.direction = DMA_MEM_TO_DEV; -- cgit v1.2.3 From 06eea7d18fe86fdf09771f5a9d1ac74134725df1 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 17 Jul 2023 12:24:59 +0530 Subject: PCI: endpoint: Add kernel-doc for pci_epc_mem_init() API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing kernel-doc for pci_epc_mem_init() API. Link: https://lore.kernel.org/linux-pci/20230717065459.14138-8-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Reviewed-by: Randy Dunlap --- drivers/pci/endpoint/pci-epc-mem.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c index 7dcf6f480b82..a9c028f58da1 100644 --- a/drivers/pci/endpoint/pci-epc-mem.c +++ b/drivers/pci/endpoint/pci-epc-mem.c @@ -115,6 +115,16 @@ err_mem: } EXPORT_SYMBOL_GPL(pci_epc_multi_mem_init); +/** + * pci_epc_mem_init() - Initialize the pci_epc_mem structure + * @epc: the EPC device that invoked pci_epc_mem_init + * @base: Physical address of the window region + * @size: Total Size of the window region + * @page_size: Page size of the window region + * + * Invoke to initialize a single pci_epc_mem structure used by the + * endpoint functions to allocate memory for mapping the PCI host memory + */ int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base, size_t size, size_t page_size) { -- cgit v1.2.3 From 823de40c94d680ec8d57a660ac96a653acadb0a5 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 26 Jul 2023 20:59:31 +0530 Subject: PCI: qcom-ep: Treat unknown IRQ events as an error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes, the Qcom PCIe EP controller can receive some interrupts unknown to the driver, like safety interrupts in newer SoCs. In those cases, if the driver doesn't clear the interrupts, it will end up in an interrupt storm. However, the users will not know about it because the log is treated as a debug message. So let's treat the unknown event log as an error so that it at least makes the user aware, thereby getting fixed eventually. [kwilczynski: commit log] Link: https://lore.kernel.org/linux-pci/20230726152931.18134-1-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 0fe7f06f2102..86929a7a104e 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -593,7 +593,7 @@ static irqreturn_t qcom_pcie_ep_global_irq_thread(int irq, void *data) dw_pcie_ep_linkup(&pci->ep); pcie_ep->link_status = QCOM_PCIE_EP_LINK_UP; } else { - dev_dbg(dev, "Received unknown event: %d\n", status); + dev_err(dev, "Received unknown event: %d\n", status); } return IRQ_HANDLED; -- cgit v1.2.3 From 01794236666abef69a07b48fa0948c4157d7ca70 Mon Sep 17 00:00:00 2001 From: Krishna chaitanya chundru Date: Wed, 19 Jul 2023 12:50:18 +0530 Subject: PCI: qcom-ep: Add ICC bandwidth voting support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for voting interconnect (ICC) bandwidth based on the link speed and width. This commit is inspired from the basic interconnect support added to pcie-qcom driver in commit c4860af88d0c ("PCI: qcom: Add basic interconnect support"). The interconnect support is kept optional to be backward compatible with legacy device trees. [kwilczynski: add missing kernel-doc for the icc_mem variable] Link: https://lore.kernel.org/linux-pci/1689751218-24492-5-git-send-email-quic_krichai@quicinc.com Signed-off-by: Krishna chaitanya chundru Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 72 +++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 86929a7a104e..38f1a1b75039 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,11 @@ #define CORE_RESET_TIME_US_MAX 1005 #define WAKE_DELAY_US 2000 /* 2 ms */ +#define PCIE_GEN1_BW_MBPS 250 +#define PCIE_GEN2_BW_MBPS 500 +#define PCIE_GEN3_BW_MBPS 985 +#define PCIE_GEN4_BW_MBPS 1969 + #define to_pcie_ep(x) dev_get_drvdata((x)->dev) enum qcom_pcie_ep_link_status { @@ -155,6 +161,7 @@ enum qcom_pcie_ep_link_status { * @wake: WAKE# GPIO * @phy: PHY controller block * @debugfs: PCIe Endpoint Debugfs directory + * @icc_mem: Handle to an interconnect path between PCIe and MEM * @clks: PCIe clocks * @num_clks: PCIe clocks count * @perst_en: Flag for PERST enable @@ -178,6 +185,8 @@ struct qcom_pcie_ep { struct phy *phy; struct dentry *debugfs; + struct icc_path *icc_mem; + struct clk_bulk_data *clks; int num_clks; @@ -253,8 +262,49 @@ static void qcom_pcie_dw_stop_link(struct dw_pcie *pci) disable_irq(pcie_ep->perst_irq); } +static void qcom_pcie_ep_icc_update(struct qcom_pcie_ep *pcie_ep) +{ + struct dw_pcie *pci = &pcie_ep->pci; + u32 offset, status, bw; + int speed, width; + int ret; + + if (!pcie_ep->icc_mem) + return; + + offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA); + + speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status); + width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status); + + switch (speed) { + case 1: + bw = MBps_to_icc(PCIE_GEN1_BW_MBPS); + break; + case 2: + bw = MBps_to_icc(PCIE_GEN2_BW_MBPS); + break; + case 3: + bw = MBps_to_icc(PCIE_GEN3_BW_MBPS); + break; + default: + dev_warn(pci->dev, "using default GEN4 bandwidth\n"); + fallthrough; + case 4: + bw = MBps_to_icc(PCIE_GEN4_BW_MBPS); + break; + } + + ret = icc_set_bw(pcie_ep->icc_mem, 0, width * bw); + if (ret) + dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n", + ret); +} + static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep) { + struct dw_pcie *pci = &pcie_ep->pci; int ret; ret = clk_bulk_prepare_enable(pcie_ep->num_clks, pcie_ep->clks); @@ -277,8 +327,24 @@ static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep) if (ret) goto err_phy_exit; + /* + * Some Qualcomm platforms require interconnect bandwidth constraints + * to be set before enabling interconnect clocks. + * + * Set an initial peak bandwidth corresponding to single-lane Gen 1 + * for the pcie-mem path. + */ + ret = icc_set_bw(pcie_ep->icc_mem, 0, MBps_to_icc(PCIE_GEN1_BW_MBPS)); + if (ret) { + dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n", + ret); + goto err_phy_off; + } + return 0; +err_phy_off: + phy_power_off(pcie_ep->phy); err_phy_exit: phy_exit(pcie_ep->phy); err_disable_clk: @@ -289,6 +355,7 @@ err_disable_clk: static void qcom_pcie_disable_resources(struct qcom_pcie_ep *pcie_ep) { + icc_set_bw(pcie_ep->icc_mem, 0, 0); phy_power_off(pcie_ep->phy); phy_exit(pcie_ep->phy); clk_bulk_disable_unprepare(pcie_ep->num_clks, pcie_ep->clks); @@ -550,6 +617,10 @@ static int qcom_pcie_ep_get_resources(struct platform_device *pdev, if (IS_ERR(pcie_ep->phy)) ret = PTR_ERR(pcie_ep->phy); + pcie_ep->icc_mem = devm_of_icc_get(dev, "pcie-mem"); + if (IS_ERR(pcie_ep->icc_mem)) + ret = PTR_ERR(pcie_ep->icc_mem); + return ret; } @@ -573,6 +644,7 @@ static irqreturn_t qcom_pcie_ep_global_irq_thread(int irq, void *data) } else if (FIELD_GET(PARF_INT_ALL_BME, status)) { dev_dbg(dev, "Received BME event. Link is enabled!\n"); pcie_ep->link_status = QCOM_PCIE_EP_LINK_ENABLED; + qcom_pcie_ep_icc_update(pcie_ep); pci_epc_bme_notify(pci->ep.epc); } else if (FIELD_GET(PARF_INT_ALL_PM_TURNOFF, status)) { dev_dbg(dev, "Received PM Turn-off event! Entering L23\n"); -- cgit v1.2.3