@@ -41,6 +41,15 @@ struct rcar_msi {
int irq2;
};
+/* Structure representing the PCIe interface */
+struct rcar_pcie_host {
+ struct rcar_pcie pcie;
+ struct phy *phy;
+ struct clk *bus_clk;
+ struct rcar_msi msi;
+ int (*phy_init_fn)(struct rcar_pcie_host *host);
+};
+
#ifdef CONFIG_ARM
/*
* Here we keep a static copy of the remapped PCIe controller address.
@@ -56,14 +65,34 @@ static void __iomem *pcie_base;
static struct device *pcie_dev;
#endif
-/* Structure representing the PCIe interface */
-struct rcar_pcie_host {
- struct rcar_pcie pcie;
- struct phy *phy;
- struct clk *bus_clk;
- struct rcar_msi msi;
- int (*phy_init_fn)(struct rcar_pcie_host *host);
-};
+static DEFINE_SPINLOCK(pmsr_lock);
+
+static int rcar_pcie_wakeup(struct device *pcie_dev, void __iomem *pcie_base)
+{
+ u32 pmsr, val;
+ int ret = 0;
+
+ if (!pcie_base || pm_runtime_suspended(pcie_dev))
+ return 1;
+
+ pmsr = readl(pcie_base + PMSR);
+
+ /*
+ * Test if the PCIe controller received PM_ENTER_L1 DLLP and
+ * the PCIe controller is not in L1 link state. If true, apply
+ * fix, which will put the controller into L1 link state, from
+ * which it can return to L0s/L0 on its own.
+ */
+ if ((pmsr & PMEL1RX) && ((pmsr & PMSTATE) != PMSTATE_L1)) {
+ writel(L1IATN, pcie_base + PMCTLR);
+ ret = readl_poll_timeout_atomic(pcie_base + PMSR, val,
+ val & L1FAEG, 10, 1000);
+ WARN(ret, "Timeout waiting for L1 link state, ret=%d\n", ret);
+ writel(L1FAEG | PMEL1RX, pcie_base + PMSR);
+ }
+
+ return ret;
+}
static struct rcar_pcie_host *msi_to_host(struct rcar_msi *msi)
{
@@ -85,6 +114,15 @@ static int rcar_pcie_config_access(struct rcar_pcie_host *host,
{
struct rcar_pcie *pcie = &host->pcie;
unsigned int dev, func, reg, index;
+ unsigned long flags;
+ int ret;
+
+ /* Wake the bus up in case it is in L1 state. */
+ spin_lock_irqsave(&pmsr_lock, flags);
+ ret = rcar_pcie_wakeup(pcie->dev, pcie->base);
+ spin_unlock_irqrestore(&pmsr_lock, flags);
+ if (ret)
+ return ret;
dev = PCI_SLOT(devfn);
func = PCI_FUNC(devfn);
@@ -1050,36 +1088,18 @@ static struct platform_driver rcar_pcie_driver = {
};
#ifdef CONFIG_ARM
-static DEFINE_SPINLOCK(pmsr_lock);
static int rcar_pcie_aarch32_abort_handler(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
{
unsigned long flags;
- u32 pmsr, val;
int ret = 0;
spin_lock_irqsave(&pmsr_lock, flags);
- if (!pcie_base || pm_runtime_suspended(pcie_dev)) {
- ret = 1;
+ ret = rcar_pcie_wakeup(pcie_dev, pcie_base);
+ spin_unlock_irqrestore(&pmsr_lock, flags);
+ if (ret)
goto unlock_exit;
- }
-
- pmsr = readl(pcie_base + PMSR);
-
- /*
- * Test if the PCIe controller received PM_ENTER_L1 DLLP and
- * the PCIe controller is not in L1 link state. If true, apply
- * fix, which will put the controller into L1 link state, from
- * which it can return to L0s/L0 on its own.
- */
- if ((pmsr & PMEL1RX) && ((pmsr & PMSTATE) != PMSTATE_L1)) {
- writel(L1IATN, pcie_base + PMCTLR);
- ret = readl_poll_timeout_atomic(pcie_base + PMSR, val,
- val & L1FAEG, 10, 1000);
- WARN(ret, "Timeout waiting for L1 link state, ret=%d\n", ret);
- writel(L1FAEG | PMEL1RX, pcie_base + PMSR);
- }
unlock_exit:
spin_unlock_irqrestore(&pmsr_lock, flags);