[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250408065221.1941928-2-hongxing.zhu@nxp.com>
Date: Tue, 8 Apr 2025 14:52:18 +0800
From: Richard Zhu <hongxing.zhu@....com>
To: jingoohan1@...il.com,
frank.li@....com,
l.stach@...gutronix.de,
lpieralisi@...nel.org,
kw@...ux.com,
manivannan.sadhasivam@...aro.org,
robh@...nel.org,
bhelgaas@...gle.com,
shawnguo@...nel.org,
s.hauer@...gutronix.de,
kernel@...gutronix.de,
festevam@...il.com
Cc: linux-pci@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org,
imx@...ts.linux.dev,
linux-kernel@...r.kernel.org,
Richard Zhu <hongxing.zhu@....com>
Subject: [PATCH v1 1/4] PCI: dwc: Add quirk to fix hang issue in L2 poll of suspend
i.MX6QP PCIe is hang in L2 poll during suspend when one endpoint device is
connected, for example the Intel e1000e network card.
Refer to Figure5-1 Link Power Management State Flow Diagram of PCI
Express Base Spec Rev6.0. L0 can be transferred to LDn directly.
It's harmless to let dw_pcie_suspend_noirq() proceed suspend after the
PME_Turn_Off is sent out, whatever the ltssm state is in L2 or L3 on
some PME_Turn_Off handshake broken platforms.
To fix this issue, add one quirk to remove the L2 entry poll and let
dw_pcie_suspend_noirq() proceed directly after PME_Turn_Off is sent out.
Signed-off-by: Richard Zhu <hongxing.zhu@....com>
---
.../pci/controller/dwc/pcie-designware-host.c | 22 ++++++++++---------
drivers/pci/controller/dwc/pcie-designware.h | 4 ++++
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index ecc33f6789e3..0817df5b8a59 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -947,7 +947,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;
+ int ret = 0;
/*
* If L1SS is supported, then do not put the link into L2 as some
@@ -964,15 +964,17 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci)
return ret;
}
- 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;
+ if (!dwc_check_quirk(pci, QUIRK_NOL2POLL_IN_PM)) {
+ 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;
+ }
}
/*
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 56aafdbcdaca..05fe654d7761 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -282,6 +282,9 @@
/* Default eDMA LLP memory size */
#define DMA_LLP_MEM_SIZE PAGE_SIZE
+#define QUIRK_NOL2POLL_IN_PM BIT(0)
+#define dwc_check_quirk(pci, val) (pci->quirk_flag & val)
+
struct dw_pcie;
struct dw_pcie_rp;
struct dw_pcie_ep;
@@ -491,6 +494,7 @@ struct dw_pcie {
const struct dw_pcie_ops *ops;
u32 version;
u32 type;
+ u32 quirk_flag;
unsigned long caps;
int num_lanes;
int max_link_speed;
--
2.37.1
Powered by blists - more mailing lists