diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 6e04d0d75824d2..15c20675bac9f6 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1809,26 +1809,40 @@ static int qcom_pcie_probe(struct platform_device *pdev) static int __maybe_unused qcom_pcie_pm_suspend(struct qcom_pcie *pcie) { u32 val; + ktime_t timeout, start; struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; if (!pcie->cfg->supports_system_suspend) return 0; - /* if the link is not active turn off clocks */ - if (!dw_pcie_link_up(pci)) { - dev_info(dev, "Link is not active\n"); - goto suspend; - } + start = ktime_get(); + /* Wait max 200 ms */ + timeout = ktime_add_ms(start, 200); - /* if the link is not in l1ss don't turn off clocks */ - val = readl(pcie->parf + PCIE20_PARF_PM_STTS); - if (!(val & PCIE20_PARF_PM_STTS_LINKST_IN_L1SUB)) { - dev_warn(dev, "Link is not in L1ss\n"); - return 0; + while (1) { + + if (!dw_pcie_link_up(pci)) { + dev_warn(dev, "Link is not active\n"); + break; + } + + /* if the link is not in l1ss don't turn off clocks */ + val = readl(pcie->parf + PCIE20_PARF_PM_STTS); + if ((val & PCIE20_PARF_PM_STTS_LINKST_IN_L1SUB)) { + dev_dbg(dev, "Link enters L1ss after %d ms\n", + ktime_to_ms(ktime_get() - start)); + break; + } + + if (ktime_after(ktime_get(), timeout)) { + dev_warn(dev, "Link is not in L1ss\n"); + return 0; + } + + udelay(1000); } -suspend: if (pcie->cfg->ops->suspend) pcie->cfg->ops->suspend(pcie);