summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2023-09-14 04:54:23 +0300
committerSerge Semin <fancer.lancer@gmail.com>2026-08-06 01:02:55 +0300
commit06654f62b2178ec0ea99f469be526333ccb7b3bd (patch)
tree927df951991d2fa052f1b9df50f75d27da4ecf0a
parent25585771d6f06c707d8b419e9bba746094204c5a (diff)
downloadlinux-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.c40
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)