PCI: designware: Add generic dw_pcie_wait_for_link()
authorJoao Pinto <Joao.Pinto@synopsys.com>
Thu, 10 Mar 2016 20:44:35 +0000 (14:44 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 15 Mar 2016 13:50:45 +0000 (08:50 -0500)
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>
drivers/pci/host/pci-dra7xx.c
drivers/pci/host/pci-exynos.c
drivers/pci/host/pci-imx6.c
drivers/pci/host/pci-keystone.c
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-designware.h
drivers/pci/host/pcie-qcom.c
drivers/pci/host/pcie-spear13xx.c

index 923607bdabc5c63ef940453f3ffe42180b29b02b..2ca3a1f30ebf2770f1db370955c2c11f33245001 100644 (file)
@@ -10,7 +10,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -108,7 +107,6 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp)
 {
        struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
        u32 reg;
-       unsigned int retries;
 
        if (dw_pcie_link_up(pp)) {
                dev_err(pp->dev, "link is already up\n");
@@ -119,14 +117,7 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp)
        reg |= LTSSM_EN;
        dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
 
-       for (retries = 0; retries < 1000; retries++) {
-               if (dw_pcie_link_up(pp))
-                       return 0;
-               usleep_range(10, 20);
-       }
-
-       dev_err(pp->dev, "link is not up\n");
-       return -EINVAL;
+       return dw_pcie_wait_for_link(pp);
 }
 
 static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
index d997d22d4231da6de08cab29dd101d699dbb4fe0..219976103efc5b67e7c31df52c9102f1582a67e1 100644 (file)
@@ -318,7 +318,6 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
 {
        struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
        u32 val;
-       unsigned int retries;
 
        if (dw_pcie_link_up(pp)) {
                dev_err(pp->dev, "Link already up\n");
@@ -357,13 +356,8 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
                          PCIE_APP_LTSSM_ENABLE);
 
        /* check if the link is up or not */
-       for (retries = 0; retries < 10; retries++) {
-               if (dw_pcie_link_up(pp)) {
-                       dev_info(pp->dev, "Link up\n");
-                       return 0;
-               }
-               mdelay(100);
-       }
+       if (!dw_pcie_wait_for_link(pp))
+               return 0;
 
        while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) {
                val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED);
@@ -372,8 +366,7 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
        /* power off phy */
        exynos_pcie_power_off_phy(pp);
 
-       dev_err(pp->dev, "PCIe Link Fail\n");
-       return -EINVAL;
+       return -ETIMEDOUT;
 }
 
 static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp)
index fe600964fa50177bc17b28627568268608896010..6c35d867399f8a82b12045e73f382684fc9f174f 100644 (file)
@@ -330,19 +330,14 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)
 
 static int imx6_pcie_wait_for_link(struct pcie_port *pp)
 {
-       unsigned int retries;
-
-       for (retries = 0; retries < 200; retries++) {
-               if (dw_pcie_link_up(pp))
-                       return 0;
-               usleep_range(100, 1000);
-       }
+       /* check if the link is up or not */
+       if (!dw_pcie_wait_for_link(pp))
+               return 0;
 
-       dev_err(pp->dev, "phy link never came up\n");
        dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
                readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
                readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
-       return -EINVAL;
+       return -ETIMEDOUT;
 }
 
 static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp)
index 0aa81bd3de12d8eca876851e6f019a87f9b88f64..9a91487d6ecb1f663582de582f9a9ba37ac8df52 100644 (file)
@@ -97,17 +97,15 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
                return 0;
        }
 
-       ks_dw_pcie_initiate_link_train(ks_pcie);
        /* check if the link is up or not */
-       for (retries = 0; retries < 200; retries++) {
-               if (dw_pcie_link_up(pp))
-                       return 0;
-               usleep_range(100, 1000);
+       for (retries = 0; retries < 5; retries++) {
                ks_dw_pcie_initiate_link_train(ks_pcie);
+               if (!dw_pcie_wait_for_link(pp))
+                       return 0;
        }
 
        dev_err(pp->dev, "phy link never came up\n");
-       return -EINVAL;
+       return -ETIMEDOUT;
 }
 
 static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
