]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: dwc: Remove LTSSM state test in dw_pcie_suspend_noirq()
authorRichard Zhu <hongxing.zhu@nxp.com>
Tue, 10 Dec 2024 08:15:57 +0000 (16:15 +0800)
committerBjorn Helgaas <bhelgaas@google.com>
Sat, 18 Jan 2025 19:38:34 +0000 (13:38 -0600)
It's safe to send PME_TURN_OFF message regardless of whether the link is up
or down, so don't test the LTSSM state before sending the PME_TURN_OFF
message.

Only print an error message when the LTSSM is not in DETECT or POLL. There
shouldn't be an error when no Endpoint is connected at all.

Link: https://lore.kernel.org/r/20241210081557.163555-3-hongxing.zhu@nxp.com
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
[kwilczynski: commit log]
Signed-off-by: Krzysztof WilczyƄski <kwilczynski@kernel.org>
[bhelgaas: commit log]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-designware.h

index d6d5fff1121c6baffb59172f57da13c81dd2cbc3..f43753bb7888dab3ed15a40383f866e477bead2c 100644 (file)
@@ -924,7 +924,7 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci)
 {
        u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
        u32 val;
-       int ret = 0;
+       int ret;
 
        /*
         * If L1SS is supported, then do not put the link into L2 as some
@@ -933,25 +933,32 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci)
        if (dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKCTL) & PCI_EXP_LNKCTL_ASPM_L1)
                return 0;
 
-       if (dw_pcie_get_ltssm(pci) <= DW_PCIE_LTSSM_DETECT_ACT)
-               return 0;
-
-       if (pci->pp.ops->pme_turn_off)
+       if (pci->pp.ops->pme_turn_off) {
                pci->pp.ops->pme_turn_off(&pci->pp);
-       else
+       } else {
                ret = dw_pcie_pme_turn_off(pci);
+               if (ret)
+                       return ret;
+       }
 
-       if (ret)
-               return ret;
-
-       ret = read_poll_timeout(dw_pcie_get_ltssm, val, val == DW_PCIE_LTSSM_L2_IDLE,
+       ret = read_poll_timeout(dw_pcie_get_ltssm, val,
+                               val == DW_PCIE_LTSSM_L2_IDLE ||
+                               val <= DW_PCIE_LTSSM_DETECT_WAIT,
                                PCIE_PME_TO_L2_TIMEOUT_US/10,
                                PCIE_PME_TO_L2_TIMEOUT_US, false, pci);
        if (ret) {
+               /* Only log message when LTSSM isn't in DETECT or POLL */
                dev_err(pci->dev, "Timeout waiting for L2 entry! LTSSM: 0x%x\n", val);
                return ret;
        }
 
+       /*
+        * Per PCIe r6.0, sec 5.3.3.2.1, software should wait at least
+        * 100ns after L2/L3 Ready before turning off refclock and
+        * main power. This is harmless when no endpoint is connected.
+        */
+       udelay(1);
+
        dw_pcie_stop_link(pci);
        if (pci->pp.ops->deinit)
                pci->pp.ops->deinit(&pci->pp);
index 1d0ec47e1986a7561a997f15e983a76b7363283c..8c0222f019d7017641e9fd9a76a8cdfa32cf2be6 100644 (file)
@@ -330,6 +330,7 @@ enum dw_pcie_ltssm {
        /* Need to align with PCIE_PORT_DEBUG0 bits 0:5 */
        DW_PCIE_LTSSM_DETECT_QUIET = 0x0,
        DW_PCIE_LTSSM_DETECT_ACT = 0x1,
+       DW_PCIE_LTSSM_DETECT_WAIT = 0x6,
        DW_PCIE_LTSSM_L0 = 0x11,
        DW_PCIE_LTSSM_L2_IDLE = 0x15,