Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -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)
+3 −10
Original line number Diff line number Diff line
@@ -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");
	if (!dw_pcie_wait_for_link(pp))
		return 0;
		}
		mdelay(100);
	}

	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)
+4 −9
Original line number Diff line number Diff line
@@ -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))
	/* check if the link is up or not */
	if (!dw_pcie_wait_for_link(pp))
		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",
		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)
+4 −6
Original line number Diff line number Diff line
@@ -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)
+19 −0
Original line number Diff line number Diff line
@@ -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)
Loading