* [PATCH v3 01/16] PCI: dwc: Add pcie_cap field and helper in designware header
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 02/16] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
` (14 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, 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 de4b245b1758..8113efd33a24 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -591,6 +591,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)
@@ -829,6 +831,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] 17+ messages in thread* [PATCH v3 02/16] PCI: dwc: Use cached PCIe capability offset in core
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
2026-07-20 15:06 ` [PATCH v3 01/16] PCI: dwc: Add pcie_cap field and helper in designware header Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 03/16] PCI: dwc: imx6: Use cached PCIe capability offset Hans Zhang
` (13 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, 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.
In the DWC core, dw_pcie_find_capability() is called at several locations:
- dw_pcie_ep_init_non_sticky_registers()
- dw_pcie_wait_for_link()
- dw_pcie_link_set_max_speed()
- dw_pcie_link_get_max_link_width()
- dw_pcie_link_set_max_link_width()
The cached offset is initialized after hardware is ready:
- In host mode: dw_pcie_host_init() calls pp->ops->host_init() (enables
clocks/resets), then dw_pcie_get_pcie_cap() caches the offset.
- In endpoint mode: the core no longer caches automatically. Instead,
drivers must call dw_pcie_get_pcie_cap() after hardware is enabled
(e.g., after PERST# deassert). dw_pcie_ep_init_non_sticky_registers()
is called after that point, so it can safely use pci->pcie_cap.
dw_pcie_ep_init_non_sticky_registers() now assumes pci->pcie_cap is
valid. if not, it prints a warning and skips the operation. The other
functions run after probe, so pci->pcie_cap is already valid and can
be used directly.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +-
drivers/pci/controller/dwc/pcie-designware-host.c | 2 ++
drivers/pci/controller/dwc/pcie-designware.c | 15 ++++++---------
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 7d2794945704..14228be8bbce 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -1246,7 +1246,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 = pci->pcie_cap;
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);
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 06722259d2e3..fee800ac56d4 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -593,6 +593,8 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
goto err_free_ecam;
}
+ dw_pcie_get_pcie_cap(pci);
+
if (pci_msi_enabled()) {
pp->use_imsi_rx = !(pp->ops->msi_init ||
of_property_present(np, "msi-parent") ||
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index ec4722ed9303..810729b91892 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -766,7 +766,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 */
@@ -806,8 +806,7 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
pci_host_common_link_train_delay(pci->max_link_speed);
- 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),
@@ -843,7 +842,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,7 +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);
}
@@ -898,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;
@@ -935,10 +933,9 @@ 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);
FIELD_MODIFY(PCI_EXP_LNKCAP_MLW, &lnkcap, 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] 17+ messages in thread* [PATCH v3 03/16] PCI: dwc: imx6: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
2026-07-20 15:06 ` [PATCH v3 01/16] PCI: dwc: Add pcie_cap field and helper in designware header Hans Zhang
2026-07-20 15:06 ` [PATCH v3 02/16] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 04/16] PCI: dwc: layerscape-ep: " Hans Zhang
` (12 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
Thus, the cached offset is available when these functions are called, and
DBI access occurs only after hardware is enabled.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pci-imx6, dw_pcie_find_capability() is called in the following
call chain:
static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = imx_pcie_start_link,
};
imx_pcie_start_link()
-> dw_pcie_find_capability()
-> imx_pcie_ltssm_enable()
-> dw_pcie_find_capability()
Replace these calls with the cached pci->pcie_cap. The call chain after
modification becomes:
dw_pcie_host_init()
-> pp->ops->init() [imx6_pcie_host_init]
-> dw_pcie_get_pcie_cap() (caches offset)
-> pci->ops->start_link = imx_pcie_start_link
-> uses pci->pcie_cap
-> imx_pcie_ltssm_enable()
-> uses pci->pcie_cap
---
drivers/pci/controller/dwc/pci-imx6.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 98e1db751132..74b28b4df484 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -966,10 +966,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,
@@ -995,7 +995,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;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 04/16] PCI: dwc: layerscape-ep: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (2 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 03/16] PCI: dwc: imx6: Use cached PCIe capability offset Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 05/16] PCI: dwc: meson: " Hans Zhang
` (11 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
Replace these with dw_pcie_get_pcie_cap(). The hardware is already enabled
by the driver before ls_pcie_ep_probe() and before the interrupt handler
runs. dw_pcie_get_pcie_cap() will cache the offset on first call, and
subsequent calls (including inside dw_pcie_ep_init) will use the cached
value without re-searching.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pci-layerscape-ep, dw_pcie_find_capability() is called in:
ls_pcie_ep_probe()
-> offset = dw_pcie_find_capability()
-> pcie->lnkcap = dw_pcie_readl_dbi(offset + PCI_EXP_LNKCAP)
-> dw_pcie_ep_init()
-> ls_pcie_ep_interrupt_init()
-> devm_request_irq(..., ls_pcie_ep_event_handler)
-> ls_pcie_ep_event_handler()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pci-layerscape-ep.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
index 8936975ff104..b2d0b51df3c5 100644
--- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
+++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
@@ -74,7 +74,6 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
struct ls_pcie_ep *pcie = dev_id;
struct dw_pcie *pci = pcie->pci;
u32 val, cfg;
- u8 offset;
val = ls_pcie_pf_lut_readl(pcie, PEX_PF0_PME_MES_DR);
ls_pcie_pf_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
@@ -83,9 +82,6 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
return IRQ_NONE;
if (val & PEX_PF0_PME_MES_DR_LUD) {
-
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
-
/*
* The values of the Maximum Link Width and Supported Link
* Speed from the Link Capabilities Register will be lost
@@ -93,7 +89,8 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
* that configured by the Reset Configuration Word (RCW).
*/
dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, pcie->lnkcap);
+ dw_pcie_writel_dbi(pci, pci->pcie_cap + PCI_EXP_LNKCAP,
+ pcie->lnkcap);
dw_pcie_dbi_ro_wr_dis(pci);
cfg = ls_pcie_pf_lut_readl(pcie, PEX_PF0_CONFIG);
@@ -266,7 +263,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);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 05/16] PCI: dwc: meson: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (3 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 04/16] PCI: dwc: layerscape-ep: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 06/16] PCI: dwc: rockchip: " Hans Zhang
` (10 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
dw_pcie_host_init() calls pp->ops->init (meson_pcie_host_init) before
caching the offset. Therefore, inside .init we must call
dw_pcie_get_pcie_cap() to obtain the offset (the helper will perform the
DBI read and cache the result). This is safe because the hardware is
already enabled by the driver's own initialization.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pci-meson, the call chain is:
static const struct dw_pcie_host_ops meson_pcie_host_ops = {
.init = meson_pcie_host_init,
};
meson_pcie_host_init()
-> meson_set_max_payload()
-> dw_pcie_find_capability()
-> meson_set_max_rd_req_size()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pci-meson.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
index 7a4da9fae1ea..c9d0388d262b 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -277,7 +277,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 = dw_pcie_get_pcie_cap(pci);
int max_payload_size = meson_size_to_payload(mp, size);
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
@@ -293,7 +293,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 = dw_pcie_get_pcie_cap(pci);
int max_rd_req_size = meson_size_to_payload(mp, size);
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 06/16] PCI: dwc: rockchip: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (4 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 05/16] PCI: dwc: meson: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 07/16] PCI: dwc: eswin: " Hans Zhang
` (9 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang, Sebastian Reichel
dw_pcie_host_init() calls .init before caching the offset. So inside
.init we call dw_pcie_get_pcie_cap() to trigger caching. The helper will
perform the DBI read (hardware is already enabled) and cache the result.
Signed-off-by: Hans Zhang <18255117159@163.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
In pcie-dw-rockchip, the call chain is:
static const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
.init = rockchip_pcie_host_init,
};
rockchip_pcie_host_init()
-> rockchip_pcie_enable_l0s()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 731d93663cca..be8b6187913d 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -369,7 +369,7 @@ static void rockchip_pcie_enable_l0s(struct dw_pcie *pci)
u32 cap, lnkcap;
/* Enable L0S capability for all SoCs */
- cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ cap = dw_pcie_get_pcie_cap(pci);
if (cap) {
lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
lnkcap |= PCI_EXP_LNKCAP_ASPM_L0S;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 07/16] PCI: dwc: eswin: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (5 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 06/16] PCI: dwc: rockchip: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 08/16] PCI: dwc: fu740: " Hans Zhang
` (8 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
This function is called after dw_pcie_host_init() has already cached the
offset (dw_pcie_link_up() is called after .init and after caching).
Therefore, we can directly use pci->pcie_cap.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-eswin, the call chain is:
static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = eswin_pcie_link_up,
};
eswin_pcie_link_up()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-eswin.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-eswin.c b/drivers/pci/controller/dwc/pcie-eswin.c
index ce8d64f8a395..6a37fd5a8384 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;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 08/16] PCI: dwc: fu740: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (6 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 07/16] PCI: dwc: eswin: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 09/16] PCI: dwc: intel-gw: " Hans Zhang
` (7 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
This callback is invoked after dw_pcie_host_init() has cached the offset,
so we can use pci->pcie_cap directly.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-fu740, the call chain is:
static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = fu740_pcie_start_link,
};
fu740_pcie_start_link()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-fu740.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c
index d0a34f680397..72c0a6316fff 100644
--- a/drivers/pci/controller/dwc/pcie-fu740.c
+++ b/drivers/pci/controller/dwc/pcie-fu740.c
@@ -178,7 +178,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;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 09/16] PCI: dwc: intel-gw: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (7 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 08/16] PCI: dwc: fu740: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 10/16] PCI: dwc: qcom-ep: " Hans Zhang
` (6 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
dw_pcie_host_init() calls .init before caching the offset, so inside
.init we must call dw_pcie_get_pcie_cap() to obtain the offset (hardware
is already enabled). The helper will cache the result for later use.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-intel-gw, the call chain is:
static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
.init = intel_pcie_rc_init,
};
intel_pcie_rc_init()
-> intel_pcie_host_setup()
-> intel_pcie_link_setup()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-intel-gw.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index 348e579e683f..a891c3f8eb01 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -119,7 +119,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 = dw_pcie_get_pcie_cap(&pcie->pci);
val = pcie_rc_cfg_rd(pcie, offset + PCI_EXP_LNKCTL);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 10/16] PCI: dwc: qcom-ep: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (8 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 09/16] PCI: dwc: intel-gw: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 11/16] PCI: dwc: qcom: " Hans Zhang
` (5 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
dw_pcie_ep_init() no longer caches the offset automatically. For qcom-ep,
hardware (clocks, PHY) is enabled only after PERST# deassert. Therefore,
we must call dw_pcie_get_pcie_cap() in qcom_pcie_perst_deassert() after
the resources are enabled, before any DBI access. This ensures the cached
offset is valid for subsequent uses in interrupt handlers and ICC updates.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-qcom-ep, dw_pcie_find_capability() appears in:
qcom_pcie_ep_probe()
-> dw_pcie_ep_init()
-> qcom_pcie_ep_enable_irq_resources()
-> qcom_pcie_ep_global_irq_thread()
-> qcom_pcie_ep_icc_update()
-> dw_pcie_find_capability()
-> qcom_pcie_ep_perst_irq_thread()
-> qcom_pcie_perst_deassert()
-> offset = dw_pcie_find_capability() (called twice)
---
drivers/pci/controller/dwc/pcie-qcom-ep.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c
index 56184e6ca6e6..16b0891f9571 100644
--- a/drivers/pci/controller/dwc/pcie-qcom-ep.c
+++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c
@@ -307,15 +307,13 @@ 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;
if (!pcie_ep->icc_mem)
return;
- 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);
speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status);
@@ -491,14 +489,15 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci)
dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_get_pcie_cap(pci);
+
/* Set the L0s Exit Latency to 2us-4us = 0x6 */
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = pci->pcie_cap;
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
FIELD_MODIFY(PCI_EXP_LNKCAP_L0SEL, &val, 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);
FIELD_MODIFY(PCI_EXP_LNKCAP_L1EL, &val, 0x6);
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, val);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 11/16] PCI: dwc: qcom: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (9 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 10/16] PCI: dwc: qcom-ep: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 12/16] PCI: dwc: sophgo: " Hans Zhang
` (4 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
dw_pcie_host_init() caches the offset after .init, so .post_init callbacks
and later functions (.link_up, icc_opp_update) can use pci->pcie_cap
directly. For .init itself, we must call dw_pcie_get_pcie_cap() inside
qcom_pcie_host_init() to obtain the offset (hardware is already enabled).
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-qcom, dw_pcie_find_capability() appears in multiple call chains:
static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
.init = qcom_pcie_host_init,
};
qcom_pcie_host_init()
-> qcom_pcie_clear_aspm_l0s()
-> dw_pcie_find_capability()
static const struct qcom_pcie_ops ops_* = {
.post_init = qcom_pcie_post_init_*,
};
qcom_pcie_post_init_*()
-> qcom_pcie_set_slot_nccs() (for many versions)
-> dw_pcie_find_capability()
-> For 2_3_3 and 2_9_0: also calls dw_pcie_find_capability() directly
static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = qcom_pcie_link_up,
};
qcom_pcie_link_up()
-> dw_pcie_find_capability()
qcom_pcie_probe()
-> dw_pcie_host_init()
-> qcom_pcie_icc_opp_update()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-qcom.c | 21 +++++++++------------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index d8eb52857f69..bd383d7cb02b 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -341,13 +341,13 @@ 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;
+ u8 offset;
u32 val;
if (!pcie->cfg->no_l0s)
return;
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = dw_pcie_get_pcie_cap(pci);
dw_pcie_dbi_ro_wr_en(pci);
@@ -360,7 +360,6 @@ static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *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);
@@ -370,9 +369,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);
}
@@ -935,7 +934,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;
/* Force PHY out of lowest power state */
@@ -1257,7 +1256,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;
@@ -1303,8 +1302,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;
}
@@ -1664,15 +1662,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))
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 12/16] PCI: dwc: sophgo: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (10 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 11/16] PCI: dwc: qcom: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 13/16] PCI: dwc: spacemit-k1: " Hans Zhang
` (3 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
dw_pcie_host_init() calls .init before caching, so we must call
dw_pcie_get_pcie_cap() inside .init. The hardware is already enabled by
the driver's own initialization before this point. The helper will cache
the offset and avoid redundant searches.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-sophgo, the call chain is:
static const struct dw_pcie_host_ops sophgo_pcie_host_ops = {
.init = sophgo_pcie_host_init,
};
sophgo_pcie_host_init()
-> sophgo_pcie_disable_l0s_l1()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-sophgo.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-sophgo.c b/drivers/pci/controller/dwc/pcie-sophgo.c
index 044088898819..39703d2b7b5f 100644
--- a/drivers/pci/controller/dwc/pcie-sophgo.c
+++ b/drivers/pci/controller/dwc/pcie-sophgo.c
@@ -164,9 +164,10 @@ 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;
+ u8 offset;
+ u32 val;
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = dw_pcie_get_pcie_cap(pci);
dw_pcie_dbi_ro_wr_en(pci);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 13/16] PCI: dwc: spacemit-k1: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (11 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 12/16] PCI: dwc: sophgo: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 14/16] PCI: dwc: spear13xx: " Hans Zhang
` (2 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
Because .init runs before core caching, we call dw_pcie_get_pcie_cap()
inside k1_pcie_disable_aspm_l1() to get the capability base, then add
PCI_EXP_LNKCAP. Hardware is already enabled at this point.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-spacemit-k1, the call chain is:
static const struct dw_pcie_host_ops k1_pcie_host_ops = {
.init = k1_pcie_init,
};
k1_pcie_init()
-> k1_pcie_disable_aspm_l1()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-spacemit-k1.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
index 04241df8fd59..3e741324f44a 100644
--- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
+++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
@@ -116,7 +116,7 @@ static void k1_pcie_disable_aspm_l1(struct k1_pcie *k1)
u8 offset;
u32 val;
- offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ offset = dw_pcie_get_pcie_cap(pci);
offset += PCI_EXP_LNKCAP;
dw_pcie_dbi_ro_wr_en(pci);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 14/16] PCI: dwc: spear13xx: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (12 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 13/16] PCI: dwc: spacemit-k1: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 15/16] PCI: dwc: tegra194: " Hans Zhang
2026-07-20 15:06 ` [PATCH v3 16/16] PCI: dwc: ultrarisc: " Hans Zhang
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
Inside .init we must call dw_pcie_get_pcie_cap() to obtain the offset,
because the core has not yet cached it. The hardware is already enabled
by the driver's own initialization before this point.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-spear13xx, the call chain is:
static const struct dw_pcie_host_ops spear13xx_pcie_host_ops = {
.init = spear13xx_pcie_host_init,
};
spear13xx_pcie_host_init()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-spear13xx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c
index 01794a9d3ad2..6e4c11b497d4 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 exp_cap_off = dw_pcie_get_pcie_cap(pci);
u32 val;
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 15/16] PCI: dwc: tegra194: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (13 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 14/16] PCI: dwc: spear13xx: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
2026-07-20 15:06 ` [PATCH v3 16/16] PCI: dwc: ultrarisc: " Hans Zhang
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
In host mode: tegra_pcie_dw_host_init() runs inside .start_link, which is
called after dw_pcie_host_init() has cached the offset. However, the
driver's own initialization already enables hardware, so calling
dw_pcie_get_pcie_cap() is safe and will return the cached value.
In endpoint mode: pex_ep_event_pex_rst_deassert() runs after hardware is
enabled (PERST# deassert). Because the core no longer caches automatically,
we call dw_pcie_get_pcie_cap() here to cache the offset for subsequent
accesses. The helper performs the DBI read only when hardware is ready.
Thus, the private pcie_cap_base is always valid and can still be used for
register accesses.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-tegra194, dw_pcie_find_capability() appears in:
static const struct dw_pcie_ops tegra_dw_pcie_ops = {
.start_link = tegra_pcie_dw_start_link,
};
tegra_pcie_dw_start_link()
-> tegra_pcie_dw_host_init()
-> dw_pcie_find_capability()
tegra_pcie_dw_probe()
case DW_PCIE_EP_TYPE:
tegra_pcie_config_ep()
-> pex_ep_event_pex_rst_deassert()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-tegra194.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 795cef5a915d..bf482bc66a92 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -905,8 +905,7 @@ 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);
+ pcie->pcie_cap_base = dw_pcie_get_pcie_cap(pci);
val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
@@ -1889,8 +1888,7 @@ 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);
+ pcie->pcie_cap_base = dw_pcie_get_pcie_cap(pci);
/* Clear Slot Clock Configuration bit if SRNS configuration */
if (pcie->enable_srns) {
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v3 16/16] PCI: dwc: ultrarisc: Use cached PCIe capability offset
2026-07-20 15:06 [PATCH v3 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (14 preceding siblings ...)
2026-07-20 15:06 ` [PATCH v3 15/16] PCI: dwc: tegra194: " Hans Zhang
@ 2026-07-20 15:06 ` Hans Zhang
15 siblings, 0 replies; 17+ messages in thread
From: Hans Zhang @ 2026-07-20 15:06 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: imx, linuxppc-dev, linux-amlogic, linux-rockchip, linux-arm-msm,
sophgo, linux-riscv, spacemit, linux-tegra, linux-pci,
linux-kernel, Hans Zhang
Inside .init we call dw_pcie_get_pcie_cap() to obtain the offset, because
the core has not yet cached it. Hardware is already enabled by the driver
before this point.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
In pcie-ultrarisc, the call chain is:
static const struct dw_pcie_host_ops ultrarisc_pcie_host_ops = {
.init = ultrarisc_pcie_host_init,
};
ultrarisc_pcie_host_init()
-> dw_pcie_find_capability()
---
drivers/pci/controller/dwc/pcie-ultrarisc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-ultrarisc.c b/drivers/pci/controller/dwc/pcie-ultrarisc.c
index 6ee661ceff67..3f6e3ab0aa69 100644
--- a/drivers/pci/controller/dwc/pcie-ultrarisc.c
+++ b/drivers/pci/controller/dwc/pcie-ultrarisc.c
@@ -49,7 +49,7 @@ static int ultrarisc_pcie_host_init(struct dw_pcie_rp *pp)
FIELD_MODIFY(PORT_FLT_SF_MASK, &val, PORT_FLT_SF_VAL_64);
dw_pcie_writel_dbi(pci, PCIE_TIMER_CTRL_MAX_FUNC_NUM, val);
- cap_exp = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ cap_exp = dw_pcie_get_pcie_cap(pci);
val = dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_LNKCTL2);
FIELD_MODIFY(PCI_EXP_LNKCTL2_TLS, &val, PCI_EXP_LNKCTL2_TLS_16_0GT);
dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_LNKCTL2, val);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread