Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: designware: Add generic dw_pcie_wait_for_link()

Several DesignWare-based drivers (dra7xx, exynos, imx6, keystone, qcom, and
spear13xx) had similar loops waiting for the link to come up.

Add a generic dw_pcie_wait_for_link() for use by all these drivers so the
waiting is done consistently, e.g., always using usleep_range() rather than
mdelay() and using similar timeouts and retry counts.

Note that this changes the Keystone link training/wait for link strategy,
so we initiate link training, then wait longer for the link to come up
before re-initiating link training.

[bhelgaas: changelog, split into its own patch, update pci-keystone.c, pcie-qcom.c]
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Pratyush Anand <pratyush.anand@gmail.com>

authored by

Joao Pinto and committed by
Bjorn Helgaas
886bc5ce c1678ffc

+39 -59
+1 -10
drivers/pci/host/pci-dra7xx.c
··· 10 10 * published by the Free Software Foundation. 11 11 */ 12 12 13 - #include <linux/delay.h> 14 13 #include <linux/err.h> 15 14 #include <linux/interrupt.h> 16 15 #include <linux/irq.h> ··· 107 108 { 108 109 struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); 109 110 u32 reg; 110 - unsigned int retries; 111 111 112 112 if (dw_pcie_link_up(pp)) { 113 113 dev_err(pp->dev, "link is already up\n"); ··· 117 119 reg |= LTSSM_EN; 118 120 dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); 119 121 120 - for (retries = 0; retries < 1000; retries++) { 121 - if (dw_pcie_link_up(pp)) 122 - return 0; 123 - usleep_range(10, 20); 124 - } 125 - 126 - dev_err(pp->dev, "link is not up\n"); 127 - return -EINVAL; 122 + return dw_pcie_wait_for_link(pp); 128 123 } 129 124 130 125 static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
+3 -10
drivers/pci/host/pci-exynos.c
··· 318 318 { 319 319 struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); 320 320 u32 val; 321 - unsigned int retries; 322 321 323 322 if (dw_pcie_link_up(pp)) { 324 323 dev_err(pp->dev, "Link already up\n"); ··· 356 357 PCIE_APP_LTSSM_ENABLE); 357 358 358 359 /* check if the link is up or not */ 359 - for (retries = 0; retries < 10; retries++) { 360 - if (dw_pcie_link_up(pp)) { 361 - dev_info(pp->dev, "Link up\n"); 362 - return 0; 363 - } 364 - mdelay(100); 365 - } 360 + if (!dw_pcie_wait_for_link(pp)) 361 + return 0; 366 362 367 363 while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) { 368 364 val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED); ··· 366 372 /* power off phy */ 367 373 exynos_pcie_power_off_phy(pp); 368 374 369 - dev_err(pp->dev, "PCIe Link Fail\n"); 370 - return -EINVAL; 375 + return -ETIMEDOUT; 371 376 } 372 377 373 378 static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp)
+4 -9
drivers/pci/host/pci-imx6.c
··· 330 330 331 331 static int imx6_pcie_wait_for_link(struct pcie_port *pp) 332 332 { 333 - unsigned int retries; 333 + /* check if the link is up or not */ 334 + if (!dw_pcie_wait_for_link(pp)) 335 + return 0; 334 336 335 - for (retries = 0; retries < 200; retries++) { 336 - if (dw_pcie_link_up(pp)) 337 - return 0; 338 - usleep_range(100, 1000); 339 - } 340 - 341 - dev_err(pp->dev, "phy link never came up\n"); 342 337 dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", 343 338 readl(pp->dbi_base + PCIE_PHY_DEBUG_R0), 344 339 readl(pp->dbi_base + PCIE_PHY_DEBUG_R1)); 345 - return -EINVAL; 340 + return -ETIMEDOUT; 346 341 } 347 342 348 343 static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp)
+4 -6
drivers/pci/host/pci-keystone.c
··· 97 97 return 0; 98 98 } 99 99 100 - ks_dw_pcie_initiate_link_train(ks_pcie); 101 100 /* check if the link is up or not */ 102 - for (retries = 0; retries < 200; retries++) { 103 - if (dw_pcie_link_up(pp)) 104 - return 0; 105 - usleep_range(100, 1000); 101 + for (retries = 0; retries < 5; retries++) { 106 102 ks_dw_pcie_initiate_link_train(ks_pcie); 103 + if (!dw_pcie_wait_for_link(pp)) 104 + return 0; 107 105 } 108 106 109 107 dev_err(pp->dev, "phy link never came up\n"); 110 - return -EINVAL; 108 + return -ETIMEDOUT; 111 109 } 112 110 113 111 static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
+19
drivers/pci/host/pcie-designware.c
··· 22 22 #include <linux/pci_regs.h> 23 23 #include <linux/platform_device.h> 24 24 #include <linux/types.h> 25 + #include <linux/delay.h> 25 26 26 27 #include "pcie-designware.h" 27 28 ··· 380 379 .setup_irqs = dw_msi_setup_irqs, 381 380 .teardown_irq = dw_msi_teardown_irq, 382 381 }; 382 + 383 + int dw_pcie_wait_for_link(struct pcie_port *pp) 384 + { 385 + int retries; 386 + 387 + /* check if the link is up or not */ 388 + for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) { 389 + if (dw_pcie_link_up(pp)) { 390 + dev_info(pp->dev, "link up\n"); 391 + return 0; 392 + } 393 + usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX); 394 + } 395 + 396 + dev_err(pp->dev, "phy link never came up\n"); 397 + 398 + return -ETIMEDOUT; 399 + } 383 400 384 401 int dw_pcie_link_up(struct pcie_port *pp) 385 402 {
+6
drivers/pci/host/pcie-designware.h
··· 22 22 #define MAX_MSI_IRQS 32 23 23 #define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32) 24 24 25 + /* Parameters for the waiting for link up routine */ 26 + #define LINK_WAIT_MAX_RETRIES 10 27 + #define LINK_WAIT_USLEEP_MIN 90000 28 + #define LINK_WAIT_USLEEP_MAX 100000 29 + 25 30 struct pcie_port { 26 31 struct device *dev; 27 32 u8 root_bus_nr; ··· 81 76 int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val); 82 77 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); 83 78 void dw_pcie_msi_init(struct pcie_port *pp); 79 + int dw_pcie_wait_for_link(struct pcie_port *pp); 84 80 int dw_pcie_link_up(struct pcie_port *pp); 85 81 void dw_pcie_setup_rc(struct pcie_port *pp); 86 82 int dw_pcie_host_init(struct pcie_port *pp);
+1 -11
drivers/pci/host/pcie-qcom.c
··· 116 116 117 117 static int qcom_pcie_establish_link(struct qcom_pcie *pcie) 118 118 { 119 - struct device *dev = pcie->dev; 120 - unsigned int retries = 0; 121 119 u32 val; 122 120 123 121 if (dw_pcie_link_up(&pcie->pp)) ··· 126 128 val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE; 127 129 writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL); 128 130 129 - do { 130 - if (dw_pcie_link_up(&pcie->pp)) 131 - return 0; 132 - usleep_range(250, 1000); 133 - } while (retries < 200); 134 - 135 - dev_warn(dev, "phy link never came up\n"); 136 - 137 - return -ETIMEDOUT; 131 + return dw_pcie_wait_for_link(&pcie->pp); 138 132 } 139 133 140 134 static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie)
+1 -13
drivers/pci/host/pcie-spear13xx.c
··· 13 13 */ 14 14 15 15 #include <linux/clk.h> 16 - #include <linux/delay.h> 17 16 #include <linux/interrupt.h> 18 17 #include <linux/kernel.h> 19 18 #include <linux/module.h> ··· 148 149 struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); 149 150 struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; 150 151 u32 exp_cap_off = EXP_CAP_ID_OFFSET; 151 - unsigned int retries; 152 152 153 153 if (dw_pcie_link_up(pp)) { 154 154 dev_err(pp->dev, "link already up\n"); ··· 198 200 | ((u32)1 << REG_TRANSLATION_ENABLE), 199 201 &app_reg->app_ctrl_0); 200 202 201 - /* check if the link is up or not */ 202 - for (retries = 0; retries < 10; retries++) { 203 - if (dw_pcie_link_up(pp)) { 204 - dev_info(pp->dev, "link up\n"); 205 - return 0; 206 - } 207 - mdelay(100); 208 - } 209 - 210 - dev_err(pp->dev, "link Fail\n"); 211 - return -EINVAL; 203 + return dw_pcie_wait_for_link(pp); 212 204 } 213 205 214 206 static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)