Commit 886bc5ce authored by Joao Pinto's avatar Joao Pinto Committed by Bjorn Helgaas

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: default avatarJoao Pinto <jpinto@synopsys.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Acked-by: default avatarPratyush Anand <pratyush.anand@gmail.com>
parent c1678ffc
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -108,7 +107,6 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp) ...@@ -108,7 +107,6 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp)
{ {
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
u32 reg; u32 reg;
unsigned int retries;
if (dw_pcie_link_up(pp)) { if (dw_pcie_link_up(pp)) {
dev_err(pp->dev, "link is already up\n"); dev_err(pp->dev, "link is already up\n");
...@@ -119,14 +117,7 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp) ...@@ -119,14 +117,7 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp)
reg |= LTSSM_EN; reg |= LTSSM_EN;
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
for (retries = 0; retries < 1000; retries++) { return dw_pcie_wait_for_link(pp);
if (dw_pcie_link_up(pp))
return 0;
usleep_range(10, 20);
}
dev_err(pp->dev, "link is not up\n");
return -EINVAL;
} }
static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp) static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
......
...@@ -318,7 +318,6 @@ static int exynos_pcie_establish_link(struct pcie_port *pp) ...@@ -318,7 +318,6 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
{ {
struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
u32 val; u32 val;
unsigned int retries;
if (dw_pcie_link_up(pp)) { if (dw_pcie_link_up(pp)) {
dev_err(pp->dev, "Link already up\n"); dev_err(pp->dev, "Link already up\n");
...@@ -357,13 +356,8 @@ static int exynos_pcie_establish_link(struct pcie_port *pp) ...@@ -357,13 +356,8 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
PCIE_APP_LTSSM_ENABLE); PCIE_APP_LTSSM_ENABLE);
/* check if the link is up or not */ /* check if the link is up or not */
for (retries = 0; retries < 10; retries++) { if (!dw_pcie_wait_for_link(pp))
if (dw_pcie_link_up(pp)) {
dev_info(pp->dev, "Link up\n");
return 0; return 0;
}
mdelay(100);
}
while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) { while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) {
val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED); val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED);
...@@ -372,8 +366,7 @@ static int exynos_pcie_establish_link(struct pcie_port *pp) ...@@ -372,8 +366,7 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
/* power off phy */ /* power off phy */
exynos_pcie_power_off_phy(pp); exynos_pcie_power_off_phy(pp);
dev_err(pp->dev, "PCIe Link Fail\n"); return -ETIMEDOUT;
return -EINVAL;
} }
static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp) static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp)
......
...@@ -330,19 +330,14 @@ static void imx6_pcie_init_phy(struct pcie_port *pp) ...@@ -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) static int imx6_pcie_wait_for_link(struct pcie_port *pp)
{ {
unsigned int retries; /* check if the link is up or not */
if (!dw_pcie_wait_for_link(pp))
for (retries = 0; retries < 200; retries++) {
if (dw_pcie_link_up(pp))
return 0; return 0;
usleep_range(100, 1000);
}
dev_err(pp->dev, "phy link never came up\n");
dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\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_R0),
readl(pp->dbi_base + PCIE_PHY_DEBUG_R1)); readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
return -EINVAL; return -ETIMEDOUT;
} }
static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp) static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp)
......
...@@ -97,17 +97,15 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) ...@@ -97,17 +97,15 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
return 0; return 0;
} }
ks_dw_pcie_initiate_link_train(ks_pcie);
/* check if the link is up or not */ /* check if the link is up or not */
for (retries = 0; retries < 200; retries++) { for (retries = 0; retries < 5; retries++) {
if (dw_pcie_link_up(pp))
return 0;
usleep_range(100, 1000);
ks_dw_pcie_initiate_link_train(ks_pcie); 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"); 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) static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/pci_regs.h> #include <linux/pci_regs.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/delay.h>
#include "pcie-designware.h" #include "pcie-designware.h"
...@@ -380,6 +381,24 @@ static struct msi_controller dw_pcie_msi_chip = { ...@@ -380,6 +381,24 @@ static struct msi_controller dw_pcie_msi_chip = {
.teardown_irq = dw_msi_teardown_irq, .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) int dw_pcie_link_up(struct pcie_port *pp)
{ {
if (pp->ops->link_up) if (pp->ops->link_up)
......
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
#define MAX_MSI_IRQS 32 #define MAX_MSI_IRQS 32
#define MAX_MSI_CTRLS (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 pcie_port {
struct device *dev; struct device *dev;
u8 root_bus_nr; u8 root_bus_nr;
...@@ -76,6 +81,7 @@ int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val); ...@@ -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); int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(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); int dw_pcie_link_up(struct pcie_port *pp);
void dw_pcie_setup_rc(struct pcie_port *pp); void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp); int dw_pcie_host_init(struct pcie_port *pp);
......
...@@ -116,8 +116,6 @@ static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg) ...@@ -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) static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
{ {
struct device *dev = pcie->dev;
unsigned int retries = 0;
u32 val; u32 val;
if (dw_pcie_link_up(&pcie->pp)) if (dw_pcie_link_up(&pcie->pp))
...@@ -128,15 +126,7 @@ static int qcom_pcie_establish_link(struct qcom_pcie *pcie) ...@@ -128,15 +126,7 @@ static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE; val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE;
writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL); writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL);
do { return dw_pcie_wait_for_link(&pcie->pp);
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;
} }
static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie) static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie)
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -149,7 +148,6 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp) ...@@ -149,7 +148,6 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp);
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
u32 exp_cap_off = EXP_CAP_ID_OFFSET; u32 exp_cap_off = EXP_CAP_ID_OFFSET;
unsigned int retries;
if (dw_pcie_link_up(pp)) { if (dw_pcie_link_up(pp)) {
dev_err(pp->dev, "link already up\n"); dev_err(pp->dev, "link already up\n");
...@@ -200,17 +198,7 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp) ...@@ -200,17 +198,7 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp)
| ((u32)1 << REG_TRANSLATION_ENABLE), | ((u32)1 << REG_TRANSLATION_ENABLE),
&app_reg->app_ctrl_0); &app_reg->app_ctrl_0);
/* check if the link is up or not */ return dw_pcie_wait_for_link(pp);
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;
} }
static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment