Skip to content

Commit a3f00f2

Browse files
jamesequinlanbjorn-helgaas
authored andcommitted
PCI: brcmstb: Add a way to indicate if PCIe bridge is active
In a future commit, a new handler will be introduced that in part does reads and writes to some of the PCIe registers. When this handler is invoked, it is paramount that it does not do these register accesses when the PCIe bridge is inactive, as this will cause CPU abort errors. To solve this we keep a spinlock that guards a variable which indicates whether the bridge is on or off. When the bridge is on, access of the PCIe HW registers may proceed. Since there are multiple ways to reset the bridge, we introduce a general function to obtain the spinlock, call the specific function that is used for the specific SoC, sets the bridge active indicator variable, and releases the spinlock. Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com> Link: https://patch.msgid.link/20251029193616.3670003-2-james.quinlan@broadcom.com
1 parent 9583f9d commit a3f00f2

1 file changed

Lines changed: 35 additions & 5 deletions

File tree

drivers/pci/controller/pcie-brcmstb.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/reset.h>
3131
#include <linux/sizes.h>
3232
#include <linux/slab.h>
33+
#include <linux/spinlock.h>
3334
#include <linux/string.h>
3435
#include <linux/types.h>
3536

@@ -258,6 +259,7 @@ struct pcie_cfg_data {
258259
int (*perst_set)(struct brcm_pcie *pcie, u32 val);
259260
int (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
260261
int (*post_setup)(struct brcm_pcie *pcie);
262+
bool has_err_report;
261263
};
262264

263265
struct subdev_regulators {
@@ -302,13 +304,33 @@ struct brcm_pcie {
302304
struct subdev_regulators *sr;
303305
bool ep_wakeup_capable;
304306
const struct pcie_cfg_data *cfg;
307+
bool bridge_in_reset;
308+
spinlock_t bridge_lock;
305309
};
306310

307311
static inline bool is_bmips(const struct brcm_pcie *pcie)
308312
{
309313
return pcie->cfg->soc_base == BCM7435 || pcie->cfg->soc_base == BCM7425;
310314
}
311315

316+
static int brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val)
317+
{
318+
unsigned long flags;
319+
int ret;
320+
321+
if (pcie->cfg->has_err_report)
322+
spin_lock_irqsave(&pcie->bridge_lock, flags);
323+
324+
ret = pcie->cfg->bridge_sw_init_set(pcie, val);
325+
/* If we fail, assume the bridge is in reset (off) */
326+
pcie->bridge_in_reset = ret ? true : val;
327+
328+
if (pcie->cfg->has_err_report)
329+
spin_unlock_irqrestore(&pcie->bridge_lock, flags);
330+
331+
return ret;
332+
}
333+
312334
/*
313335
* This is to convert the size of the inbound "BAR" region to the
314336
* non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE
@@ -1080,7 +1102,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
10801102
int memc, ret;
10811103

10821104
/* Reset the bridge */
1083-
ret = pcie->cfg->bridge_sw_init_set(pcie, 1);
1105+
ret = brcm_pcie_bridge_sw_init_set(pcie, 1);
10841106
if (ret)
10851107
return ret;
10861108

@@ -1096,7 +1118,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
10961118
usleep_range(100, 200);
10971119

10981120
/* Take the bridge out of reset */
1099-
ret = pcie->cfg->bridge_sw_init_set(pcie, 0);
1121+
ret = brcm_pcie_bridge_sw_init_set(pcie, 0);
11001122
if (ret)
11011123
return ret;
11021124

@@ -1561,7 +1583,7 @@ static int brcm_pcie_turn_off(struct brcm_pcie *pcie)
15611583

15621584
if (!(pcie->cfg->quirks & CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN))
15631585
/* Shutdown PCIe bridge */
1564-
ret = pcie->cfg->bridge_sw_init_set(pcie, 1);
1586+
ret = brcm_pcie_bridge_sw_init_set(pcie, 1);
15651587

15661588
return ret;
15671589
}
@@ -1649,7 +1671,9 @@ static int brcm_pcie_resume_noirq(struct device *dev)
16491671
goto err_reset;
16501672

16511673
/* Take bridge out of reset so we can access the SERDES reg */
1652-
pcie->cfg->bridge_sw_init_set(pcie, 0);
1674+
ret = brcm_pcie_bridge_sw_init_set(pcie, 0);
1675+
if (ret)
1676+
goto err_reset;
16531677

16541678
/* SERDES_IDDQ = 0 */
16551679
tmp = readl(base + HARD_DEBUG(pcie));
@@ -1917,7 +1941,10 @@ static int brcm_pcie_probe(struct platform_device *pdev)
19171941
if (ret)
19181942
return dev_err_probe(&pdev->dev, ret, "could not enable clock\n");
19191943

1920-
pcie->cfg->bridge_sw_init_set(pcie, 0);
1944+
ret = brcm_pcie_bridge_sw_init_set(pcie, 0);
1945+
if (ret)
1946+
return dev_err_probe(&pdev->dev, ret,
1947+
"could not de-assert bridge reset\n");
19211948

19221949
if (pcie->swinit_reset) {
19231950
ret = reset_control_assert(pcie->swinit_reset);
@@ -1992,6 +2019,9 @@ static int brcm_pcie_probe(struct platform_device *pdev)
19922019
return ret;
19932020
}
19942021

2022+
if (pcie->cfg->has_err_report)
2023+
spin_lock_init(&pcie->bridge_lock);
2024+
19952025
return 0;
19962026

19972027
fail:

0 commit comments

Comments
 (0)