]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: qcom: Set max OPP before DBI access during resume
authorQiang Yu <qiang.yu@oss.qualcomm.com>
Fri, 17 Apr 2026 04:16:25 +0000 (21:16 -0700)
committerManivannan Sadhasivam <mani@kernel.org>
Wed, 13 May 2026 13:42:44 +0000 (19:12 +0530)
During resume, qcom_pcie_icc_opp_update() may access DBI registers before
the OPP votes are restored, triggering NoC errors.

Set the PCIe controller to the maximum OPP first in resume_noirq(), then
proceed with link/DBI accesses. The OPP is later updated again based on
the actual link bandwidth requirements.

Introduce a helper to reuse the max-OPP setup code and share it with
probe().

Fixes: 5b6272e0efd5 ("PCI: qcom: Add OPP support to scale performance")
Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
[mani: commit log and error log rewording]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20260416-setmaxopp-v1-1-6a74e2d945a0@oss.qualcomm.com
drivers/pci/controller/dwc/pcie-qcom.c

index af6bf5cce65bee0b12ef7a08bfc1121d85b407f9..f21f3806fc1f4be4a370c1644b75185a2362fce3 100644 (file)
@@ -1613,6 +1613,22 @@ static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie)
        }
 }
 
+static int qcom_pcie_set_max_opp(struct device *dev)
+{
+       unsigned long max_freq = ULONG_MAX;
+       struct dev_pm_opp *opp;
+       int ret;
+
+       opp = dev_pm_opp_find_freq_floor(dev, &max_freq);
+       if (IS_ERR(opp))
+               return PTR_ERR(opp);
+
+       ret = dev_pm_opp_set_opp(dev, opp);
+       dev_pm_opp_put(opp);
+
+       return ret;
+}
+
 static int qcom_pcie_link_transition_count(struct seq_file *s, void *data)
 {
        struct qcom_pcie *pcie = (struct qcom_pcie *)dev_get_drvdata(s->private);
@@ -1845,9 +1861,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
        struct qcom_pcie_perst *perst, *tmp_perst;
        struct qcom_pcie_port *port, *tmp_port;
        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;
@@ -1951,21 +1965,9 @@ static int qcom_pcie_probe(struct platform_device *pdev)
         * 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)) {
-                       ret = PTR_ERR(opp);
-                       dev_err_probe(pci->dev, ret,
-                                     "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);
+               ret = qcom_pcie_set_max_opp(dev);
                if (ret) {
-                       dev_err_probe(pci->dev, ret,
-                                     "Failed to set OPP for freq %lu\n",
-                                     max_freq);
+                       dev_err_probe(dev, ret, "Failed to set max OPP\n");
                        goto err_pm_runtime_put;
                }
 
@@ -2100,6 +2102,14 @@ static int qcom_pcie_resume_noirq(struct device *dev)
                return 0;
 
        if (pm_suspend_target_state != PM_SUSPEND_MEM) {
+               if (pcie->use_pm_opp) {
+                       ret = qcom_pcie_set_max_opp(dev);
+                       if (ret) {
+                               dev_err(dev, "Failed to set max OPP: %d\n", ret);
+                               return ret;
+                       }
+               }
+
                ret = icc_enable(pcie->icc_cpu);
                if (ret) {
                        dev_err(dev, "Failed to enable CPU-PCIe interconnect path: %d\n", ret);