summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLucas Stach <l.stach@pengutronix.de>2016-01-25 16:50:02 -0600
committerBen Hutchings <ben@decadent.org.uk>2016-05-01 00:05:44 +0200
commit92d27c4aaca0d15bb742de785dfd57f0f68aa586 (patch)
tree362e66b7afda45a82344b1221b9cdbe510fed59a
parentf5aa19a43aaba8be755936fa2dbe93404fcec169 (diff)
downloadlinux-stable-92d27c4aaca0d15bb742de785dfd57f0f68aa586.tar.gz
linux-stable-92d27c4aaca0d15bb742de785dfd57f0f68aa586.tar.bz2
linux-stable-92d27c4aaca0d15bb742de785dfd57f0f68aa586.zip
PCI: imx6: Move link up check into imx6_pcie_wait_for_link()
commit 4d107d3b5a686b5834e533a00b73bf7b1cf59df7 upstream. imx6_pcie_link_up() previously used usleep_range() to wait for the link to come up. Since it may be called while holding the config spinlock, the sleep causes a "BUG: scheduling while atomic" error. Instead of waiting for the link to come up in imx6_pcie_link_up(), do the waiting in imx6_pcie_wait_for_link(), where we're not holding a lock and sleeping is allowed. [bhelgaas: changelog, references to bugzilla and f95d3ae77191] Link: https://bugzilla.kernel.org/show_bug.cgi?id=100031 Fixes: f95d3ae77191 ("PCI: imx6: Wait for retraining") Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> [bwh: Backported to 3.16: also update the retry loop in imx6_pcie_wait_for_link() as done upstream in commit 6cbb247e85eb ("PCI: designware: Wait for link to come up with consistent style")] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--drivers/pci/host/pci-imx6.c32
1 files changed, 24 insertions, 8 deletions
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index d54cf5f49e1c..c81ab705292a 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -315,17 +315,33 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)
static int imx6_pcie_wait_for_link(struct pcie_port *pp)
{
- int count = 200;
+ unsigned int retries;
- while (!dw_pcie_link_up(pp)) {
- usleep_range(100, 1000);
- if (--count)
- continue;
-
- return -EINVAL;
+ /*
+ * Test if the PHY reports that the link is up and also that the LTSSM
+ * training finished. There are three possible states of the link when
+ * this code is called:
+ * 1) The link is DOWN (unlikely)
+ * The link didn't come up yet for some reason. This usually means
+ * we have a real problem somewhere, if it happens with a peripheral
+ * connected. This state calls for inspection of the DEBUG registers.
+ * 2) The link is UP, but still in LTSSM training
+ * Wait for the training to finish, which should take a very short
+ * time. If the training does not finish, we have a problem and we
+ * need to inspect the DEBUG registers. If the training does finish,
+ * the link is up and operating correctly.
+ * 3) The link is UP and no longer in LTSSM training
+ * The link is up and operating correctly.
+ */
+ for (retries = 0; retries < 200; retries++) {
+ u32 reg = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
+ if ((reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) &&
+ !(reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
+ return 0;
+ usleep_range(1000, 2000);
}
- return 0;
+ return -EINVAL;
}
static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg)