On surprise down, LTSSM state transits from L0 -> Recovery.RcvrLock -> Recovery.RcvrSpeed -> Gen1 Recovery.RcvrLock -> Detect. Recovery.RcvrLock and Recovery.RcvrSpeed transit times are 24 msec and 48 msec respectively. So, the total time taken to transit from L0 to detect state is ~96 msec. Hence, increase the poll time to 120 msec. Disable the LTSSM state after it transits to detect to avoid LTSSM toggling between polling and detect states. tegra_pcie_dw_pme_turnoff() function is called in non-atomic context only, so use the non-atomic poll function. Signed-off-by: Vidya Sagar <vidyas@xxxxxxxxxx> --- V3: * Addressed review comments from Bjorn * Reworded the commit message V2: * None drivers/pci/controller/dwc/pcie-tegra194.c | 55 +++++++++++++--------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 69e11a74a0d7..897e2a22bcd3 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -141,7 +141,11 @@ #define APPL_DEBUG_PM_LINKST_IN_L0 0x11 #define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) #define APPL_DEBUG_LTSSM_STATE_SHIFT 3 -#define LTSSM_STATE_PRE_DETECT 5 +#define LTSSM_STATE_DETECT_QUIET 0x00 +#define LTSSM_STATE_DETECT_ACT 0x08 +#define LTSSM_STATE_PRE_DETECT_QUIET 0x28 +#define LTSSM_STATE_DETECT_WAIT 0x30 +#define LTSSM_STATE_L2_IDLE 0xa8 #define APPL_RADM_STATUS 0xE4 #define APPL_PM_XMT_TURNOFF_STATE BIT(0) @@ -210,7 +214,8 @@ #define PME_ACK_DELAY 100 /* 100 us */ #define PME_ACK_TIMEOUT 10000 /* 10 ms */ -#define LTSSM_TIMEOUT 50000 /* 50ms */ +#define LTSSM_DELAY 10000 /* 10 ms */ +#define LTSSM_TIMEOUT 120000 /* 120 ms */ #define GEN3_GEN4_EQ_PRESET_INIT 5 @@ -1663,23 +1668,22 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) data &= ~APPL_PINMUX_PEX_RST; appl_writel(pcie, data, APPL_PINMUX); + err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT), + LTSSM_DELAY, LTSSM_TIMEOUT); + if (err) + dev_info(pcie->dev, "Link didn't go to detect state\n"); + /* - * Some cards do not go to detect state even after de-asserting - * PERST#. So, de-assert LTSSM to bring link to detect state. + * Deassert LTSSM state to stop the state toggling between + * polling and detect. */ data = readl(pcie->appl_base + APPL_CTRL); data &= ~APPL_CTRL_LTSSM_EN; writel(data, pcie->appl_base + APPL_CTRL); - - err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, - data, - ((data & - APPL_DEBUG_LTSSM_STATE_MASK) >> - APPL_DEBUG_LTSSM_STATE_SHIFT) == - LTSSM_STATE_PRE_DETECT, - 1, LTSSM_TIMEOUT); - if (err) - dev_info(pcie->dev, "Link didn't go to detect state\n"); } /* * DBI registers may not be accessible after this as PLL-E would be @@ -1769,19 +1773,24 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) if (pcie->ep_state == EP_STATE_DISABLED) return; - /* Disable LTSSM */ + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE), + LTSSM_DELAY, LTSSM_TIMEOUT); + if (ret) + dev_err(pcie->dev, "LTSSM state: 0x%x timeout: %d\n", val, ret); + + /* + * Deassert LTSSM state to stop the state toggling between + * polling and detect. + */ val = appl_readl(pcie, APPL_CTRL); val &= ~APPL_CTRL_LTSSM_EN; appl_writel(pcie, val, APPL_CTRL); - ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, - ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> - APPL_DEBUG_LTSSM_STATE_SHIFT) == - LTSSM_STATE_PRE_DETECT, - 1, LTSSM_TIMEOUT); - if (ret) - dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); - reset_control_assert(pcie->core_rst); tegra_pcie_disable_phy(pcie); -- 2.17.1