* [PATCH 0/3] PCI: dwc: Cache PCIe capability offset and simplify drivers
@ 2026-05-09 13:51 Hans Zhang
2026-05-09 13:51 ` [PATCH 1/3] PCI: dwc: Add pcie_cap field and helper in designware header Hans Zhang
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Hans Zhang @ 2026-05-09 13:51 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: mx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
The DWC PCIe core and its many platform drivers repeatedly call
dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) to obtain the offset of the
PCI Express Capability structure. This is wasteful and makes the code
verbose. And some even search for the PCI_CAP_ID_EXP offset value within
the suspend/resume functions.
Add a cached pcie_cap field in struct dw_pcie and a helper
dw_pcie_get_pcie_cap() to initialize it once at probe time. Then replace
all explicit capability searches with the cached value across the
entire dwc subtree.
Hans Zhang (3):
PCI: dwc: Add pcie_cap field and helper in designware header
PCI: dwc: Use cached PCIe capability offset in core
PCI: dwc: Simplify platform drivers using cached capability offset
drivers/pci/controller/dwc/pci-imx6.c | 6 +--
.../pci/controller/dwc/pci-layerscape-ep.c | 4 +-
drivers/pci/controller/dwc/pci-meson.c | 4 +-
.../pci/controller/dwc/pcie-designware-ep.c | 4 +-
.../pci/controller/dwc/pcie-designware-host.c | 4 +-
drivers/pci/controller/dwc/pcie-designware.c | 16 +++---
drivers/pci/controller/dwc/pcie-designware.h | 17 +++++++
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 15 +++---
drivers/pci/controller/dwc/pcie-eswin.c | 3 +-
drivers/pci/controller/dwc/pcie-fu740.c | 2 +-
drivers/pci/controller/dwc/pcie-intel-gw.c | 2 +-
drivers/pci/controller/dwc/pcie-qcom-ep.c | 11 ++--
drivers/pci/controller/dwc/pcie-qcom.c | 24 ++++-----
drivers/pci/controller/dwc/pcie-sophgo.c | 8 ++-
drivers/pci/controller/dwc/pcie-spacemit-k1.c | 5 +-
drivers/pci/controller/dwc/pcie-spear13xx.c | 6 +--
drivers/pci/controller/dwc/pcie-tegra194.c | 51 +++++++------------
17 files changed, 85 insertions(+), 97 deletions(-)
base-commit: 70390501d1944d4e5b8f7352be180fceb3a44132
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/3] PCI: dwc: Add pcie_cap field and helper in designware header
2026-05-09 13:51 [PATCH 0/3] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
@ 2026-05-09 13:51 ` Hans Zhang
2026-05-09 13:51 ` [PATCH 2/3] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
2026-05-09 13:51 ` [PATCH 3/3] PCI: dwc: Simplify platform drivers using cached capability offset Hans Zhang
2 siblings, 0 replies; 6+ messages in thread
From: Hans Zhang @ 2026-05-09 13:51 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: mx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
Add a pcie_cap field to struct dw_pcie to store the offset of the
PCI Express Capability structure. Provide a helper dw_pcie_get_pcie_cap()
which performs the capability search on first call and caches the result.
This is a preparatory step for replacing repetitive capability searches
in both core and platform drivers.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-designware.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 3e69ef60165b..4baf7eb072eb 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -568,6 +568,8 @@ struct dw_pcie {
* use_parent_dt_ranges to true to avoid this warning.
*/
bool use_parent_dt_ranges;
+
+ u8 pcie_cap; /* PCIe capability offset */
};
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
@@ -805,6 +807,21 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
dw_pcie_writel_dbi(pci, reg, val);
}
+/**
+ * dw_pcie_get_pcie_cap() - Return cached PCIe Capability offset
+ * @pci: DWC instance
+ *
+ * Finds and caches the offset of PCI_CAP_ID_EXP on first call.
+ * Returns 0 if the capability is not present.
+ */
+static inline u8 dw_pcie_get_pcie_cap(struct dw_pcie *pci)
+{
+ if (!pci->pcie_cap)
+ pci->pcie_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+
+ return pci->pcie_cap;
+}
+
static inline int dw_pcie_start_link(struct dw_pcie *pci)
{
if (pci->ops && pci->ops->start_link)
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3] PCI: dwc: Use cached PCIe capability offset in core
2026-05-09 13:51 [PATCH 0/3] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
2026-05-09 13:51 ` [PATCH 1/3] PCI: dwc: Add pcie_cap field and helper in designware header Hans Zhang
@ 2026-05-09 13:51 ` Hans Zhang
2026-05-09 15:07 ` sashiko-bot
2026-05-09 13:51 ` [PATCH 3/3] PCI: dwc: Simplify platform drivers using cached capability offset Hans Zhang
2 siblings, 1 reply; 6+ messages in thread
From: Hans Zhang @ 2026-05-09 13:51 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: mx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
Modify the DWC core functions to use the cached pcie_cap offset instead
of calling dw_pcie_find_capability() each time.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-designware-ep.c | 4 +++-
.../pci/controller/dwc/pcie-designware-host.c | 4 +++-
drivers/pci/controller/dwc/pcie-designware.c | 16 ++++++----------
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index d4dc3b24da60..fdcb9012058d 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -1128,7 +1128,7 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci)
* to all other functions as well.
*/
if (funcs > 1) {
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = dw_pcie_get_pcie_cap(pci);
func0_lnkcap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
func0_lnkcap = FIELD_GET(PCI_EXP_LNKCAP_MLW |
PCI_EXP_LNKCAP_SLS, func0_lnkcap);
@@ -1390,6 +1390,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
ep->msi_msg_addr = 0;
ep->msi_map_size = 0;
+ dw_pcie_get_pcie_cap(pci);
+
epc = devm_pci_epc_create(dev, &epc_ops);
if (IS_ERR(epc)) {
dev_err(dev, "Failed to create epc device\n");
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index c9517a348836..7b3ba83ed616 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -575,6 +575,8 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
raw_spin_lock_init(&pp->lock);
+ dw_pcie_get_pcie_cap(pci);
+
bridge = devm_pci_alloc_host_bridge(dev, 0);
if (!bridge)
return -ENOMEM;
@@ -1218,7 +1220,7 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci)
int dw_pcie_suspend_noirq(struct dw_pcie *pci)
{
- u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = pci->pcie_cap;
int ret = 0;
u32 val;
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index c11cf61b8319..db62b93c6255 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -761,7 +761,7 @@ const char *dw_pcie_ltssm_status_string(enum dw_pcie_ltssm ltssm)
*/
int dw_pcie_wait_for_link(struct dw_pcie *pci)
{
- u32 offset, val, ltssm;
+ u32 val, ltssm;
int retries;
/* Check if the link is up or not */
@@ -807,8 +807,7 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
if (pci->max_link_speed > 2)
msleep(PCIE_RESET_CONFIG_WAIT_MS);
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
- val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
+ val = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
@@ -844,7 +843,7 @@ EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
static void dw_pcie_link_set_max_speed(struct dw_pcie *pci)
{
u32 cap, ctrl2, link_speed;
- u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = pci->pcie_cap;
cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
@@ -890,8 +889,7 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci)
int dw_pcie_link_get_max_link_width(struct dw_pcie *pci)
{
- u8 cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
- u32 lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
+ u32 lnkcap = dw_pcie_readl_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCAP);
return FIELD_GET(PCI_EXP_LNKCAP_MLW, lnkcap);
}
@@ -899,7 +897,6 @@ int dw_pcie_link_get_max_link_width(struct dw_pcie *pci)
static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
{
u32 lnkcap, lwsc, plc;
- u8 cap;
if (!num_lanes)
return;
@@ -936,11 +933,10 @@ static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, plc);
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, lwsc);
- cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
- lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
+ lnkcap = dw_pcie_readl_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCAP);
lnkcap &= ~PCI_EXP_LNKCAP_MLW;
lnkcap |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, num_lanes);
- dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
+ dw_pcie_writel_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCAP, lnkcap);
}
void dw_pcie_iatu_detect(struct dw_pcie *pci)
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] PCI: dwc: Simplify platform drivers using cached capability offset
2026-05-09 13:51 [PATCH 0/3] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
2026-05-09 13:51 ` [PATCH 1/3] PCI: dwc: Add pcie_cap field and helper in designware header Hans Zhang
2026-05-09 13:51 ` [PATCH 2/3] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
@ 2026-05-09 13:51 ` Hans Zhang
2026-05-09 15:55 ` sashiko-bot
2 siblings, 1 reply; 6+ messages in thread
From: Hans Zhang @ 2026-05-09 13:51 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: mx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
Replace explicit dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) calls
with the cached pci->pcie_cap in all DWC-based platform drivers:
- i.MX6, Layerscape EP, Meson
- Rockchip (also remove redundant NULL check and fix typo)
- Eswin, Fu740
- Intel Gateway, Qualcomm EP, Qualcomm RC
- Sophgo, Spacemit-k1, Spear13xx
- Tegra194 (remove private pcie_cap_base)
For drivers that need the offset before the core caches it (e.g.,
ls_pcie_ep_probe), use dw_pcie_get_pcie_cap() to ensure caching.
Adjust variable types from u16 to u8 where appropriate.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pci-imx6.c | 6 +--
.../pci/controller/dwc/pci-layerscape-ep.c | 4 +-
drivers/pci/controller/dwc/pci-meson.c | 4 +-
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 15 +++---
drivers/pci/controller/dwc/pcie-eswin.c | 3 +-
drivers/pci/controller/dwc/pcie-fu740.c | 2 +-
drivers/pci/controller/dwc/pcie-intel-gw.c | 2 +-
drivers/pci/controller/dwc/pcie-qcom-ep.c | 11 ++--
drivers/pci/controller/dwc/pcie-qcom.c | 24 ++++-----
drivers/pci/controller/dwc/pcie-sophgo.c | 8 ++-
drivers/pci/controller/dwc/pcie-spacemit-k1.c | 5 +-
drivers/pci/controller/dwc/pcie-spear13xx.c | 6 +--
drivers/pci/controller/dwc/pcie-tegra194.c | 51 +++++++------------
13 files changed, 56 insertions(+), 85 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index e35044cc5218..dc464b460fc1 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -936,10 +936,10 @@ static void imx_pcie_ltssm_enable(struct device *dev)
{
struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
const struct imx_pcie_drvdata *drvdata = imx_pcie->drvdata;
- u8 offset = dw_pcie_find_capability(imx_pcie->pci, PCI_CAP_ID_EXP);
+ struct dw_pcie *pci = imx_pcie->pci;
u32 tmp;
- tmp = dw_pcie_readl_dbi(imx_pcie->pci, offset + PCI_EXP_LNKCAP);
+ tmp = dw_pcie_readl_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCAP);
phy_set_speed(imx_pcie->phy, FIELD_GET(PCI_EXP_LNKCAP_SLS, tmp));
if (drvdata->ltssm_mask)
regmap_update_bits(imx_pcie->iomuxc_gpr, drvdata->ltssm_off, drvdata->ltssm_mask,
@@ -965,7 +965,7 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
{
struct imx_pcie *imx_pcie = to_imx_pcie(pci);
struct device *dev = pci->dev;
- u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = pci->pcie_cap;
u32 tmp;
int ret;
diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
index 8936975ff104..fdb89ae13e4a 100644
--- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
+++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
@@ -84,7 +84,7 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
if (val & PEX_PF0_PME_MES_DR_LUD) {
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = dw_pcie_get_pcie_cap(pci);
/*
* The values of the Maximum Link Width and Supported Link
@@ -266,7 +266,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pcie);
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = dw_pcie_get_pcie_cap(pci);
pcie->lnkcap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
ret = dw_pcie_ep_init(&pci->ep);
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
index 0694084f612b..e8750178fbb0 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -276,7 +276,7 @@ static void meson_set_max_payload(struct meson_pcie *mp, int size)
{
struct dw_pcie *pci = &mp->pci;
u32 val;
- u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = pci->pcie_cap;
int max_payload_size = meson_size_to_payload(mp, size);
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
@@ -292,7 +292,7 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
{
struct dw_pcie *pci = &mp->pci;
u32 val;
- u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = pci->pcie_cap;
int max_rd_req_size = meson_size_to_payload(mp, size);
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 731d93663cca..9acdc18a573e 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -366,17 +366,14 @@ static void rockchip_pcie_configure_l1ss(struct dw_pcie *pci)
static void rockchip_pcie_enable_l0s(struct dw_pcie *pci)
{
- u32 cap, lnkcap;
+ u32 lnkcap;
/* Enable L0S capability for all SoCs */
- cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
- if (cap) {
- lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
- lnkcap |= PCI_EXP_LNKCAP_ASPM_L0S;
- dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
- dw_pcie_dbi_ro_wr_dis(pci);
- }
+ lnkcap = dw_pcie_readl_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCAP);
+ lnkcap |= PCI_EXP_LNKCAP_ASPM_L0S;
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writel_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCAP, lnkcap);
+ dw_pcie_dbi_ro_wr_dis(pci);
}
static int rockchip_pcie_start_link(struct dw_pcie *pci)
diff --git a/drivers/pci/controller/dwc/pcie-eswin.c b/drivers/pci/controller/dwc/pcie-eswin.c
index 2845832b3824..2e5b94c27026 100644
--- a/drivers/pci/controller/dwc/pcie-eswin.c
+++ b/drivers/pci/controller/dwc/pcie-eswin.c
@@ -84,8 +84,7 @@ static int eswin_pcie_start_link(struct dw_pcie *pci)
static bool eswin_pcie_link_up(struct dw_pcie *pci)
{
- u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
- u16 val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
+ u16 val = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
return val & PCI_EXP_LNKSTA_DLLLA;
}
diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c
index 66367252032b..553a940e6d89 100644
--- a/drivers/pci/controller/dwc/pcie-fu740.c
+++ b/drivers/pci/controller/dwc/pcie-fu740.c
@@ -179,7 +179,7 @@ static int fu740_pcie_start_link(struct dw_pcie *pci)
{
struct device *dev = pci->dev;
struct fu740_pcie *afp = dev_get_drvdata(dev);
- u8 cap_exp = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 cap_exp = pci->pcie_cap;
int ret;
u32 orig, tmp;
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index c21906eced61..939b9dcac7fe 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -121,7 +121,7 @@ static void intel_pcie_ltssm_disable(struct intel_pcie *pcie)
static void intel_pcie_link_setup(struct intel_pcie *pcie)
{
u32 val;
- u8 offset = dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP);
+ u8 offset = pcie->pci.pcie_cap;
val = pcie_rc_cfg_rd(pcie, offset + PCI_EXP_LNKCTL);
diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c
index 257c2bcb5f76..d041189be248 100644
--- a/drivers/pci/controller/dwc/pcie-qcom-ep.c
+++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c
@@ -307,14 +307,14 @@ static void qcom_pcie_dw_write_dbi2(struct dw_pcie *pci, void __iomem *base,
static void qcom_pcie_ep_icc_update(struct qcom_pcie_ep *pcie_ep)
{
struct dw_pcie *pci = &pcie_ep->pci;
- u32 offset, status;
- int speed, width;
- int ret;
+ int speed, width, ret;
+ u32 status;
+ u8 offset;
if (!pcie_ep->icc_mem)
return;
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = dw_pcie_get_pcie_cap(pci);
status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
@@ -492,14 +492,13 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci)
dw_pcie_dbi_ro_wr_en(pci);
/* Set the L0s Exit Latency to 2us-4us = 0x6 */
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = dw_pcie_get_pcie_cap(pci);
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
val &= ~PCI_EXP_LNKCAP_L0SEL;
val |= FIELD_PREP(PCI_EXP_LNKCAP_L0SEL, 0x6);
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, val);
/* Set the L1 Exit Latency to be 32us-64 us = 0x6 */
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
val &= ~PCI_EXP_LNKCAP_L1EL;
val |= FIELD_PREP(PCI_EXP_LNKCAP_L1EL, 0x6);
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index af6bf5cce65b..ddb0ae2bf64b 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -333,26 +333,22 @@ static int qcom_pcie_start_link(struct dw_pcie *pci)
static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci)
{
struct qcom_pcie *pcie = to_qcom_pcie(pci);
- u16 offset;
u32 val;
if (!pcie->cfg->no_l0s)
return;
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
-
dw_pcie_dbi_ro_wr_en(pci);
- val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
+ val = readl(pci->dbi_base + pci->pcie_cap + PCI_EXP_LNKCAP);
val &= ~PCI_EXP_LNKCAP_ASPM_L0S;
- writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
+ writel(val, pci->dbi_base + pci->pcie_cap + PCI_EXP_LNKCAP);
dw_pcie_dbi_ro_wr_dis(pci);
}
static void qcom_pcie_set_slot_nccs(struct dw_pcie *pci)
{
- u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
u32 val;
dw_pcie_dbi_ro_wr_en(pci);
@@ -362,9 +358,9 @@ static void qcom_pcie_set_slot_nccs(struct dw_pcie *pci)
* notifications for the Hot-Plug commands. So set the NCCS field to
* avoid waiting for the completions.
*/
- val = readl(pci->dbi_base + offset + PCI_EXP_SLTCAP);
+ val = readl(pci->dbi_base + pci->pcie_cap + PCI_EXP_SLTCAP);
val |= PCI_EXP_SLTCAP_NCCS;
- writel(val, pci->dbi_base + offset + PCI_EXP_SLTCAP);
+ writel(val, pci->dbi_base + pci->pcie_cap + PCI_EXP_SLTCAP);
dw_pcie_dbi_ro_wr_dis(pci);
}
@@ -900,7 +896,7 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
static int qcom_pcie_post_init_2_3_3(struct qcom_pcie *pcie)
{
struct dw_pcie *pci = pcie->pci;
- u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = pci->pcie_cap;
u32 val;
val = readl(pcie->parf + PARF_PHY_CTRL);
@@ -1209,7 +1205,7 @@ static int qcom_pcie_init_2_9_0(struct qcom_pcie *pcie)
static int qcom_pcie_post_init_2_9_0(struct qcom_pcie *pcie)
{
struct dw_pcie *pci = pcie->pci;
- u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = pci->pcie_cap;
u32 val;
int i;
@@ -1254,8 +1250,7 @@ static int qcom_pcie_post_init_2_9_0(struct qcom_pcie *pcie)
static bool qcom_pcie_link_up(struct dw_pcie *pci)
{
- u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
- u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
+ u16 val = readw(pci->dbi_base + pci->pcie_cap + PCI_EXP_LNKSTA);
return val & PCI_EXP_LNKSTA_DLLLA;
}
@@ -1559,15 +1554,14 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie)
{
- u32 offset, status, width, speed;
+ u32 status, width, speed;
struct dw_pcie *pci = pcie->pci;
struct dev_pm_opp_key key = {};
unsigned long freq_kbps;
struct dev_pm_opp *opp;
int ret, freq_mbps;
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
- status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
+ status = readw(pci->dbi_base + pci->pcie_cap + PCI_EXP_LNKSTA);
/* Only update constraints if link is up. */
if (!(status & PCI_EXP_LNKSTA_DLLLA))
diff --git a/drivers/pci/controller/dwc/pcie-sophgo.c b/drivers/pci/controller/dwc/pcie-sophgo.c
index 044088898819..5a2cd95c6de7 100644
--- a/drivers/pci/controller/dwc/pcie-sophgo.c
+++ b/drivers/pci/controller/dwc/pcie-sophgo.c
@@ -164,15 +164,13 @@ static void sophgo_pcie_msi_enable(struct dw_pcie_rp *pp)
static void sophgo_pcie_disable_l0s_l1(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- u32 offset, val;
-
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u32 val;
dw_pcie_dbi_ro_wr_en(pci);
- val = dw_pcie_readl_dbi(pci, PCI_EXP_LNKCAP + offset);
+ val = dw_pcie_readl_dbi(pci, PCI_EXP_LNKCAP + pci->pcie_cap);
val &= ~(PCI_EXP_LNKCAP_ASPM_L0S | PCI_EXP_LNKCAP_ASPM_L1);
- dw_pcie_writel_dbi(pci, PCI_EXP_LNKCAP + offset, val);
+ dw_pcie_writel_dbi(pci, PCI_EXP_LNKCAP + pci->pcie_cap, val);
dw_pcie_dbi_ro_wr_dis(pci);
}
diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
index be20a520255b..6f0556336f44 100644
--- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
+++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
@@ -114,12 +114,9 @@ static void k1_pcie_disable_resources(struct k1_pcie *k1)
static void k1_pcie_disable_aspm_l1(struct k1_pcie *k1)
{
struct dw_pcie *pci = &k1->pci;
- u8 offset;
+ u8 offset = pci->pcie_cap + PCI_EXP_LNKCAP;
u32 val;
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
- offset += PCI_EXP_LNKCAP;
-
dw_pcie_dbi_ro_wr_en(pci);
val = dw_pcie_readl_dbi(pci, offset);
val &= ~PCI_EXP_LNKCAP_ASPM_L1;
diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c
index 01794a9d3ad2..920454266f3f 100644
--- a/drivers/pci/controller/dwc/pcie-spear13xx.c
+++ b/drivers/pci/controller/dwc/pcie-spear13xx.c
@@ -122,7 +122,7 @@ static int spear13xx_pcie_host_init(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
- u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = pci->pcie_cap;
u32 val;
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
@@ -132,9 +132,9 @@ static int spear13xx_pcie_host_init(struct dw_pcie_rp *pp)
* default value in capability register is 512 bytes. So force
* it to 128 here.
*/
- val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
+ val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_DEVCTL);
val &= ~PCI_EXP_DEVCTL_READRQ;
- dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
+ dw_pcie_writew_dbi(pci, offset + PCI_EXP_DEVCTL, val);
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 9dcfa194050e..0d5a5e9027d9 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -268,7 +268,6 @@ struct tegra_pcie_dw {
u32 num_lanes;
u32 cid;
u32 ras_des_cap;
- u32 pcie_cap_base;
u32 aspm_cmrt;
u32 aspm_pwr_on_t;
u32 aspm_l0s_enter_lat;
@@ -312,7 +311,7 @@ static void tegra_pcie_icc_set(struct tegra_pcie_dw *pcie)
struct dw_pcie *pci = &pcie->pci;
u32 val, speed, width;
- val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
+ val = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, val);
width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val);
@@ -340,22 +339,22 @@ static void apply_bad_link_workaround(struct dw_pcie_rp *pp)
* stable anyway, not waiting to confirm if link is really
* transitioning to Gen-2 speed
*/
- val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
+ val = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
if (val & PCI_EXP_LNKSTA_LBMS) {
current_link_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val);
if (pcie->init_link_width > current_link_width) {
dev_warn(pci->dev, "PCIe link is bad, width reduced\n");
- val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
+ val = dw_pcie_readw_dbi(pci, pci->pcie_cap +
PCI_EXP_LNKCTL2);
val &= ~PCI_EXP_LNKCTL2_TLS;
val |= PCI_EXP_LNKCTL2_TLS_2_5GT;
- dw_pcie_writew_dbi(pci, pcie->pcie_cap_base +
+ dw_pcie_writew_dbi(pci, pci->pcie_cap +
PCI_EXP_LNKCTL2, val);
- val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
+ val = dw_pcie_readw_dbi(pci, pci->pcie_cap +
PCI_EXP_LNKCTL);
val |= PCI_EXP_LNKCTL_RL;
- dw_pcie_writew_dbi(pci, pcie->pcie_cap_base +
+ dw_pcie_writew_dbi(pci, pci->pcie_cap +
PCI_EXP_LNKCTL, val);
}
}
@@ -399,17 +398,17 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
apply_bad_link_workaround(pp);
}
if (status_l1 & APPL_INTR_STATUS_L1_8_0_BW_MGT_INT_STS) {
- val_w = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
+ val_w = dw_pcie_readw_dbi(pci, pci->pcie_cap +
PCI_EXP_LNKSTA);
val_w |= PCI_EXP_LNKSTA_LBMS;
- dw_pcie_writew_dbi(pci, pcie->pcie_cap_base +
+ dw_pcie_writew_dbi(pci, pci->pcie_cap +
PCI_EXP_LNKSTA, val_w);
appl_writel(pcie,
APPL_INTR_STATUS_L1_8_0_BW_MGT_INT_STS,
APPL_INTR_STATUS_L1_8_0);
- val_w = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
+ val_w = dw_pcie_readw_dbi(pci, pci->pcie_cap +
PCI_EXP_LNKSTA);
dev_dbg(pci->dev, "Link Speed : Gen-%u\n", val_w &
PCI_EXP_LNKSTA_CLS);
@@ -675,7 +674,7 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
- pcie->ras_des_cap = dw_pcie_find_ext_capability(&pcie->pci,
+ pcie->ras_des_cap = dw_pcie_find_ext_capability(pci,
PCI_EXT_CAP_ID_VNDR);
/* Enable ASPM counters */
@@ -766,15 +765,12 @@ static void tegra_pcie_enable_system_interrupts(struct dw_pcie_rp *pp)
appl_writel(pcie, val, APPL_INTR_EN_L1_18);
}
- val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base +
- PCI_EXP_LNKSTA);
+ val_w = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
pcie->init_link_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val_w);
- val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base +
- PCI_EXP_LNKCTL);
+ val_w = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCTL);
val_w |= PCI_EXP_LNKCTL_LBMIE;
- dw_pcie_writew_dbi(&pcie->pci, pcie->pcie_cap_base + PCI_EXP_LNKCTL,
- val_w);
+ dw_pcie_writew_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCTL, val_w);
}
static void tegra_pcie_enable_intx_interrupts(struct dw_pcie_rp *pp)
@@ -903,10 +899,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
pp->bridge->ops = &tegra_pci_ops;
- if (!pcie->pcie_cap_base)
- pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
- PCI_CAP_ID_EXP);
-
val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
@@ -927,10 +919,9 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
/* Clear Slot Clock Configuration bit if SRNS configuration */
if (pcie->enable_srns) {
- val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
- PCI_EXP_LNKSTA);
+ val_16 = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
val_16 &= ~PCI_EXP_LNKSTA_SLC;
- dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA,
+ dw_pcie_writew_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA,
val_16);
}
@@ -1047,8 +1038,7 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
static bool tegra_pcie_dw_link_up(struct dw_pcie *pci)
{
- struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
- u32 val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
+ u32 val = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
return val & PCI_EXP_LNKSTA_DLLLA;
}
@@ -1878,16 +1868,13 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
}
- pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
- PCI_CAP_ID_EXP);
+ dw_pcie_get_pcie_cap(pci);
/* Clear Slot Clock Configuration bit if SRNS configuration */
if (pcie->enable_srns) {
- val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
- PCI_EXP_LNKSTA);
+ val_16 = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
val_16 &= ~PCI_EXP_LNKSTA_SLC;
- dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA,
- val_16);
+ dw_pcie_writew_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA, val_16);
}
clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/3] PCI: dwc: Use cached PCIe capability offset in core
2026-05-09 13:51 ` [PATCH 2/3] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
@ 2026-05-09 15:07 ` sashiko-bot
0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-05-09 15:07 UTC (permalink / raw)
To: Hans Zhang; +Cc: linux-pci
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Calling `dw_pcie_get_pcie_cap()` before `ops->init()`/`ops->pre_init()` accesses unclocked hardware registers, causing a kernel panic or system hang.
- [High] Direct access to `pci->pcie_cap` bypasses lazy initialization, leading to invalid register reads/writes and silent PCI config space corruption.
--
commit 26cd77098a4771b4de6b7f3b4769d54179db8507
Author: Hans Zhang <18255117159@163.com>
PCI: dwc: Use cached PCIe capability offset in core
This commit modifies the DWC core functions to use a cached pcie_cap offset
rather than looking up the capability each time.
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -1390,6 +1390,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> ep->msi_msg_addr = 0;
> ep->msi_map_size = 0;
>
> + dw_pcie_get_pcie_cap(pci);
> +
> epc = devm_pci_epc_create(dev, &epc_ops);
Will this dw_pcie_get_pcie_cap() call cause a crash by accessing unclocked
hardware registers?
Looking at dw_pcie_ep_init(), clocks and regulators aren't enabled until
ep->ops->pre_init(ep) is executed further down in this function.
Calling dw_pcie_get_pcie_cap() here performs MMIO reads on the DBI
configuration space. On architectures like ARM/ARM64, reading from unclocked
MMIO space can trigger a synchronous external abort and kernel panic. If the
bus instead returns 0xFFFFFFFF, it could loop infinitely searching for the
next capability.
[ ... ]
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -575,6 +575,8 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
>
> raw_spin_lock_init(&pp->lock);
>
> + dw_pcie_get_pcie_cap(pci);
> +
> bridge = devm_pci_alloc_host_bridge(dev, 0);
Does this have the same early MMIO access issue as dw_pcie_ep_init()?
The platform-specific pp->ops->init(pp) callback isn't called until after
bridge allocation and resource fetching, so clocks might not be ready yet.
[ ... ]
> @@ -1218,7 +1220,7 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci)
>
> int dw_pcie_suspend_noirq(struct dw_pcie *pci)
> {
> - u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> + u8 offset = pci->pcie_cap;
Is it safe to bypass the lazy initialization provided by
dw_pcie_get_pcie_cap(pci)?
If pci->pcie_cap is 0, this direct struct access means the fallback
capability search is completely skipped.
[ ... ]
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -807,8 +807,7 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
> if (pci->max_link_speed > 2)
> msleep(PCIE_RESET_CONFIG_WAIT_MS);
>
> - offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> - val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
> + val = dw_pcie_readw_dbi(pci, pci->pcie_cap + PCI_EXP_LNKSTA);
Could bypassing dw_pcie_get_pcie_cap() here lead to silent PCI config
space corruption?
If pci->pcie_cap remains 0, reading or writing to pci->pcie_cap +
PCI_EXP_LNKSTA would operate on offset 0x12. This maps to the standard PCI
Header Type and BIST registers rather than the PCIe capability region,
potentially breaking link status checking and speed configuration.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509135152.2241235-1-18255117159@163.com?part=2
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 3/3] PCI: dwc: Simplify platform drivers using cached capability offset
2026-05-09 13:51 ` [PATCH 3/3] PCI: dwc: Simplify platform drivers using cached capability offset Hans Zhang
@ 2026-05-09 15:55 ` sashiko-bot
0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-05-09 15:55 UTC (permalink / raw)
To: Hans Zhang; +Cc: linux-pci
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Hardware access violation and state corruption due to prematurely cached `pci->pcie_cap` evaluating to 0 during early platform initialization.
--
commit fc0c674ee4b79463c25ac169e08eff8e9302d0c5
Author: Hans Zhang <18255117159@163.com>
PCI: dwc: Simplify platform drivers using cached capability offset
This commit replaces explicit dw_pcie_find_capability calls with the
cached pci->pcie_cap across several DWC-based platform drivers to
simplify the code.
> diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
> index c21906eced618..939b9dcac7fe2 100644
> --- a/drivers/pci/controller/dwc/pcie-intel-gw.c
> +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
> @@ -121,7 +121,7 @@ static void intel_pcie_ltssm_disable(struct intel_pcie *pcie)
> static void intel_pcie_link_setup(struct intel_pcie *pcie)
> {
> u32 val;
> - u8 offset = dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP);
> + u8 offset = pcie->pci.pcie_cap;
Will pcie->pci.pcie_cap be correctly populated here during early
initialization?
Since some platform drivers (like Intel Gateway and SpacemiT K1) enable
clocks and deassert resets in their .init callbacks, the hardware might
be inaccessible when the DWC core initially attempts to cache the
capability offset.
If the core evaluates pcie_cap to 0 before the hardware is powered on,
would using the cached value here cause us to read and modify standard
PCI configuration header registers instead of the PCIe Capability
structure?
[ ... ]
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index be20a520255b6..6f0556336f440 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -114,12 +114,9 @@ static void k1_pcie_disable_resources(struct k1_pcie *k1)
> static void k1_pcie_disable_aspm_l1(struct k1_pcie *k1)
> {
> struct dw_pcie *pci = &k1->pci;
> - u8 offset;
> + u8 offset = pci->pcie_cap + PCI_EXP_LNKCAP;
> u32 val;
>
> - offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> - offset += PCI_EXP_LNKCAP;
Could this also experience the same issue if pci->pcie_cap evaluated to 0
during early core initialization, causing offset to incorrectly point to
0 + PCI_EXP_LNKCAP (0x0c)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509135152.2241235-1-18255117159@163.com?part=3
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-05-09 15:55 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-09 13:51 [PATCH 0/3] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
2026-05-09 13:51 ` [PATCH 1/3] PCI: dwc: Add pcie_cap field and helper in designware header Hans Zhang
2026-05-09 13:51 ` [PATCH 2/3] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
2026-05-09 15:07 ` sashiko-bot
2026-05-09 13:51 ` [PATCH 3/3] PCI: dwc: Simplify platform drivers using cached capability offset Hans Zhang
2026-05-09 15:55 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox