Skip to content

Commit c2863b2

Browse files
committed
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()
2 parents c501cf9 + a115b1b commit c2863b2

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

drivers/pci/controller/pcie-rcar-ep.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,9 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
492492
pcie->dev = dev;
493493

494494
pm_runtime_enable(dev);
495-
err = pm_runtime_get_sync(dev);
495+
err = pm_runtime_resume_and_get(dev);
496496
if (err < 0) {
497-
dev_err(dev, "pm_runtime_get_sync failed\n");
497+
dev_err(dev, "pm_runtime_resume_and_get failed\n");
498498
goto err_pm_disable;
499499
}
500500

drivers/pci/controller/pcie-rcar-host.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313

1414
#include <linux/bitops.h>
1515
#include <linux/clk.h>
16+
#include <linux/clk-provider.h>
1617
#include <linux/delay.h>
1718
#include <linux/interrupt.h>
1819
#include <linux/irq.h>
1920
#include <linux/irqdomain.h>
2021
#include <linux/kernel.h>
2122
#include <linux/init.h>
23+
#include <linux/iopoll.h>
2224
#include <linux/msi.h>
2325
#include <linux/of_address.h>
2426
#include <linux/of_irq.h>
@@ -41,6 +43,21 @@ struct rcar_msi {
4143
int irq2;
4244
};
4345

46+
#ifdef CONFIG_ARM
47+
/*
48+
* Here we keep a static copy of the remapped PCIe controller address.
49+
* This is only used on aarch32 systems, all of which have one single
50+
* PCIe controller, to provide quick access to the PCIe controller in
51+
* the L1 link state fixup function, called from the ARM fault handler.
52+
*/
53+
static void __iomem *pcie_base;
54+
/*
55+
* Static copy of bus clock pointer, so we can check whether the clock
56+
* is enabled or not.
57+
*/
58+
static struct clk *pcie_bus_clk;
59+
#endif
60+
4461
/* Structure representing the PCIe interface */
4562
struct rcar_pcie_host {
4663
struct rcar_pcie pcie;
@@ -774,6 +791,12 @@ static int rcar_pcie_get_resources(struct rcar_pcie_host *host)
774791
}
775792
host->msi.irq2 = i;
776793

794+
#ifdef CONFIG_ARM
795+
/* Cache static copy for L1 link state fixup hook on aarch32 */
796+
pcie_base = pcie->base;
797+
pcie_bus_clk = host->bus_clk;
798+
#endif
799+
777800
return 0;
778801

779802
err_irq2:
@@ -1029,4 +1052,67 @@ static struct platform_driver rcar_pcie_driver = {
10291052
},
10301053
.probe = rcar_pcie_probe,
10311054
};
1055+
1056+
#ifdef CONFIG_ARM
1057+
static DEFINE_SPINLOCK(pmsr_lock);
1058+
static int rcar_pcie_aarch32_abort_handler(unsigned long addr,
1059+
unsigned int fsr, struct pt_regs *regs)
1060+
{
1061+
unsigned long flags;
1062+
u32 pmsr, val;
1063+
int ret = 0;
1064+
1065+
spin_lock_irqsave(&pmsr_lock, flags);
1066+
1067+
if (!pcie_base || !__clk_is_enabled(pcie_bus_clk)) {
1068+
ret = 1;
1069+
goto unlock_exit;
1070+
}
1071+
1072+
pmsr = readl(pcie_base + PMSR);
1073+
1074+
/*
1075+
* Test if the PCIe controller received PM_ENTER_L1 DLLP and
1076+
* the PCIe controller is not in L1 link state. If true, apply
1077+
* fix, which will put the controller into L1 link state, from
1078+
* which it can return to L0s/L0 on its own.
1079+
*/
1080+
if ((pmsr & PMEL1RX) && ((pmsr & PMSTATE) != PMSTATE_L1)) {
1081+
writel(L1IATN, pcie_base + PMCTLR);
1082+
ret = readl_poll_timeout_atomic(pcie_base + PMSR, val,
1083+
val & L1FAEG, 10, 1000);
1084+
WARN(ret, "Timeout waiting for L1 link state, ret=%d\n", ret);
1085+
writel(L1FAEG | PMEL1RX, pcie_base + PMSR);
1086+
}
1087+
1088+
unlock_exit:
1089+
spin_unlock_irqrestore(&pmsr_lock, flags);
1090+
return ret;
1091+
}
1092+
1093+
static const struct of_device_id rcar_pcie_abort_handler_of_match[] __initconst = {
1094+
{ .compatible = "renesas,pcie-r8a7779" },
1095+
{ .compatible = "renesas,pcie-r8a7790" },
1096+
{ .compatible = "renesas,pcie-r8a7791" },
1097+
{ .compatible = "renesas,pcie-rcar-gen2" },
1098+
{},
1099+
};
1100+
1101+
static int __init rcar_pcie_init(void)
1102+
{
1103+
if (of_find_matching_node(NULL, rcar_pcie_abort_handler_of_match)) {
1104+
#ifdef CONFIG_ARM_LPAE
1105+
hook_fault_code(17, rcar_pcie_aarch32_abort_handler, SIGBUS, 0,
1106+
"asynchronous external abort");
1107+
#else
1108+
hook_fault_code(22, rcar_pcie_aarch32_abort_handler, SIGBUS, 0,
1109+
"imprecise external abort");
1110+
#endif
1111+
}
1112+
1113+
return platform_driver_register(&rcar_pcie_driver);
1114+
}
1115+
device_initcall(rcar_pcie_init);
1116+
#else
10321117
builtin_platform_driver(rcar_pcie_driver);
1118+
#endif

drivers/pci/controller/pcie-rcar.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@
8585
#define LTSMDIS BIT(31)
8686
#define MACCTLR_INIT_VAL (LTSMDIS | MACCTLR_NFTS_MASK)
8787
#define PMSR 0x01105c
88+
#define L1FAEG BIT(31)
89+
#define PMEL1RX BIT(23)
90+
#define PMSTATE GENMASK(18, 16)
91+
#define PMSTATE_L1 (3 << 16)
92+
#define PMCTLR 0x011060
93+
#define L1IATN BIT(31)
94+
8895
#define MACS2R 0x011078
8996
#define MACCGSPSETR 0x011084
9097
#define SPCNGRSN BIT(31)

0 commit comments

Comments
 (0)