index f85f10d220490308be8413faf9c69aeca26c9c1e..e4fb44295d61cd10f7d0383dcac7b7118e6fbfdd 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pci_regs.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
+#include <linux/delay.h>
 
 #include "pcie-designware.h"
 
@@ -380,6 +381,24 @@ static struct msi_controller dw_pcie_msi_chip = {
        .teardown_irq = dw_msi_teardown_irq,
 };
 
+int dw_pcie_wait_for_link(struct pcie_port *pp)
+{
+       int retries;
+
+       /* check if the link is up or not */
+       for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+               if (dw_pcie_link_up(pp)) {
+                       dev_info(pp->dev, "link up\n");
+                       return 0;
+               }
+               usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+       }
+
+       dev_err(pp->dev, "phy link never came up\n");
+
+       return -ETIMEDOUT;
+}
+
 int dw_pcie_link_up(struct pcie_port *pp)
 {
        if (pp->ops->link_up)
index 2356d29e8527e71062d4fd5addb9f0ac55652b46..f437f9b5be04dd73174aec81afb7d41ff56fac14 100644 (file)
 #define MAX_MSI_IRQS                   32
 #define MAX_MSI_CTRLS                  (MAX_MSI_IRQS / 32)
 
+/* Parameters for the waiting for link up routine */
+#define LINK_WAIT_MAX_RETRIES          10
+#define LINK_WAIT_USLEEP_MIN           90000
+#define LINK_WAIT_USLEEP_MAX           100000
+
 struct pcie_port {
        struct device           *dev;
        u8                      root_bus_nr;
@@ -76,6 +81,7 @@ int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val);
 int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 void dw_pcie_msi_init(struct pcie_port *pp);
+int dw_pcie_wait_for_link(struct pcie_port *pp);
 int dw_pcie_link_up(struct pcie_port *pp);
 void dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
index e845fba19632d8518cb6af9a622f301668f5aa0c..f2f90c50f75d7f496f67e38495727826feed951f 100644 (file)
@@ -116,8 +116,6 @@ static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg)
 
 static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
 {
-       struct device *dev = pcie->dev;
-       unsigned int retries = 0;
        u32 val;
 
        if (dw_pcie_link_up(&pcie->pp))
@@ -128,15 +126,7 @@ static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
        val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE;
        writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL);
 
-       do {
-               if (dw_pcie_link_up(&pcie->pp))
-                       return 0;
-               usleep_range(250, 1000);
-       } while (retries < 200);
-
-       dev_warn(dev, "phy link never came up\n");
-
-       return -ETIMEDOUT;
+       return dw_pcie_wait_for_link(&pcie->pp);
 }
 
 static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie)
index a6cd8233e8c08c8fee6e1df3a1a7d40fdc2250a8..a4060b85ab23b6bcd41222ffc387d1626a3b0185 100644 (file)
@@ -13,7 +13,6 @@
  */
 
 #include <linux/clk.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -149,7 +148,6 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
        struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp);
        struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
        u32 exp_cap_off = EXP_CAP_ID_OFFSET;
-       unsigned int retries;
 
        if (dw_pcie_link_up(pp)) {
                dev_err(pp->dev, "link already up\n");
@@ -200,17 +198,7 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
                        | ((u32)1 << REG_TRANSLATION_ENABLE),
                        &app_reg->app_ctrl_0);
 
-       /* check if the link is up or not */
-       for (retries = 0; retries < 10; retries++) {
-               if (dw_pcie_link_up(pp)) {
-                       dev_info(pp->dev, "link up\n");
-                       return 0;
-               }
-               mdelay(100);
-       }
-
-       dev_err(pp->dev, "link Fail\n");
-       return -EINVAL;
+       return dw_pcie_wait_for_link(pp);
 }
 
 static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)