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: 5b6272e0ef ("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
This commit is contained in:
Qiang Yu 2026-04-16 21:16:25 -07:00 committed by Manivannan Sadhasivam
parent 254f49634e
commit 5dc31cd4a9

View 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);