From 652935ba05860eadaa19ac9efe7aea61fb7a3aef Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 17 Apr 2024 12:32:53 +0530 Subject: PCI: qcom: Use devm_clk_bulk_get_all() API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for the device drivers to validate the clocks defined in Devicetree. The validation should be performed by the DT schema and the drivers should just get all the clocks from DT. Right now the driver hardcodes the clock info and validates them against DT which is redundant. So use devm_clk_bulk_get_all() that just gets all the clocks defined in DT and get rid of all static clocks info from the driver. This simplifies the driver. Link: https://lore.kernel.org/linux-pci/20240417-pci-qcom-clk-bulk-v1-1-52ca19b3d6b2@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-qcom.c | 177 +++++++++++---------------------- 1 file changed, 58 insertions(+), 119 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 14772edcf0d3..3d2eeff9a876 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -154,58 +154,56 @@ #define QCOM_PCIE_LINK_SPEED_TO_BW(speed) \ Mbps_to_icc(PCIE_SPEED2MBS_ENC(pcie_link_speed[speed])) -#define QCOM_PCIE_1_0_0_MAX_CLOCKS 4 struct qcom_pcie_resources_1_0_0 { - struct clk_bulk_data clks[QCOM_PCIE_1_0_0_MAX_CLOCKS]; + struct clk_bulk_data *clks; + int num_clks; struct reset_control *core; struct regulator *vdda; }; -#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 #define QCOM_PCIE_2_1_0_MAX_RESETS 6 #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 struct qcom_pcie_resources_2_1_0 { - struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS]; + struct clk_bulk_data *clks; + int num_clks; struct reset_control_bulk_data resets[QCOM_PCIE_2_1_0_MAX_RESETS]; int num_resets; struct regulator_bulk_data supplies[QCOM_PCIE_2_1_0_MAX_SUPPLY]; }; -#define QCOM_PCIE_2_3_2_MAX_CLOCKS 4 #define QCOM_PCIE_2_3_2_MAX_SUPPLY 2 struct qcom_pcie_resources_2_3_2 { - struct clk_bulk_data clks[QCOM_PCIE_2_3_2_MAX_CLOCKS]; + struct clk_bulk_data *clks; + int num_clks; struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY]; }; -#define QCOM_PCIE_2_3_3_MAX_CLOCKS 5 #define QCOM_PCIE_2_3_3_MAX_RESETS 7 struct qcom_pcie_resources_2_3_3 { - struct clk_bulk_data clks[QCOM_PCIE_2_3_3_MAX_CLOCKS]; + struct clk_bulk_data *clks; + int num_clks; struct reset_control_bulk_data rst[QCOM_PCIE_2_3_3_MAX_RESETS]; }; -#define QCOM_PCIE_2_4_0_MAX_CLOCKS 4 #define QCOM_PCIE_2_4_0_MAX_RESETS 12 struct qcom_pcie_resources_2_4_0 { - struct clk_bulk_data clks[QCOM_PCIE_2_4_0_MAX_CLOCKS]; + struct clk_bulk_data *clks; int num_clks; struct reset_control_bulk_data resets[QCOM_PCIE_2_4_0_MAX_RESETS]; int num_resets; }; -#define QCOM_PCIE_2_7_0_MAX_CLOCKS 15 #define QCOM_PCIE_2_7_0_MAX_SUPPLIES 2 struct qcom_pcie_resources_2_7_0 { - struct clk_bulk_data clks[QCOM_PCIE_2_7_0_MAX_CLOCKS]; + struct clk_bulk_data *clks; int num_clks; struct regulator_bulk_data supplies[QCOM_PCIE_2_7_0_MAX_SUPPLIES]; struct reset_control *rst; }; -#define QCOM_PCIE_2_9_0_MAX_CLOCKS 5 struct qcom_pcie_resources_2_9_0 { - struct clk_bulk_data clks[QCOM_PCIE_2_9_0_MAX_CLOCKS]; + struct clk_bulk_data *clks; + int num_clks; struct reset_control *rst; }; @@ -337,21 +335,11 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie) if (ret) return ret; - res->clks[0].id = "iface"; - res->clks[1].id = "core"; - res->clks[2].id = "phy"; - res->clks[3].id = "aux"; - res->clks[4].id = "ref"; - - /* iface, core, phy are required */ - ret = devm_clk_bulk_get(dev, 3, res->clks); - if (ret < 0) - return ret; - - /* aux, ref are optional */ - ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3); - if (ret < 0) - return ret; + res->num_clks = devm_clk_bulk_get_all(dev, &res->clks); + if (res->num_clks < 0) { + dev_err(dev, "Failed to get clocks\n"); + return res->num_clks; + } res->resets[0].id = "pci"; res->resets[1].id = "axi"; @@ -373,7 +361,7 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0; - clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); + clk_bulk_disable_unprepare(res->num_clks, res->clks); reset_control_bulk_assert(res->num_resets, res->resets); writel(1, pcie->parf + PARF_PHY_CTRL); @@ -425,7 +413,7 @@ static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie) val &= ~PHY_TEST_PWR_DOWN; writel(val, pcie->parf + PARF_PHY_CTRL); - ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); + ret = clk_bulk_prepare_enable(res->num_clks, res->clks); if (ret) return ret; @@ -476,20 +464,16 @@ static int qcom_pcie_get_resources_1_0_0(struct qcom_pcie *pcie) struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0; struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; - int ret; res->vdda = devm_regulator_get(dev, "vdda"); if (IS_ERR(res->vdda)) return PTR_ERR(res->vdda); - res->clks[0].id = "iface"; - res->clks[1].id = "aux"; - res->clks[2].id = "master_bus"; - res->clks[3].id = "slave_bus"; - - ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks); - if (ret < 0) - return ret; + res->num_clks = devm_clk_bulk_get_all(dev, &res->clks); + if (res->num_clks < 0) { + dev_err(dev, "Failed to get clocks\n"); + return res->num_clks; + } res->core = devm_reset_control_get_exclusive(dev, "core"); return PTR_ERR_OR_ZERO(res->core); @@ -500,7 +484,7 @@ static void qcom_pcie_deinit_1_0_0(struct qcom_pcie *pcie) struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0; reset_control_assert(res->core); - clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); + clk_bulk_disable_unprepare(res->num_clks, res->clks); regulator_disable(res->vdda); } @@ -517,7 +501,7 @@ static int qcom_pcie_init_1_0_0(struct qcom_pcie *pcie) return ret; } - ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); + ret = clk_bulk_prepare_enable(res->num_clks, res->clks); if (ret) { dev_err(dev, "cannot prepare/enable clocks\n"); goto err_assert_reset; @@ -532,7 +516,7 @@ static int qcom_pcie_init_1_0_0(struct qcom_pcie *pcie) return 0; err_disable_clks: - clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); + clk_bulk_disable_unprepare(res->num_clks, res->clks); err_assert_reset: reset_control_assert(res->core); @@ -580,14 +564,11 @@ static int qcom_pcie_get_resources_2_3_2(struct qcom_pcie *pcie) if (ret) return ret; - res->clks[0].id = "aux"; - res->clks[1].id = "cfg"; - res->clks[2].id = "bus_master"; - res->clks[3].id = "bus_slave"; - - ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks); - if (ret < 0) - return ret; + res->num_clks = devm_clk_bulk_get_all(dev, &res->clks); + if (res->num_clks < 0) { + dev_err(dev, "Failed to get clocks\n"); + return res->num_clks; + } return 0; } @@ -596,7 +577,7 @@ static void qcom_pcie_deinit_2_3_2(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2; - clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); + clk_bulk_disable_unprepare(res->num_clks, res->clks); regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies); } @@ -613,7 +594,7 @@ static int qcom_pcie_init_2_3_2(struct qcom_pcie *pcie) return ret; } - ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); + ret = clk_bulk_prepare_enable(res->num_clks, res->clks); if (ret) { dev_err(dev, "cannot prepare/enable clocks\n"); regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies); @@ -661,17 +642,11 @@ static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie) bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019"); int ret; - res->clks[0].id = "aux"; - res->clks[1].id = "master_bus"; - res->clks[2].id = "slave_bus"; - res->clks[3].id = "iface"; - - /* qcom,pcie-ipq4019 is defined without "iface" */ - res->num_clks = is_ipq ? 3 : 4; - - ret = devm_clk_bulk_get(dev, res->num_clks, res->clks); - if (ret < 0) - return ret; + res->num_clks = devm_clk_bulk_get_all(dev, &res->clks); + if (res->num_clks < 0) { + dev_err(dev, "Failed to get clocks\n"); + return res->num_clks; + } res->resets[0].id = "axi_m"; res->resets[1].id = "axi_s"; @@ -742,15 +717,11 @@ static int qcom_pcie_get_resources_2_3_3(struct qcom_pcie *pcie) struct device *dev = pci->dev; int ret; - res->clks[0].id = "iface"; - res->clks[1].id = "axi_m"; - res->clks[2].id = "axi_s"; - res->clks[3].id = "ahb"; - res->clks[4].id = "aux"; - - ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks); - if (ret < 0) - return ret; + res->num_clks = devm_clk_bulk_get_all(dev, &res->clks); + if (res->num_clks < 0) { + dev_err(dev, "Failed to get clocks\n"); + return res->num_clks; + } res->rst[0].id = "axi_m"; res->rst[1].id = "axi_s"; @@ -771,7 +742,7 @@ static void qcom_pcie_deinit_2_3_3(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3; - clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); + clk_bulk_disable_unprepare(res->num_clks, res->clks); } static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie) @@ -801,7 +772,7 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie) */ usleep_range(2000, 2500); - ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); + ret = clk_bulk_prepare_enable(res->num_clks, res->clks); if (ret) { dev_err(dev, "cannot prepare/enable clocks\n"); goto err_assert_resets; @@ -862,8 +833,6 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie) struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0; struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; - unsigned int num_clks, num_opt_clks; - unsigned int idx; int ret; res->rst = devm_reset_control_array_get_exclusive(dev); @@ -877,36 +846,11 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie) if (ret) return ret; - idx = 0; - res->clks[idx++].id = "aux"; - res->clks[idx++].id = "cfg"; - res->clks[idx++].id = "bus_master"; - res->clks[idx++].id = "bus_slave"; - res->clks[idx++].id = "slave_q2a"; - - num_clks = idx; - - ret = devm_clk_bulk_get(dev, num_clks, res->clks); - if (ret < 0) - return ret; - - res->clks[idx++].id = "tbu"; - res->clks[idx++].id = "ddrss_sf_tbu"; - res->clks[idx++].id = "aggre0"; - res->clks[idx++].id = "aggre1"; - res->clks[idx++].id = "noc_aggr"; - res->clks[idx++].id = "noc_aggr_4"; - res->clks[idx++].id = "noc_aggr_south_sf"; - res->clks[idx++].id = "cnoc_qx"; - res->clks[idx++].id = "sleep"; - res->clks[idx++].id = "cnoc_sf_axi"; - - num_opt_clks = idx - num_clks; - res->num_clks = idx; - - ret = devm_clk_bulk_get_optional(dev, num_opt_clks, res->clks + num_clks); - if (ret < 0) - return ret; + res->num_clks = devm_clk_bulk_get_all(dev, &res->clks); + if (res->num_clks < 0) { + dev_err(dev, "Failed to get clocks\n"); + return res->num_clks; + } return 0; } @@ -1101,17 +1045,12 @@ static int qcom_pcie_get_resources_2_9_0(struct qcom_pcie *pcie) struct qcom_pcie_resources_2_9_0 *res = &pcie->res.v2_9_0; struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; - int ret; - - res->clks[0].id = "iface"; - res->clks[1].id = "axi_m"; - res->clks[2].id = "axi_s"; - res->clks[3].id = "axi_bridge"; - res->clks[4].id = "rchng"; - ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks); - if (ret < 0) - return ret; + res->num_clks = devm_clk_bulk_get_all(dev, &res->clks); + if (res->num_clks < 0) { + dev_err(dev, "Failed to get clocks\n"); + return res->num_clks; + } res->rst = devm_reset_control_array_get_exclusive(dev); if (IS_ERR(res->rst)) @@ -1124,7 +1063,7 @@ static void qcom_pcie_deinit_2_9_0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_9_0 *res = &pcie->res.v2_9_0; - clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); + clk_bulk_disable_unprepare(res->num_clks, res->clks); } static int qcom_pcie_init_2_9_0(struct qcom_pcie *pcie) @@ -1153,7 +1092,7 @@ static int qcom_pcie_init_2_9_0(struct qcom_pcie *pcie) usleep_range(2000, 2500); - return clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); + return clk_bulk_prepare_enable(res->num_clks, res->clks); } static int qcom_pcie_post_init_2_9_0(struct qcom_pcie *pcie) -- cgit v1.2.3 From 9d3d5e75f31ca43d038a63cf701b5af4eae4623b Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Tue, 30 Apr 2024 21:25:37 +0530 Subject: dt-bindings: PCI: qcom-ep: Add support for SA8775P SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add devicetree bindings support for SA8775P SoC. It has DMA register space and dma interrupt to support HDMA. Link: https://lore.kernel.org/linux-pci/1714492540-15419-2-git-send-email-quic_msarkar@quicinc.com Signed-off-by: Mrinmay Sarkar Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Krzysztof Kozlowski Acked-by: Manivannan Sadhasivam --- .../devicetree/bindings/pci/qcom,pcie-ep.yaml | 64 +++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml index a223ce029cab..46802f7d9482 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml @@ -13,6 +13,7 @@ properties: compatible: oneOf: - enum: + - qcom,sa8775p-pcie-ep - qcom,sdx55-pcie-ep - qcom,sm8450-pcie-ep - items: @@ -20,6 +21,7 @@ properties: - const: qcom,sdx55-pcie-ep reg: + minItems: 6 items: - description: Qualcomm-specific PARF configuration registers - description: DesignWare PCIe registers @@ -27,8 +29,10 @@ properties: - description: Address Translation Unit (ATU) registers - description: Memory region used to map remote RC address space - description: BAR memory region + - description: DMA register space reg-names: + minItems: 6 items: - const: parf - const: dbi @@ -36,13 +40,14 @@ properties: - const: atu - const: addr_space - const: mmio + - const: dma clocks: - minItems: 7 + minItems: 5 maxItems: 8 clock-names: - minItems: 7 + minItems: 5 maxItems: 8 qcom,perst-regs: @@ -57,14 +62,18 @@ properties: - description: Perst separation enable offset interrupts: + minItems: 2 items: - description: PCIe Global interrupt - description: PCIe Doorbell interrupt + - description: DMA interrupt interrupt-names: + minItems: 2 items: - const: global - const: doorbell + - const: dma reset-gpios: description: GPIO used as PERST# input signal @@ -125,6 +134,10 @@ allOf: - qcom,sdx55-pcie-ep then: properties: + reg: + maxItems: 6 + reg-names: + maxItems: 6 clocks: items: - description: PCIe Auxiliary clock @@ -143,6 +156,10 @@ allOf: - const: slave_q2a - const: sleep - const: ref + interrupts: + maxItems: 2 + interrupt-names: + maxItems: 2 - if: properties: @@ -152,6 +169,10 @@ allOf: - qcom,sm8450-pcie-ep then: properties: + reg: + maxItems: 6 + reg-names: + maxItems: 6 clocks: items: - description: PCIe Auxiliary clock @@ -172,6 +193,45 @@ allOf: - const: ref - const: ddrss_sf_tbu - const: aggre_noc_axi + interrupts: + maxItems: 2 + interrupt-names: + maxItems: 2 + + - if: + properties: + compatible: + contains: + enum: + - qcom,sa8775p-pcie-ep + then: + properties: + reg: + minItems: 7 + maxItems: 7 + reg-names: + minItems: 7 + maxItems: 7 + clocks: + items: + - description: PCIe Auxiliary clock + - description: PCIe CFG AHB clock + - description: PCIe Master AXI clock + - description: PCIe Slave AXI clock + - description: PCIe Slave Q2A AXI clock + clock-names: + items: + - const: aux + - const: cfg + - const: bus_master + - const: bus_slave + - const: slave_q2a + interrupts: + minItems: 3 + maxItems: 3 + interrupt-names: + minItems: 3 + maxItems: 3 unevaluatedProperties: false -- cgit v1.2.3 From 58d0d3e032b3679023afd0062d9ddfb7823c6e5d Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Tue, 30 Apr 2024 21:25:38 +0530 Subject: PCI: qcom-ep: 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 to the Qualcomm PCIe Endpoint Controller driver. Adding new compatible string as it has different set of clocks compared to other SoCs. Link: https://lore.kernel.org/linux-pci/1714492540-15419-3-git-send-email-quic_msarkar@quicinc.com Signed-off-by: Mrinmay Sarkar Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 2fb8c15e7a91..a95c755df0fa 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -875,6 +875,7 @@ static void qcom_pcie_ep_remove(struct platform_device *pdev) } static const struct of_device_id qcom_pcie_ep_match[] = { + { .compatible = "qcom,sa8775p-pcie-ep", }, { .compatible = "qcom,sdx55-pcie-ep", }, { .compatible = "qcom,sm8450-pcie-ep", }, { } -- cgit v1.2.3 From 0b45127a1b85ed84bc78ebcd569968849df265a9 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 18 Mar 2024 11:34:25 +0530 Subject: PCI: dwc: Refactor dw_pcie_edma_find_chip() API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to add support for Hyper DMA (HDMA), refactor the existing dw_pcie_edma_find_chip() API by moving the common code to separate functions. No functional change. Suggested-by: Serge Semin Link: https://lore.kernel.org/linux-pci/20240318-dw-hdma-v5-1-f04c5cdde760@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Frank Li Reviewed-by: Serge Semin Reviewed-by: Siddharth Vadapalli Reviewed-by: Yoshihiro Shimoda --- drivers/pci/controller/dwc/pcie-designware.c | 37 ++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 250cf7f40b85..e591c1cd1efb 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -880,7 +880,17 @@ static struct dw_edma_plat_ops dw_pcie_edma_ops = { .irq_vector = dw_pcie_edma_irq_vector, }; -static int dw_pcie_edma_find_chip(struct dw_pcie *pci) +static void dw_pcie_edma_init_data(struct dw_pcie *pci) +{ + pci->edma.dev = pci->dev; + + if (!pci->edma.ops) + pci->edma.ops = &dw_pcie_edma_ops; + + pci->edma.flags |= DW_EDMA_CHIP_LOCAL; +} + +static int dw_pcie_edma_find_mf(struct dw_pcie *pci) { u32 val; @@ -902,8 +912,6 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci) if (val == 0xFFFFFFFF && pci->edma.reg_base) { pci->edma.mf = EDMA_MF_EDMA_UNROLL; - - val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL); } else if (val != 0xFFFFFFFF) { pci->edma.mf = EDMA_MF_EDMA_LEGACY; @@ -912,12 +920,14 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci) return -ENODEV; } - pci->edma.dev = pci->dev; + return 0; +} - if (!pci->edma.ops) - pci->edma.ops = &dw_pcie_edma_ops; +static int dw_pcie_edma_find_channels(struct dw_pcie *pci) +{ + u32 val; - pci->edma.flags |= DW_EDMA_CHIP_LOCAL; + val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL); pci->edma.ll_wr_cnt = FIELD_GET(PCIE_DMA_NUM_WR_CHAN, val); pci->edma.ll_rd_cnt = FIELD_GET(PCIE_DMA_NUM_RD_CHAN, val); @@ -930,6 +940,19 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci) return 0; } +static int dw_pcie_edma_find_chip(struct dw_pcie *pci) +{ + int ret; + + dw_pcie_edma_init_data(pci); + + ret = dw_pcie_edma_find_mf(pci); + if (ret) + return ret; + + return dw_pcie_edma_find_channels(pci); +} + static int dw_pcie_edma_irq_verify(struct dw_pcie *pci) { struct platform_device *pdev = to_platform_device(pci->dev); -- cgit v1.2.3 From 0d278fbdb432e4c8406b75487fe36e3a6b50a680 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 18 Mar 2024 11:34:26 +0530 Subject: PCI: dwc: Skip finding eDMA channels count for HDMA platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the case of Hyper DMA (HDMA) present in DWC controllers, there is no way the drivers can auto detect the number of read/write channels as like its predecessor embedded DMA (eDMA). So the glue drivers making use of HDMA have to pass the channels count during probe. To accommodate that, skip the existing auto detection of channels count procedure for HDMA based platforms. If the channels count passed by the glue drivers were wrong in any form, then the existing sanity check will catch it. Suggested-by: Serge Semin Link: https://lore.kernel.org/linux-pci/20240318-dw-hdma-v5-2-f04c5cdde760@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Frank Li Reviewed-by: Serge Semin Reviewed-by: Siddharth Vadapalli Reviewed-by: Yoshihiro Shimoda --- drivers/pci/controller/dwc/pcie-designware.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index e591c1cd1efb..d17549f67e72 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -927,10 +927,18 @@ static int dw_pcie_edma_find_channels(struct dw_pcie *pci) { u32 val; - val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL); + /* + * Autodetect the read/write channels count only for non-HDMA platforms. + * HDMA platforms with native CSR mapping doesn't support autodetect, + * so the glue drivers should've passed the valid count already. If not, + * the below sanity check will catch it. + */ + if (pci->edma.mf != EDMA_MF_HDMA_NATIVE) { + val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL); - pci->edma.ll_wr_cnt = FIELD_GET(PCIE_DMA_NUM_WR_CHAN, val); - pci->edma.ll_rd_cnt = FIELD_GET(PCIE_DMA_NUM_RD_CHAN, val); + pci->edma.ll_wr_cnt = FIELD_GET(PCIE_DMA_NUM_WR_CHAN, val); + pci->edma.ll_rd_cnt = FIELD_GET(PCIE_DMA_NUM_RD_CHAN, val); + } /* Sanity check the channels count if the mapping was incorrect */ if (!pci->edma.ll_wr_cnt || pci->edma.ll_wr_cnt > EDMA_MAX_WR_CH || -- cgit v1.2.3 From 0551abf2192dc944337516033678488cb08caa37 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 18 Mar 2024 11:34:27 +0530 Subject: PCI: dwc: Pass the eDMA mapping format flag directly from glue drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of maintaining a separate capability for glue drivers that cannot support auto detection of the eDMA mapping format, pass the mapping format directly from them. This will simplify the code and also allow adding HDMA support that also doesn't support auto detection of mapping format. Suggested-by: Serge Semin Link: https://lore.kernel.org/linux-pci/20240318-dw-hdma-v5-3-f04c5cdde760@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Serge Semin Reviewed-by: Siddharth Vadapalli Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda --- drivers/pci/controller/dwc/pcie-designware.c | 16 +++++++++------- drivers/pci/controller/dwc/pcie-designware.h | 5 ++--- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index d17549f67e72..bf57a2f713da 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -894,18 +894,20 @@ static int dw_pcie_edma_find_mf(struct dw_pcie *pci) { u32 val; + /* + * Bail out finding the mapping format if it is already set by the glue + * driver. Also ensure that the edma.reg_base is pointing to a valid + * memory region. + */ + if (pci->edma.mf != EDMA_MF_EDMA_LEGACY) + return pci->edma.reg_base ? 0 : -ENODEV; + /* * Indirect eDMA CSRs access has been completely removed since v5.40a * thus no space is now reserved for the eDMA channels viewport and * former DMA CTRL register is no longer fixed to FFs. - * - * Note that Renesas R-Car S4-8's PCIe controllers for unknown reason - * have zeros in the eDMA CTRL register even though the HW-manual - * explicitly states there must FFs if the unrolled mapping is enabled. - * For such cases the low-level drivers are supposed to manually - * activate the unrolled mapping to bypass the auto-detection procedure. */ - if (dw_pcie_ver_is_ge(pci, 540A) || dw_pcie_cap_is(pci, EDMA_UNROLL)) + if (dw_pcie_ver_is_ge(pci, 540A)) val = 0xFFFFFFFF; else val = dw_pcie_readl_dbi(pci, PCIE_DMA_VIEWPORT_BASE + PCIE_DMA_CTRL); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index f8e5431a207b..313cd9808403 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -51,9 +51,8 @@ /* DWC PCIe controller capabilities */ #define DW_PCIE_CAP_REQ_RES 0 -#define DW_PCIE_CAP_EDMA_UNROLL 1 -#define DW_PCIE_CAP_IATU_UNROLL 2 -#define DW_PCIE_CAP_CDM_CHECK 3 +#define DW_PCIE_CAP_IATU_UNROLL 1 +#define DW_PCIE_CAP_CDM_CHECK 2 #define dw_pcie_cap_is(_pci, _cap) \ test_bit(DW_PCIE_CAP_ ## _cap, &(_pci)->caps) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index cfeccc2f9ee1..d99e12f3e4ff 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -255,7 +255,7 @@ static struct rcar_gen4_pcie *rcar_gen4_pcie_alloc(struct platform_device *pdev) rcar->dw.ops = &dw_pcie_ops; rcar->dw.dev = dev; rcar->pdev = pdev; - dw_pcie_cap_set(&rcar->dw, EDMA_UNROLL); + rcar->dw.edma.mf = EDMA_MF_EDMA_UNROLL; dw_pcie_cap_set(&rcar->dw, REQ_RES); platform_set_drvdata(pdev, rcar); -- cgit v1.2.3 From c94391ba52b9efa8797ad75a95c40c40df833c61 Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Mon, 18 Mar 2024 11:34:28 +0530 Subject: PCI: qcom-ep: Add HDMA support for SA8775P SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SA8775P SoC supports the new Hyper DMA (HDMA) DMA Engine inside the DWC IP, so add support for it by passing the mapping format and the number of read/write channels count. The PCIe EP controller used on this SoC is of version 1.34.0, so a separate config struct is introduced for the sake of enabling HDMA conditionally. It should be noted that for the eDMA support (predecessor of HDMA), there are no mapping format and channels count specified. That is because eDMA supports auto detection of both parameters, whereas HDMA doesn't. [mani: reworded commit message, added kdoc, and minor cleanups] Link: https://lore.kernel.org/linux-pci/20240318-dw-hdma-v5-4-f04c5cdde760@linaro.org Signed-off-by: Mrinmay Sarkar Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Frank Li Reviewed-by: Siddharth Vadapalli --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index a95c755df0fa..925a2427ece1 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -149,6 +149,14 @@ enum qcom_pcie_ep_link_status { QCOM_PCIE_EP_LINK_DOWN, }; +/** + * struct qcom_pcie_ep_cfg - Per SoC config struct + * @hdma_support: HDMA support on this SoC + */ +struct qcom_pcie_ep_cfg { + bool hdma_support; +}; + /** * struct qcom_pcie_ep - Qualcomm PCIe Endpoint Controller * @pci: Designware PCIe controller struct @@ -803,6 +811,7 @@ static const struct dw_pcie_ep_ops pci_ep_ops = { static int qcom_pcie_ep_probe(struct platform_device *pdev) { + const struct qcom_pcie_ep_cfg *cfg; struct device *dev = &pdev->dev; struct qcom_pcie_ep *pcie_ep; char *name; @@ -816,6 +825,14 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) pcie_ep->pci.ops = &pci_ops; pcie_ep->pci.ep.ops = &pci_ep_ops; pcie_ep->pci.edma.nr_irqs = 1; + + cfg = of_device_get_match_data(dev); + if (cfg && cfg->hdma_support) { + pcie_ep->pci.edma.ll_wr_cnt = 8; + pcie_ep->pci.edma.ll_rd_cnt = 8; + pcie_ep->pci.edma.mf = EDMA_MF_HDMA_NATIVE; + } + platform_set_drvdata(pdev, pcie_ep); ret = qcom_pcie_ep_get_resources(pdev, pcie_ep); @@ -874,8 +891,12 @@ static void qcom_pcie_ep_remove(struct platform_device *pdev) qcom_pcie_disable_resources(pcie_ep); } +static const struct qcom_pcie_ep_cfg cfg_1_34_0 = { + .hdma_support = true, +}; + static const struct of_device_id qcom_pcie_ep_match[] = { - { .compatible = "qcom,sa8775p-pcie-ep", }, + { .compatible = "qcom,sa8775p-pcie-ep", .data = &cfg_1_34_0}, { .compatible = "qcom,sdx55-pcie-ep", }, { .compatible = "qcom,sm8450-pcie-ep", }, { } -- cgit v1.2.3 From 3c6c8443d45072b43c939eba9e891159a37ed282 Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Mon, 18 Mar 2024 11:34:29 +0530 Subject: PCI: epf-mhi: Enable HDMA for SA8775P SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SA8775P SoC supports Hyper DMA (HDMA) DMA Engine present in the DWC IP. So, enable it in the EPF driver so that the DMA Engine APIs can be used for data transfer. [mani: reworded commit message] Link: https://lore.kernel.org/linux-pci/20240318-dw-hdma-v5-5-f04c5cdde760@linaro.org Signed-off-by: Mrinmay Sarkar Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Frank Li Reviewed-by: Siddharth Vadapalli --- drivers/pci/endpoint/functions/pci-epf-mhi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c index 2c54d80107cf..570c1d1fb12e 100644 --- a/drivers/pci/endpoint/functions/pci-epf-mhi.c +++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c @@ -137,6 +137,7 @@ static const struct pci_epf_mhi_ep_info sa8775p_info = { .epf_flags = PCI_BASE_ADDRESS_MEM_TYPE_32, .msi_count = 32, .mru = 0x8000, + .flags = MHI_EPF_USE_DMA, }; struct pci_epf_mhi { -- cgit v1.2.3 From 1d648bf79d4dca909f242b1a0cdc458e4f9d0253 Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Mon, 11 Mar 2024 19:41:35 +0530 Subject: PCI: qcom: Override NO_SNOOP attribute for SA8775P RC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to some hardware changes, SA8775P has set the NO_SNOOP attribute in its TLP for all the PCIe controllers. NO_SNOOP attribute when set, the requester is indicating that no cache coherency issue exist for the addressed memory on the endpoint i.e., memory is not cached. But in reality, requester cannot assume this unless there is a complete control/visibility over the addressed memory on the endpoint. And worst case, if the memory is cached on the endpoint, it may lead to memory corruption issues. It should be noted that the caching of memory on the endpoint is not solely dependent on the NO_SNOOP attribute in TLP. So to avoid the corruption, this patch overrides the NO_SNOOP attribute by setting the PCIE_PARF_NO_SNOOP_OVERIDE register. This patch is not needed for other upstream supported platforms since they do not set NO_SNOOP attribute by default. 8775 has IP version 1.34.0 so introduce a new cfg(cfg_1_34_0) for this platform. Assign override_no_snoop flag into struct qcom_pcie_cfg and set it true in cfg_1_34_0 and enable cache snooping if this particular flag is true. Link: https://lore.kernel.org/linux-pci/1710166298-27144-2-git-send-email-quic_msarkar@quicinc.com Signed-off-by: Mrinmay Sarkar Signed-off-by: Krzysztof Wilczyński [bhelgaas: wrap comments to fit in 80 columns] Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 3d2eeff9a876..4dc1388c3171 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -51,6 +51,7 @@ #define PARF_SID_OFFSET 0x234 #define PARF_BDF_TRANSLATE_CFG 0x24c #define PARF_SLV_ADDR_SPACE_SIZE 0x358 +#define PARF_NO_SNOOP_OVERIDE 0x3d4 #define PARF_DEVICE_TYPE 0x1000 #define PARF_BDF_TO_SID_TABLE_N 0x2000 #define PARF_BDF_TO_SID_CFG 0x2c00 @@ -118,6 +119,10 @@ /* PARF_LTSSM register fields */ #define LTSSM_EN BIT(8) +/* PARF_NO_SNOOP_OVERIDE register fields */ +#define WR_NO_SNOOP_OVERIDE_EN BIT(1) +#define RD_NO_SNOOP_OVERIDE_EN BIT(3) + /* PARF_DEVICE_TYPE register fields */ #define DEVICE_TYPE_RC 0x4 @@ -229,8 +234,15 @@ struct qcom_pcie_ops { int (*config_sid)(struct qcom_pcie *pcie); }; + /** + * struct qcom_pcie_cfg - Per SoC config struct + * @ops: qcom PCIe ops structure + * @override_no_snoop: Override NO_SNOOP attribute in TLP to enable cache + * snooping + */ struct qcom_pcie_cfg { const struct qcom_pcie_ops *ops; + bool override_no_snoop; bool no_l0s; }; @@ -930,6 +942,12 @@ err_disable_regulators: static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) { + const struct qcom_pcie_cfg *pcie_cfg = pcie->cfg; + + if (pcie_cfg->override_no_snoop) + writel(WR_NO_SNOOP_OVERIDE_EN | RD_NO_SNOOP_OVERIDE_EN, + pcie->parf + PARF_NO_SNOOP_OVERIDE); + qcom_pcie_clear_aspm_l0s(pcie->pci); qcom_pcie_clear_hpc(pcie->pci); @@ -1305,6 +1323,11 @@ static const struct qcom_pcie_cfg cfg_1_9_0 = { .ops = &ops_1_9_0, }; +static const struct qcom_pcie_cfg cfg_1_34_0 = { + .ops = &ops_1_9_0, + .override_no_snoop = true, +}; + static const struct qcom_pcie_cfg cfg_2_1_0 = { .ops = &ops_2_1_0, }; @@ -1606,7 +1629,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_sc8280xp }, - { .compatible = "qcom,pcie-sa8775p", .data = &cfg_1_9_0}, + { .compatible = "qcom,pcie-sa8775p", .data = &cfg_1_34_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_sc8280xp }, -- cgit v1.2.3 From c71b5eb3b86448aa4bad6b2ca94c6e1d1962a5fb Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Mon, 11 Mar 2024 19:41:36 +0530 Subject: PCI: qcom-ep: Override NO_SNOOP attribute for SA8775P EP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to some hardware changes, SA8775P has set the NO_SNOOP attribute in its TLP for all the PCIe controllers. NO_SNOOP attribute when set, the requester is indicating that no cache coherency issues exist for the addressed memory on the host i.e., memory is not cached. But in reality, requester cannot assume this unless there is a complete control/visibility over the addressed memory on the host. And worst case, if the memory is cached on the host, it may lead to memory corruption issues. It should be noted that the caching of memory on the host is not solely dependent on the NO_SNOOP attribute in TLP. So to avoid the corruption, this patch overrides the NO_SNOOP attribute by setting the PCIE_PARF_NO_SNOOP_OVERIDE register. This patch is not needed for other upstream supported platforms since they do not set NO_SNOOP attribute by default. Link: https://lore.kernel.org/linux-pci/1710166298-27144-3-git-send-email-quic_msarkar@quicinc.com Signed-off-by: Mrinmay Sarkar Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 925a2427ece1..e2a28939b958 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -47,6 +47,7 @@ #define PARF_DBI_BASE_ADDR_HI 0x354 #define PARF_SLV_ADDR_SPACE_SIZE 0x358 #define PARF_SLV_ADDR_SPACE_SIZE_HI 0x35c +#define PARF_NO_SNOOP_OVERIDE 0x3d4 #define PARF_ATU_BASE_ADDR 0x634 #define PARF_ATU_BASE_ADDR_HI 0x638 #define PARF_SRIS_MODE 0x644 @@ -86,6 +87,10 @@ #define PARF_DEBUG_INT_CFG_BUS_MASTER_EN BIT(2) #define PARF_DEBUG_INT_RADM_PM_TURNOFF BIT(3) +/* PARF_NO_SNOOP_OVERIDE register fields */ +#define WR_NO_SNOOP_OVERIDE_EN BIT(1) +#define RD_NO_SNOOP_OVERIDE_EN BIT(3) + /* PARF_DEVICE_TYPE register fields */ #define PARF_DEVICE_TYPE_EP 0x0 @@ -152,9 +157,11 @@ enum qcom_pcie_ep_link_status { /** * struct qcom_pcie_ep_cfg - Per SoC config struct * @hdma_support: HDMA support on this SoC + * @override_no_snoop: Override NO_SNOOP attribute in TLP to enable cache snooping */ struct qcom_pcie_ep_cfg { bool hdma_support; + bool override_no_snoop; }; /** @@ -175,6 +182,7 @@ struct qcom_pcie_ep_cfg { * @num_clks: PCIe clocks count * @perst_en: Flag for PERST enable * @perst_sep_en: Flag for PERST separation enable + * @cfg: PCIe EP config struct * @link_status: PCIe Link status * @global_irq: Qualcomm PCIe specific Global IRQ * @perst_irq: PERST# IRQ @@ -202,6 +210,7 @@ struct qcom_pcie_ep { u32 perst_en; u32 perst_sep_en; + const struct qcom_pcie_ep_cfg *cfg; enum qcom_pcie_ep_link_status link_status; int global_irq; int perst_irq; @@ -497,6 +506,10 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) val |= BIT(8); writel_relaxed(val, pcie_ep->parf + PARF_LTSSM); + if (pcie_ep->cfg && pcie_ep->cfg->override_no_snoop) + writel_relaxed(WR_NO_SNOOP_OVERIDE_EN | RD_NO_SNOOP_OVERIDE_EN, + pcie_ep->parf + PARF_NO_SNOOP_OVERIDE); + return 0; err_disable_resources: @@ -811,7 +824,6 @@ static const struct dw_pcie_ep_ops pci_ep_ops = { static int qcom_pcie_ep_probe(struct platform_device *pdev) { - const struct qcom_pcie_ep_cfg *cfg; struct device *dev = &pdev->dev; struct qcom_pcie_ep *pcie_ep; char *name; @@ -826,8 +838,8 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) pcie_ep->pci.ep.ops = &pci_ep_ops; pcie_ep->pci.edma.nr_irqs = 1; - cfg = of_device_get_match_data(dev); - if (cfg && cfg->hdma_support) { + pcie_ep->cfg = of_device_get_match_data(dev); + if (pcie_ep->cfg && pcie_ep->cfg->hdma_support) { pcie_ep->pci.edma.ll_wr_cnt = 8; pcie_ep->pci.edma.ll_rd_cnt = 8; pcie_ep->pci.edma.mf = EDMA_MF_HDMA_NATIVE; @@ -893,6 +905,7 @@ static void qcom_pcie_ep_remove(struct platform_device *pdev) static const struct qcom_pcie_ep_cfg cfg_1_34_0 = { .hdma_support = true, + .override_no_snoop = true, }; static const struct of_device_id qcom_pcie_ep_match[] = { -- cgit v1.2.3 From 912315715d7b74f7abdb6f063ebace44ee288af9 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 30 Apr 2024 11:43:42 +0530 Subject: PCI: qcom-ep: Disable resources unconditionally during PERST# assert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All EP specific resources are enabled during PERST# deassert. As a counter operation, all resources should be disabled during PERST# assert. There is no point in skipping that if the link was not enabled. This will also result in enablement of the resources twice if PERST# got deasserted again. So remove the check from qcom_pcie_perst_assert() and disable all the resources unconditionally. Fixes: f55fee56a631 ("PCI: qcom-ep: Add Qualcomm PCIe Endpoint controller driver") Link: https://lore.kernel.org/linux-pci/20240430-pci-epf-rework-v4-1-22832d0d456f@linaro.org Tested-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Niklas Cassel --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index e2a28939b958..20c4a8063efb 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -521,12 +521,6 @@ err_disable_resources: static void qcom_pcie_perst_assert(struct dw_pcie *pci) { struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); - struct device *dev = pci->dev; - - if (pcie_ep->link_status == QCOM_PCIE_EP_LINK_DISABLED) { - dev_dbg(dev, "Link is already disabled\n"); - return; - } dw_pcie_ep_cleanup(&pci->ep); qcom_pcie_disable_resources(pcie_ep); -- cgit v1.2.3 From 980136d1c2b95644b96df6c7ec00ca5d7c87f37f Mon Sep 17 00:00:00 2001 From: Krishna chaitanya chundru Date: Wed, 19 Jun 2024 20:41:10 +0530 Subject: PCI: qcom: Add ICC bandwidth vote for CPU to PCIe path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To access the host controller registers of the host controller and the endpoint BAR/config space, the CPU-PCIe ICC (interconnect) path should be voted otherwise it may lead to NoC (Network on chip) timeout. We are surviving because of other driver voting for this path. As there is less access on this path compared to PCIe to mem path add minimum vote i.e 1KBps bandwidth always which is sufficient enough to keep the path active and is recommended by HW team. During S2RAM (Suspend-to-RAM), the DBI access can happen very late (while disabling the boot CPU). So do not disable the CPU-PCIe interconnect path during S2RAM as that may lead to NoC error. Link: https://lore.kernel.org/linux-pci/20240619-opp_support-v15-1-aa769a2173a3@quicinc.com Signed-off-by: Krishna chaitanya chundru Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Bryan O'Donoghue Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 45 +++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 4dc1388c3171..bbed7255fb12 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -255,6 +255,7 @@ struct qcom_pcie { struct phy *phy; struct gpio_desc *reset; struct icc_path *icc_mem; + struct icc_path *icc_cpu; const struct qcom_pcie_cfg *cfg; struct dentry *debugfs; bool suspended; @@ -1371,6 +1372,9 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie) if (IS_ERR(pcie->icc_mem)) return PTR_ERR(pcie->icc_mem); + pcie->icc_cpu = devm_of_icc_get(pci->dev, "cpu-pcie"); + if (IS_ERR(pcie->icc_cpu)) + return PTR_ERR(pcie->icc_cpu); /* * Some Qualcomm platforms require interconnect bandwidth constraints * to be set before enabling interconnect clocks. @@ -1380,11 +1384,25 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie) */ ret = icc_set_bw(pcie->icc_mem, 0, QCOM_PCIE_LINK_SPEED_TO_BW(1)); if (ret) { - dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n", + dev_err(pci->dev, "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", ret); return ret; } + /* + * Since the CPU-PCIe path is only used for activities like register + * access of the host controller and endpoint Config/BAR space access, + * HW team has recommended to use a minimal bandwidth of 1KBps just to + * keep the path active. + */ + ret = icc_set_bw(pcie->icc_cpu, 0, kBps_to_icc(1)); + if (ret) { + dev_err(pci->dev, "Failed to set bandwidth for CPU-PCIe interconnect path: %d\n", + ret); + icc_set_bw(pcie->icc_mem, 0, 0); + return ret; + } + return 0; } @@ -1410,7 +1428,7 @@ static void qcom_pcie_icc_update(struct qcom_pcie *pcie) ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed)); if (ret) { - dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n", + dev_err(pci->dev, "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", ret); } } @@ -1572,7 +1590,7 @@ static int qcom_pcie_suspend_noirq(struct device *dev) */ ret = icc_set_bw(pcie->icc_mem, 0, kBps_to_icc(1)); if (ret) { - dev_err(dev, "Failed to set interconnect bandwidth: %d\n", ret); + dev_err(dev, "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", ret); return ret; } @@ -1596,7 +1614,18 @@ static int qcom_pcie_suspend_noirq(struct device *dev) pcie->suspended = true; } - return 0; + /* + * Only disable CPU-PCIe interconnect path if the suspend is non-S2RAM. + * Because on some platforms, DBI access can happen very late during the + * S2RAM and a non-active CPU-PCIe interconnect path may lead to NoC + * error. + */ + if (pm_suspend_target_state != PM_SUSPEND_MEM) { + ret = icc_disable(pcie->icc_cpu); + if (ret) + dev_err(dev, "Failed to disable CPU-PCIe interconnect path: %d\n", ret); + } + return ret; } static int qcom_pcie_resume_noirq(struct device *dev) @@ -1604,6 +1633,14 @@ static int qcom_pcie_resume_noirq(struct device *dev) struct qcom_pcie *pcie = dev_get_drvdata(dev); int ret; + if (pm_suspend_target_state != PM_SUSPEND_MEM) { + ret = icc_enable(pcie->icc_cpu); + if (ret) { + dev_err(dev, "Failed to enable CPU-PCIe interconnect path: %d\n", ret); + return ret; + } + } + if (pcie->suspended) { ret = qcom_pcie_host_init(&pcie->pci->pp); if (ret) -- cgit v1.2.3 From 100ae5d77f07f9f046106e228778c7aa1c6d3af3 Mon Sep 17 00:00:00 2001 From: Krishna chaitanya chundru Date: Wed, 19 Jun 2024 20:41:12 +0530 Subject: PCI: Bring the PCIe speed to MBps logic to new pcie_dev_speed_mbps() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring the switch case in pcie_link_speed_mbps() to new function to the header file so that it can be used in other places like in controller driver. Link: https://lore.kernel.org/linux-pci/20240619-opp_support-v15-3-aa769a2173a3@quicinc.com Signed-off-by: Krishna chaitanya chundru Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam --- drivers/pci/pci.c | 19 +------------------ drivers/pci/pci.h | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 59e0949fb079..ac28b5d34648 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6020,24 +6020,7 @@ int pcie_link_speed_mbps(struct pci_dev *pdev) if (err) return err; - switch (to_pcie_link_speed(lnksta)) { - case PCIE_SPEED_2_5GT: - return 2500; - case PCIE_SPEED_5_0GT: - return 5000; - case PCIE_SPEED_8_0GT: - return 8000; - case PCIE_SPEED_16_0GT: - return 16000; - case PCIE_SPEED_32_0GT: - return 32000; - case PCIE_SPEED_64_0GT: - return 64000; - default: - break; - } - - return -EINVAL; + return pcie_dev_speed_mbps(to_pcie_link_speed(lnksta)); } EXPORT_SYMBOL(pcie_link_speed_mbps); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index fd44565c4756..7e766dcba8fb 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -290,6 +290,28 @@ void pci_bus_put(struct pci_bus *bus); (speed) == PCIE_SPEED_2_5GT ? 2500*8/10 : \ 0) +static inline int pcie_dev_speed_mbps(enum pci_bus_speed speed) +{ + switch (speed) { + case PCIE_SPEED_2_5GT: + return 2500; + case PCIE_SPEED_5_0GT: + return 5000; + case PCIE_SPEED_8_0GT: + return 8000; + case PCIE_SPEED_16_0GT: + return 16000; + case PCIE_SPEED_32_0GT: + return 32000; + case PCIE_SPEED_64_0GT: + return 64000; + default: + break; + } + + return -EINVAL; +} + const char *pci_speed_string(enum pci_bus_speed speed); enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev); enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev); -- cgit v1.2.3 From 5b6272e0efd53c487bfc5d2921d71ecae37b0446 Mon Sep 17 00:00:00 2001 From: Krishna chaitanya chundru Date: Wed, 19 Jun 2024 20:41:13 +0530 Subject: PCI: qcom: Add OPP support to scale performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QCOM Resource Power Manager-hardened (RPMh) is a hardware block which maintains hardware state of a regulator by performing max aggregation of the requests made by all of the clients. PCIe controller can operate on different RPMh performance state of power domain based on the speed of the link. And this performance state varies from target to target, like some controllers support GEN3 in NOM (Nominal) voltage corner, while some other supports GEN3 in low SVS (static voltage scaling). The SoC can be more power efficient if we scale the performance state based on the aggregate PCIe link bandwidth. Add Operating Performance Points (OPP) support to vote for RPMh state based on the aggregate link bandwidth. OPP can handle ICC bw voting also, so move ICC bw voting through OPP framework if OPP entries are present. As we are moving ICC voting as part of OPP, don't initialize ICC if OPP is supported. Before PCIe link is initialized vote for highest OPP in the OPP table, so that we are voting for maximum voltage corner for the link to come up in maximum supported speed. Link: https://lore.kernel.org/linux-pci/20240619-opp_support-v15-4-aa769a2173a3@quicinc.com Signed-off-by: Krishna chaitanya chundru Signed-off-by: Krzysztof Wilczyński [bhelgaas: wrap comments to fit in 80 columns] Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 99 +++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 19 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index bbed7255fb12..c8cbfb91e1d5 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -18,10 +18,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -30,6 +32,7 @@ #include #include #include +#include #include "../../pci.h" #include "pcie-designware.h" @@ -1406,15 +1409,13 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie) return 0; } -static void qcom_pcie_icc_update(struct qcom_pcie *pcie) +static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie) { + u32 offset, status, width, speed; struct dw_pcie *pci = pcie->pci; - u32 offset, status; - int speed, width; - int ret; - - if (!pcie->icc_mem) - return; + unsigned long freq_kbps; + struct dev_pm_opp *opp; + int ret, freq_mbps; offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA); @@ -1426,10 +1427,28 @@ static void qcom_pcie_icc_update(struct qcom_pcie *pcie) speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status); width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status); - ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed)); - if (ret) { - dev_err(pci->dev, "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", - ret); + if (pcie->icc_mem) { + ret = icc_set_bw(pcie->icc_mem, 0, + width * QCOM_PCIE_LINK_SPEED_TO_BW(speed)); + if (ret) { + dev_err(pci->dev, "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", + ret); + } + } else { + freq_mbps = pcie_dev_speed_mbps(pcie_link_speed[speed]); + if (freq_mbps < 0) + return; + + freq_kbps = freq_mbps * KILO; + opp = dev_pm_opp_find_freq_exact(pci->dev, freq_kbps * width, + true); + if (!IS_ERR(opp)) { + ret = dev_pm_opp_set_opp(pci->dev, opp); + if (ret) + dev_err(pci->dev, "Failed to set OPP for freq (%lu): %d\n", + freq_kbps * width, ret); + } + dev_pm_opp_put(opp); } } @@ -1473,7 +1492,9 @@ static void qcom_pcie_init_debugfs(struct qcom_pcie *pcie) static int qcom_pcie_probe(struct platform_device *pdev) { const struct qcom_pcie_cfg *pcie_cfg; + unsigned long max_freq = ULONG_MAX; struct device *dev = &pdev->dev; + struct dev_pm_opp *opp; struct qcom_pcie *pcie; struct dw_pcie_rp *pp; struct resource *res; @@ -1541,9 +1562,42 @@ static int qcom_pcie_probe(struct platform_device *pdev) goto err_pm_runtime_put; } - ret = qcom_pcie_icc_init(pcie); - if (ret) + /* OPP table is optional */ + ret = devm_pm_opp_of_add_table(dev); + if (ret && ret != -ENODEV) { + dev_err_probe(dev, ret, "Failed to add OPP table\n"); goto err_pm_runtime_put; + } + + /* + * Before the PCIe link is initialized, vote for highest OPP in the OPP + * table, so that we are voting for maximum voltage corner for the + * link to come up in maximum supported speed. At the end of the + * probe(), OPP will be updated using qcom_pcie_icc_opp_update(). + */ + if (!ret) { + opp = dev_pm_opp_find_freq_floor(dev, &max_freq); + if (IS_ERR(opp)) { + dev_err_probe(pci->dev, PTR_ERR(opp), + "Unable to find max freq OPP\n"); + goto err_pm_runtime_put; + } else { + ret = dev_pm_opp_set_opp(dev, opp); + } + + dev_pm_opp_put(opp); + if (ret) { + dev_err_probe(pci->dev, ret, + "Failed to set OPP for freq %lu\n", + max_freq); + goto err_pm_runtime_put; + } + } else { + /* Skip ICC init if OPP is supported as it is handled by OPP */ + ret = qcom_pcie_icc_init(pcie); + if (ret) + goto err_pm_runtime_put; + } ret = pcie->cfg->ops->get_resources(pcie); if (ret) @@ -1563,7 +1617,7 @@ static int qcom_pcie_probe(struct platform_device *pdev) goto err_phy_exit; } - qcom_pcie_icc_update(pcie); + qcom_pcie_icc_opp_update(pcie); if (pcie->mhi) qcom_pcie_init_debugfs(pcie); @@ -1588,10 +1642,14 @@ static int qcom_pcie_suspend_noirq(struct device *dev) * Set minimum bandwidth required to keep data path functional during * suspend. */ - ret = icc_set_bw(pcie->icc_mem, 0, kBps_to_icc(1)); - if (ret) { - dev_err(dev, "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", ret); - return ret; + if (pcie->icc_mem) { + ret = icc_set_bw(pcie->icc_mem, 0, kBps_to_icc(1)); + if (ret) { + dev_err(dev, + "Failed to set bandwidth for PCIe-MEM interconnect path: %d\n", + ret); + return ret; + } } /* @@ -1624,6 +1682,9 @@ static int qcom_pcie_suspend_noirq(struct device *dev) ret = icc_disable(pcie->icc_cpu); if (ret) dev_err(dev, "Failed to disable CPU-PCIe interconnect path: %d\n", ret); + + if (!pcie->icc_mem) + dev_pm_opp_set_opp(pcie->pci->dev, NULL); } return ret; } @@ -1649,7 +1710,7 @@ static int qcom_pcie_resume_noirq(struct device *dev) pcie->suspended = false; } - qcom_pcie_icc_update(pcie); + qcom_pcie_icc_opp_update(pcie); return 0; } -- cgit v1.2.3 From 101e5c5c4e766901492b51c33b34af5f775b043f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 8 Jul 2024 13:05:36 -0500 Subject: PCI: qcom: Fix missing error code in qcom_pcie_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return a negative error code if dev_pm_opp_find_freq_floor() fails; don't return success. Fixes: 78b5f6f8855e ("PCI: qcom: Add OPP support to scale performance") Link: https://lore.kernel.org/linux-pci/20240708180539.1447307-2-dan.carpenter@linaro.org Signed-off-by: Dan Carpenter Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Tested-by: Anders Roxell Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index c8cbfb91e1d5..067ccb9cc6d0 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1578,7 +1578,8 @@ static int qcom_pcie_probe(struct platform_device *pdev) if (!ret) { opp = dev_pm_opp_find_freq_floor(dev, &max_freq); if (IS_ERR(opp)) { - dev_err_probe(pci->dev, PTR_ERR(opp), + ret = PTR_ERR(opp); + dev_err_probe(pci->dev, ret, "Unable to find max freq OPP\n"); goto err_pm_runtime_put; } else { -- cgit v1.2.3 From 9553636b5757789536d0d23c83e7fba11812f958 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 8 Jul 2024 13:05:37 -0500 Subject: PCI: qcom: Prevent potential error pointer dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only call dev_pm_opp_put() if dev_pm_opp_find_freq_exact() succeeds; otherwise it leads to an error pointer dereference. Fixes: 78b5f6f8855e ("PCI: qcom: Add OPP support to scale performance") Link: https://lore.kernel.org/linux-pci/20240708180539.1447307-3-dan.carpenter@linaro.org Signed-off-by: Dan Carpenter Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Tested-by: Anders Roxell Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 067ccb9cc6d0..5973df2238b0 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1447,8 +1447,8 @@ static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie) if (ret) dev_err(pci->dev, "Failed to set OPP for freq (%lu): %d\n", freq_kbps * width, ret); + dev_pm_opp_put(opp); } - dev_pm_opp_put(opp); } } -- cgit v1.2.3 From 044b45be04cb16125a0eccba532e88dc529f64de Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 8 Jul 2024 13:05:38 -0500 Subject: PCI: qcom: Prevent use of uninitialized data in qcom_pcie_suspend_noirq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Smatch complains that "ret" could be uninitialized if "pcie->icc_mem" is NULL and "pm_suspend_target_state == PM_SUSPEND_MEM". Silence this warning by initializing ret to zero. Fixes: 78b5f6f8855e ("PCI: qcom: Add OPP support to scale performance") Link: https://lore.kernel.org/linux-pci/20240708180539.1447307-4-dan.carpenter@linaro.org Signed-off-by: Dan Carpenter Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Tested-by: Anders Roxell Reviewed-by: Manivannan Sadhasivam --- drivers/pci/controller/dwc/pcie-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 5973df2238b0..e60432b238fb 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1637,7 +1637,7 @@ err_pm_runtime_put: static int qcom_pcie_suspend_noirq(struct device *dev) { struct qcom_pcie *pcie = dev_get_drvdata(dev); - int ret; + int ret = 0; /* * Set minimum bandwidth required to keep data path functional during -- cgit v1.2.3