mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 17:24:17 +08:00
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:
commit
c2863b217e
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user