* [PATCH v2 01/16] PCI: dwc: Add pcie_cap field and helper in designware header
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 02/16] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
` (15 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 7dac37521b8e..561b434fe335 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -596,6 +596,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)
@@ -834,6 +836,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 [flat|nested] 19+ messages in thread* [PATCH v2 02/16] PCI: dwc: Use cached PCIe capability offset in core
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
2026-05-30 15:30 ` [PATCH v2 01/16] PCI: dwc: Add pcie_cap field and helper in designware header Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 03/16] PCI: dwc: imx6: Use cached PCIe capability offset Hans Zhang
` (14 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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: dw_pcie_ep_init() calls ep->ops->pre_init() (enables
hardware), then dw_pcie_get_pcie_cap() caches the offset.
dw_pcie_ep_init_non_sticky_registers() is called after pre_init, so it can
use dw_pcie_get_pcie_cap() safely. 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 | 4 +++-
.../pci/controller/dwc/pcie-designware-host.c | 2 ++
drivers/pci/controller/dwc/pcie-designware.c | 16 ++++++----------
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index a396b58d6746..11b4fa6d129c 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 = 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);
@@ -1524,6 +1524,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
if (ep->ops->pre_init)
ep->ops->pre_init(ep);
+ dw_pcie_get_pcie_cap(pci);
+
ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
ep->page_size);
if (ret < 0) {
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index cffb34f6f3a9..b8175138e47a 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 37d2715e38eb..810e920c1d8b 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -765,7 +765,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 */
@@ -811,8 +811,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),
@@ -848,7 +847,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);
@@ -894,8 +893,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);
}
@@ -903,7 +901,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;
@@ -940,10 +937,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 [flat|nested] 19+ messages in thread* [PATCH v2 03/16] PCI: dwc: imx6: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
2026-05-30 15:30 ` [PATCH v2 01/16] PCI: dwc: Add pcie_cap field and helper in designware header Hans Zhang
2026-05-30 15:30 ` [PATCH v2 02/16] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 04/16] PCI: dwc: layerscape-ep: " Hans Zhang
` (13 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 773ab65b2afa..de06ff429eff 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -933,10 +933,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,
@@ -962,7 +962,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 [flat|nested] 19+ messages in thread* [PATCH v2 04/16] PCI: dwc: layerscape-ep: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (2 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 03/16] PCI: dwc: imx6: Use cached PCIe capability offset Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 05/16] PCI: dwc: meson: " Hans Zhang
` (12 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 [flat|nested] 19+ messages in thread* [PATCH v2 05/16] PCI: dwc: meson: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (3 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 04/16] PCI: dwc: layerscape-ep: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 06/16] PCI: dwc: rockchip: " Hans Zhang
` (11 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 0694084f612b..81767d010c84 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 = 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);
@@ -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 = 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 [flat|nested] 19+ messages in thread* [PATCH v2 06/16] PCI: dwc: rockchip: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (4 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 05/16] PCI: dwc: meson: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-06-01 17:11 ` Sebastian Reichel
2026-05-30 15:30 ` [PATCH v2 07/16] PCI: dwc: eswin: " Hans Zhang
` (10 subsequent siblings)
16 siblings, 1 reply; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, linux-pci, linux-kernel, Hans Zhang
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>
---
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 [flat|nested] 19+ messages in thread* Re: [PATCH v2 06/16] PCI: dwc: rockchip: Use cached PCIe capability offset
2026-05-30 15:30 ` [PATCH v2 06/16] PCI: dwc: rockchip: " Hans Zhang
@ 2026-06-01 17:11 ` Sebastian Reichel
0 siblings, 0 replies; 19+ messages in thread
From: Sebastian Reichel @ 2026-06-01 17:11 UTC (permalink / raw)
To: Hans Zhang
Cc: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7,
robh, linux-pci, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1497 bytes --]
Hi,
On Sat, May 30, 2026 at 11:30:51PM +0800, Hans Zhang wrote:
> 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>
Greetings,
-- Sebastian
> 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
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 07/16] PCI: dwc: eswin: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (5 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 06/16] PCI: dwc: rockchip: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 08/16] PCI: dwc: fu740: " Hans Zhang
` (9 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 [flat|nested] 19+ messages in thread* [PATCH v2 08/16] PCI: dwc: fu740: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (6 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 07/16] PCI: dwc: eswin: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 09/16] PCI: dwc: intel-gw: " Hans Zhang
` (8 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 [flat|nested] 19+ messages in thread* [PATCH v2 09/16] PCI: dwc: intel-gw: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (7 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 08/16] PCI: dwc: fu740: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 10/16] PCI: dwc: qcom-ep: " Hans Zhang
` (7 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 2674cd376f49..568b2634d08d 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -120,7 +120,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 [flat|nested] 19+ messages in thread* [PATCH v2 10/16] PCI: dwc: qcom-ep: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (8 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 09/16] PCI: dwc: intel-gw: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 11/16] PCI: dwc: qcom: " Hans Zhang
` (6 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, linux-pci, linux-kernel, Hans Zhang
dw_pcie_ep_init() calls ep->ops->pre_init() (enables hardware) and then
dw_pcie_get_pcie_cap() to cache the offset. Therefore, the IRQ handlers
run after the cache is populated, so they can safely use pci->pcie_cap
directly.
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 | 11 ++++-------
1 file changed, 4 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..0471f96d3c78 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);
@@ -492,13 +490,12 @@ 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 = 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 [flat|nested] 19+ messages in thread* [PATCH v2 11/16] PCI: dwc: qcom: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (9 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 10/16] PCI: dwc: qcom-ep: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 12/16] PCI: dwc: sophgo: " Hans Zhang
` (5 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 11fc60489892..80783353d539 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;
}
@@ -1663,15 +1661,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 [flat|nested] 19+ messages in thread* [PATCH v2 12/16] PCI: dwc: sophgo: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (10 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 11/16] PCI: dwc: qcom: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 13/16] PCI: dwc: spacemit-k1: " Hans Zhang
` (4 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 [flat|nested] 19+ messages in thread* [PATCH v2 13/16] PCI: dwc: spacemit-k1: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (11 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 12/16] PCI: dwc: sophgo: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:30 ` [PATCH v2 14/16] PCI: dwc: spear13xx: " Hans Zhang
` (3 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 be20a520255b..65114060311e 100644
--- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
+++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
@@ -117,7 +117,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 [flat|nested] 19+ messages in thread* [PATCH v2 14/16] PCI: dwc: spear13xx: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (12 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 13/16] PCI: dwc: spacemit-k1: " Hans Zhang
@ 2026-05-30 15:30 ` Hans Zhang
2026-05-30 15:31 ` [PATCH v2 15/16] PCI: dwc: tegra194: " Hans Zhang
` (2 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:30 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 [flat|nested] 19+ messages in thread* [PATCH v2 15/16] PCI: dwc: tegra194: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (13 preceding siblings ...)
2026-05-30 15:30 ` [PATCH v2 14/16] PCI: dwc: spear13xx: " Hans Zhang
@ 2026-05-30 15:31 ` Hans Zhang
2026-05-30 15:31 ` [PATCH v2 16/16] PCI: dwc: ultrarisc: " Hans Zhang
2026-07-15 13:35 ` [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Manivannan Sadhasivam
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:31 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 before
dw_pcie_ep_init(), but the driver has already enabled hardware.
dw_pcie_get_pcie_cap() will perform the DBI read and cache the offset.
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 [flat|nested] 19+ messages in thread* [PATCH v2 16/16] PCI: dwc: ultrarisc: Use cached PCIe capability offset
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (14 preceding siblings ...)
2026-05-30 15:31 ` [PATCH v2 15/16] PCI: dwc: tegra194: " Hans Zhang
@ 2026-05-30 15:31 ` Hans Zhang
2026-07-15 13:35 ` [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Manivannan Sadhasivam
16 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-05-30 15:31 UTC (permalink / raw)
To: bhelgaas, lpieralisi, kwilczynski, mani, s-vadapalli, a-garg7
Cc: robh, 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 [flat|nested] 19+ messages in thread* Re: [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers
2026-05-30 15:30 [PATCH v2 00/16] PCI: dwc: Cache PCIe capability offset and simplify drivers Hans Zhang
` (15 preceding siblings ...)
2026-05-30 15:31 ` [PATCH v2 16/16] PCI: dwc: ultrarisc: " Hans Zhang
@ 2026-07-15 13:35 ` Manivannan Sadhasivam
16 siblings, 0 replies; 19+ messages in thread
From: Manivannan Sadhasivam @ 2026-07-15 13:35 UTC (permalink / raw)
To: Hans Zhang
Cc: bhelgaas, lpieralisi, kwilczynski, s-vadapalli, a-garg7, robh,
linux-pci, linux-kernel
On Sat, May 30, 2026 at 11:30:45PM +0800, Hans Zhang wrote:
> Hi,
>
> 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. Some drivers even search for the offset in suspend/resume paths.
>
> Add a cached pcie_cap field in struct dw_pcie and a helper
> dw_pcie_get_pcie_cap() to initialize it once at the point when the
> hardware is ready. Then replace all explicit capability searches with
> the cached value across the entire dwc subtree.
>
> **Safety analysis: DBI access timing**
> The PCIe Capability offset is read from DBI configuration space. DBI
> registers are only accessible after the controller's clocks, resets, and
> power are enabled. The following call graph demonstrates that all
> dw_pcie_find_capability() replacements occur only after hardware is ready:
>
> - For Root Complex mode:
> dw_pcie_host_init()
> ...
> if (pp->ops->init)
> pp->ops->init [enables clocks/resets]
> dw_pcie_get_pcie_cap() [caches offset]
> ...
> dw_pcie_link_up
> pci->ops->link_up
> ...
> dw_pcie_start_link
> pci->ops->start_link
> ...
> pci_host_probe
> if (pp->ops->post_init)
> pp->ops->post_init
> ...
>
> - For Endpoint mode:
> dw_pcie_ep_init()
> ep->ops->pre_init() [enables clocks/resets]
> dw_pcie_get_pcie_cap() [caches offset]
> dw_pcie_ep_init_non_sticky_registers() etc.
>
> - Some platform drivers (e.g., layerscape-ep, tegra194) need the offset
> before calling dw_pcie_ep_init() / dw_pcie_host_init(). They already
> enable hardware themselves and explicitly call dw_pcie_get_pcie_cap()
> before the core caches it. This is safe and ensures the cached value is
> available for all later users.
>
> Thus, no DBI access occurs before hardware is operational.
>
Not true. As Sashiko pointed out, EP platforms like Qcom, Tegra, enable
resources like clocks only after PERST# deassert. So any DBI access before that
will cause sync abort.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 19+ messages in thread