From: Qiang Yu Date: Fri, 17 Apr 2026 04:16:25 +0000 (-0700) Subject: PCI: qcom: Set max OPP before DBI access during resume X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5dc31cd4a91a7f006d23efa97a5594a7e3ac7790;p=thirdparty%2Fkernel%2Fstable.git PCI: qcom: Set max OPP before DBI access during resume 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 [mani: commit log and error log rewording] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260416-setmaxopp-v1-1-6a74e2d945a0@oss.qualcomm.com --- diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index af6bf5cce65be..f21f3806fc1f4 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -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);