Merge branch 'remotes/lorenzo/pci/rcar'

- Fix runtime PM imbalance in rcar_pcie_ep_probe() (Dinghao Liu)

* remotes/lorenzo/pci/rcar:
  PCI: rcar: Add L1 link state fix into data abort hook
  PCI: rcar: Fix runtime PM imbalance in rcar_pcie_ep_probe()
This commit is contained in:
Bjorn Helgaas 2021-09-02 14:56:49 -05:00
commit c2863b217e
3 changed files with 95 additions and 2 deletions

View File

@ -492,9 +492,9 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
pcie->dev = dev;
pm_runtime_enable(dev);
err = pm_runtime_get_sync(dev);
err = pm_runtime_resume_and_get(dev);
if (err < 0) {
dev_err(dev, "pm_runtime_get_sync failed\n");
dev_err(dev, "pm_runtime_resume_and_get failed\n");
goto err_pm_disable;
}

View File

@ -13,12 +13,14 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/iopoll.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@ -41,6 +43,21 @@ struct rcar_msi {
int irq2;
};
#ifdef CONFIG_ARM
/*
* Here we keep a static copy of the remapped PCIe controller address.
* This is only used on aarch32 systems, all of which have one single
* PCIe controller, to provide quick access to the PCIe controller in
* the L1 link state fixup function, called from the ARM fault handler.
*/
static void __iomem *pcie_base;
/*
* Static copy of bus clock pointer, so we can check whether the clock
* is enabled or not.
*/
static struct clk *pcie_bus_clk;
#endif
/* Structure representing the PCIe interface */
struct rcar_pcie_host {
struct rcar_pcie pcie;
@ -774,6 +791,12 @@ static int rcar_pcie_get_resources(struct rcar_pcie_host *host)
}
host->msi.irq2 = i;
#ifdef CONFIG_ARM
/* Cache static copy for L1 link state fixup hook on aarch32 */
pcie_base = pcie->base;
pcie_bus_clk = host->bus_clk;
#endif
return 0;
err_irq2:
@ -1029,4 +1052,67 @@ static struct platform_driver rcar_pcie_driver = {
},
.probe = rcar_pcie_probe,
};
#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 || !__clk_is_enabled(pcie_bus_clk)) {
ret = 1;
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);
return ret;
}
static const struct of_device_id rcar_pcie_abort_handler_of_match[] __initconst = {
{ .compatible = "renesas,pcie-r8a7779" },
{ .compatible = "renesas,pcie-r8a7790" },
{ .compatible = "renesas,pcie-r8a7791" },
{ .compatible = "renesas,pcie-rcar-gen2" },
{},
};
static int __init rcar_pcie_init(void)
{
if (of_find_matching_node(NULL, rcar_pcie_abort_handler_of_match)) {
#ifdef CONFIG_ARM_LPAE
hook_fault_code(17, rcar_pcie_aarch32_abort_handler, SIGBUS, 0,
"asynchronous external abort");
#else
hook_fault_code(22, rcar_pcie_aarch32_abort_handler, SIGBUS, 0,
"imprecise external abort");
#endif
}
return platform_driver_register(&rcar_pcie_driver);
}
device_initcall(rcar_pcie_init);
#else
builtin_platform_driver(rcar_pcie_driver);
#endif

View File

@ -85,6 +85,13 @@
#define LTSMDIS BIT(31)
#define MACCTLR_INIT_VAL (LTSMDIS | MACCTLR_NFTS_MASK)
#define PMSR 0x01105c
#define L1FAEG BIT(31)
#define PMEL1RX BIT(23)
#define PMSTATE GENMASK(18, 16)
#define PMSTATE_L1 (3 << 16)
#define PMCTLR 0x011060
#define L1IATN BIT(31)
#define MACS2R 0x011078
#define MACCGSPSETR 0x011084
#define SPCNGRSN BIT(31)