diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2023-09-14 04:54:23 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-06 01:02:55 +0300 |
| commit | 06654f62b2178ec0ea99f469be526333ccb7b3bd (patch) | |
| tree | 927df951991d2fa052f1b9df50f75d27da4ecf0a | |
| parent | 25585771d6f06c707d8b419e9bba746094204c5a (diff) | |
| download | linux-06654f62b2178ec0ea99f469be526333ccb7b3bd.tar.gz linux-06654f62b2178ec0ea99f469be526333ccb7b3bd.zip | |
PCI: bt1: Serialise link-up/speed-change exec sequence
At some very rare cases it might turn out that the speed-change is
re-enabled before the enabled by default speed-change procedure is
finished. In that case the link won't be re-trained for the higher speeds.
Fix that by introducing the strict link-up sequence: first wait for the
link to be established, then wait for the pre-enabled speed-change
procedure being finished, only after that re-enable the speed-change
procedure in order to gain the higher bus speeds.
Fixes: ba6ed462dcf4 ("PCI: dwc: Add Baikal-T1 PCIe controller support")
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-bt1.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/drivers/pci/controller/dwc/pcie-bt1.c b/drivers/pci/controller/dwc/pcie-bt1.c index 3bf549d40d91..7302490a88cb 100644 --- a/drivers/pci/controller/dwc/pcie-bt1.c +++ b/drivers/pci/controller/dwc/pcie-bt1.c @@ -297,22 +297,44 @@ static int bt1_pcie_start_link(struct dw_pcie *pci) return ret; } + ret = regmap_read_poll_timeout(btpci->sys_regs, BT1_CCU_PCIE_PMSC, val, + BT1_CCU_PCIE_LTSSM_LINKUP(val), + BT1_PCIE_LNK_DELAY_US, BT1_PCIE_LNK_TIMEOUT_US); + if (ret) { + dev_err(pci->dev, "LTSSM failed to get into L0 state\n"); + return ret; + } + + /* + * Wait for the speed change enabled by default and by the DW PCIe core + * driver to be finished. + */ + ret = read_poll_timeout(dw_pcie_readl_dbi, val, !(val & PORT_LOGIC_SPEED_CHANGE), + BT1_PCIE_LNK_DELAY_US, BT1_PCIE_LNK_TIMEOUT_US, false, + pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + if (ret) { + dev_err(pci->dev, "Initial speed change hanged up\n"); + return ret; + } + /* - * Activate direct speed change after the link is established in an - * attempt to reach a higher bus performance (up to Gen.3 - 8.0 GT/s). - * This is required at least to get 8.0 GT/s speed. + * Activate the direct speed change one more time after the link is + * established in order to reach a higher bus performance. This is + * required at least to get 8.0 GT/s speed. */ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); val |= PORT_LOGIC_SPEED_CHANGE; dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); - ret = regmap_read_poll_timeout(btpci->sys_regs, BT1_CCU_PCIE_PMSC, val, - BT1_CCU_PCIE_LTSSM_LINKUP(val), - BT1_PCIE_LNK_DELAY_US, BT1_PCIE_LNK_TIMEOUT_US); - if (ret) - dev_err(pci->dev, "LTSSM failed to get into L0 state\n"); + ret = read_poll_timeout(dw_pcie_readl_dbi, val, !(val & PORT_LOGIC_SPEED_CHANGE), + BT1_PCIE_LNK_DELAY_US, BT1_PCIE_LNK_TIMEOUT_US, false, + pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + if (ret) { + dev_err(pci->dev, "Speed change hanged up\n"); + return ret; + } - return ret; + return 0; } static void bt1_pcie_stop_link(struct dw_pcie *pci) |
