>From 72706b22617da7ef8dcf1924f4c204383111401c Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 11 Apr 2014 15:22:36 +0200 Subject: [PATCH 13/13] pci: pci-mvebu: wait for a device to appear to fix clock issues With the introduction of the mvebu-soc-id mechanism in arch/arm/mach-mvebu/, the PCIe clocks can be gated during early boot, and then re-enabled later when the pci-mvebu driver gets called. However, after the clock has been enabled, it takes some time for the PCIe device to become visible: this is causing problems on some platforms where PCIe devices may not be detected at boot time due to this. To fix this, this commit introduces a simple loop that waits for a valid device to actually show up on each PCIe interface for which the link is up. It fixes a problem reported both by Gregory Clement and Neil Greatorex, which were seeing all PCIe devices detected when earlyprintk was enabled, but one of the device was missing when earlyprintk was disabled. This was due to the fact that earlyprintk was slowing down the boot sufficiently to make the problem invisible. Signed-off-by: Thomas Petazzoni Reported-by: Neil Greatorex Reported-by: Gregory CLEMENT --- drivers/pci/host/pci-mvebu.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 487c926..008d718 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -21,6 +21,7 @@ #include #include #include +#include /* * PCIe unit register offsets. @@ -162,6 +163,14 @@ static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr) mvebu_writel(port, stat, PCIE_STAT_OFF); } +static u32 mvebu_pcie_get_local_bus_nr(struct mvebu_pcie_port *port) +{ + u32 stat; + + stat = mvebu_readl(port, PCIE_STAT_OFF); + return (stat & PCIE_STAT_BUS) >> 8; +} + static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr) { u32 stat; @@ -172,6 +181,30 @@ static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr) mvebu_writel(port, stat, PCIE_STAT_OFF); } +static void mvebu_pcie_wait_dev(struct mvebu_pcie_port *port) +{ + int tries; + + for (tries = 0; tries < 1000; tries++) { + u32 vpid; + + mvebu_writel(port, + PCIE_CONF_ADDR(mvebu_pcie_get_local_bus_nr(port), + PCI_DEVFN(0, 0), PCI_VENDOR_ID), + PCIE_CONF_ADDR_OFF); + vpid = mvebu_readl(port, PCIE_CONF_DATA_OFF); + + if (vpid != 0xffffffff) + break; + + udelay(100); + } + + if (tries >= 1000) + dev_warn(&port->pcie->pdev->dev, + "timeout when looking for the PCIe device\n"); +} + /* * Setup PCIE BARs and Address Decode Wins: * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks @@ -951,6 +984,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) for_each_child_of_node(pdev->dev.of_node, child) { struct mvebu_pcie_port *port = &pcie->ports[i]; enum of_gpio_flags flags; + int linkup; if (!of_device_is_available(child)) continue; @@ -1035,8 +1069,13 @@ static int mvebu_pcie_probe(struct platform_device *pdev) continue; } + linkup = mvebu_pcie_link_up(port); + mvebu_pcie_set_local_dev_nr(port, 1); + if (linkup) + mvebu_pcie_wait_dev(port); + port->dn = child; spin_lock_init(&port->conf_lock); mvebu_sw_pci_bridge_init(port); -- 1.8.3.2