* [PATCH v4 01/16] PCI: dwc: Add pcie_cap field and caching helper
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 13:12 ` Shawn Lin
2026-10-27 12:28 ` [PATCH v4 02/16] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
` (14 subsequent siblings)
15 siblings, 1 reply; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
The DWC PCIe core and its platform drivers repeatedly call
dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) to obtain the offset of the
PCI Express Capability structure. Besides being verbose, that performs a
DBI read every time, including in paths that run repeatedly such as link
up polling, suspend/resume and interrupt handlers.
Add a pcie_cap field to struct dw_pcie and a helper
dw_pcie_get_pcie_cap() that performs the lookup on first use and caches
the result for the subsequent calls.
The lookup is deliberately done lazily, at the first place that needs the
offset, instead of at a fixed point during controller initialization.
This guarantees that the DBI read happens exactly when the open coded
dw_pcie_find_capability() call it replaces used to happen, so no DBI
access can be made before the controller clocks, resets and power are
enabled. This matters for endpoint controllers such as qcom-ep and
tegra194, where DBI is only accessible after PERST# is deasserted, and it
also means platform drivers do not have to call the helper from a
specific callback at the right time.
The cached value is accessed with READ_ONCE()/WRITE_ONCE(), because the
first lookup may be triggered from different contexts, for example the
qcom-ep global IRQ and PERST# IRQ handlers. A concurrent lookup stores
the same value, so this race is benign.
A return value of 0 means that the capability is not present. This
cannot happen on real DWC hardware, where the PCI Express Capability is
mandatory, so a negative result is not cached separately: it only causes
the search to be repeated, which does not affect correctness.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-designware.h | 34 ++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 0735ae940924..fa31e8b763bc 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -592,6 +592,8 @@ struct dw_pcie {
* use_parent_dt_ranges to true to avoid this warning.
*/
bool use_parent_dt_ranges;
+
+ u8 pcie_cap; /* Offset of PCI_CAP_ID_EXP */
};
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
@@ -830,6 +832,38 @@ 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 the PCIe Capability offset
+ * @pci: DWC instance
+ *
+ * The offset of the PCI Express Capability structure is read once from
+ * the DBI configuration space on the first call and cached in
+ * @pci->pcie_cap for the subsequent ones.
+ *
+ * The lookup is done lazily at the first place that actually needs the
+ * offset, so the DBI read happens exactly when it used to happen before
+ * caching was introduced, i.e. never before the controller's clocks,
+ * resets and power are enabled.
+ *
+ * DWC PCIe controllers always implement the PCI Express Capability, so a
+ * return value of 0 means that the hardware is not usable. Callers that
+ * check the returned offset keep working, and the (never expected)
+ * lookup is simply repeated on the next call.
+ *
+ * Return: the cached offset, or 0 if the capability is not present.
+ */
+static inline u8 dw_pcie_get_pcie_cap(struct dw_pcie *pci)
+{
+ u8 cap = READ_ONCE(pci->pcie_cap);
+
+ if (!cap) {
+ cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ WRITE_ONCE(pci->pcie_cap, cap);
+ }
+
+ return cap;
+}
+
static inline int dw_pcie_start_link(struct dw_pcie *pci)
{
if (pci->ops && pci->ops->start_link)
--
2.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 01/16] PCI: dwc: Add pcie_cap field and caching helper
2026-10-27 12:28 ` [PATCH v4 01/16] PCI: dwc: Add pcie_cap field and caching helper Hans Zhang
@ 2026-10-27 13:12 ` Shawn Lin
0 siblings, 0 replies; 19+ messages in thread
From: Shawn Lin @ 2026-10-27 13:12 UTC (permalink / raw)
To: Hans Zhang, bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: shawn.lin, imx, linuxppc-dev, linux-amlogic, linux-rockchip,
linux-arm-msm, sophgo, linux-riscv, spacemit, linux-tegra,
linux-pci, linux-kernel
Hi Hans,
在 2026/10/27 星期二 20:28, Hans Zhang 写道:
> The DWC PCIe core and its platform drivers repeatedly call
> dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) to obtain the offset of the
> PCI Express Capability structure. Besides being verbose, that performs a
> DBI read every time, including in paths that run repeatedly such as link
> up polling, suspend/resume and interrupt handlers.
>
> Add a pcie_cap field to struct dw_pcie and a helper
> dw_pcie_get_pcie_cap() that performs the lookup on first use and caches
> the result for the subsequent calls.
>
> The lookup is deliberately done lazily, at the first place that needs the
> offset, instead of at a fixed point during controller initialization.
> This guarantees that the DBI read happens exactly when the open coded
> dw_pcie_find_capability() call it replaces used to happen, so no DBI
> access can be made before the controller clocks, resets and power are
With the controller inaccessible (clocks/power gated), what a DBI
read returns is platform dependent, most integrations just hang the
accessing CPU, like Rockchip's SoCs, others might return zero or
garbage. Zero self-heals as the commit message describes, but a garbage
non-zero lookup would now be cached indefinitely, so every later caller
would use a bogus offset?
Perhaps the "TX Interface Progression Detection Features" of dwc IP
could help return a dedicated value? I don't know, so I need to check
it internally. I will get back to you later.
> enabled. This matters for endpoint controllers such as qcom-ep and
> tegra194, where DBI is only accessible after PERST# is deasserted, and it
> also means platform drivers do not have to call the helper from a
> specific callback at the right time.
>
> The cached value is accessed with READ_ONCE()/WRITE_ONCE(), because the
> first lookup may be triggered from different contexts, for example the
> qcom-ep global IRQ and PERST# IRQ handlers. A concurrent lookup stores
> the same value, so this race is benign.
>
> A return value of 0 means that the capability is not present. This
> cannot happen on real DWC hardware, where the PCI Express Capability is
> mandatory, so a negative result is not cached separately: it only causes
> the search to be repeated, which does not affect correctness.
>
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---
> drivers/pci/controller/dwc/pcie-designware.h | 34 ++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 0735ae940924..fa31e8b763bc 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -592,6 +592,8 @@ struct dw_pcie {
> * use_parent_dt_ranges to true to avoid this warning.
> */
> bool use_parent_dt_ranges;
> +
> + u8 pcie_cap; /* Offset of PCI_CAP_ID_EXP */
> };
>
> #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
> @@ -830,6 +832,38 @@ 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 the PCIe Capability offset
> + * @pci: DWC instance
> + *
> + * The offset of the PCI Express Capability structure is read once from
> + * the DBI configuration space on the first call and cached in
> + * @pci->pcie_cap for the subsequent ones.
> + *
> + * The lookup is done lazily at the first place that actually needs the
> + * offset, so the DBI read happens exactly when it used to happen before
> + * caching was introduced, i.e. never before the controller's clocks,
> + * resets and power are enabled.
> + *
> + * DWC PCIe controllers always implement the PCI Express Capability, so a
> + * return value of 0 means that the hardware is not usable. Callers that
> + * check the returned offset keep working, and the (never expected)
> + * lookup is simply repeated on the next call.
> + *
> + * Return: the cached offset, or 0 if the capability is not present.
> + */
> +static inline u8 dw_pcie_get_pcie_cap(struct dw_pcie *pci)
> +{
> + u8 cap = READ_ONCE(pci->pcie_cap);
> +
> + if (!cap) {
> + cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> + WRITE_ONCE(pci->pcie_cap, cap);
> + }
> +
> + return cap;
> +}
> +
> static inline int dw_pcie_start_link(struct dw_pcie *pci)
> {
> if (pci->ops && pci->ops->start_link)
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 02/16] PCI: dwc: Use cached PCIe capability offset in core
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
2026-10-27 12:28 ` [PATCH v4 01/16] PCI: dwc: Add pcie_cap field and caching helper Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 03/16] PCI: dwc: imx6: Use cached PCIe capability offset Hans Zhang
` (13 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
Convert the DWC core users of
dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) to dw_pcie_get_pcie_cap():
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()
dw_pcie_ep_init_non_sticky_registers()
These functions are reached in exactly the same situations in which the
replaced dw_pcie_find_capability() call used to be executed, so DBI is
accessible whenever the helper performs its first lookup. Because the
lookup happens at the point of use, there is no window in which
pci->pcie_cap could be used uninitialized, neither in Root Complex nor
in Endpoint mode.
While at it, remove the now redundant capability lookup in
dw_pcie_link_get_max_link_width(): the offset variable it filled is the
one used for the register access.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +-
drivers/pci/controller/dwc/pcie-designware.c | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index de8ee3db4360..b56dbbb29733 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -1265,7 +1265,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);
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 593388f29bdd..bd18415e92da 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -806,7 +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);
+ offset = dw_pcie_get_pcie_cap(pci);
val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
@@ -844,7 +844,7 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci)
{
u32 cap, ctrl2;
enum pci_bus_speed link_speed;
- u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = dw_pcie_get_pcie_cap(pci);
u16 ctrl2_speed;
cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
@@ -879,7 +879,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);
+ u8 cap = dw_pcie_get_pcie_cap(pci);
u32 lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
return FIELD_GET(PCI_EXP_LNKCAP_MLW, lnkcap);
@@ -925,7 +925,7 @@ 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);
+ cap = dw_pcie_get_pcie_cap(pci);
lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
FIELD_MODIFY(PCI_EXP_LNKCAP_MLW, &lnkcap, num_lanes);
dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
--
2.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 03/16] PCI: dwc: imx6: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
2026-10-27 12:28 ` [PATCH v4 01/16] PCI: dwc: Add pcie_cap field and caching helper Hans Zhang
2026-10-27 12:28 ` [PATCH v4 02/16] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 04/16] PCI: dwc: layerscape-ep: " Hans Zhang
` (12 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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 the two dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) calls in
imx_pcie_ltssm_enable() and imx_pcie_start_link() with
dw_pcie_get_pcie_cap().
Both functions run with the controller powered and clocked: they are
reached either from the host .start_link callback or, in Endpoint mode,
after the PERST# deassert path has enabled the resources. The helper
therefore performs the DBI read at the same point as the replaced call
and caches the result for later invocations, which is useful for
suspend/resume where the link is started again.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pci-imx6.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 39790e66b98d..7fe9c1fa2686 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -970,7 +970,7 @@ 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);
+ u8 offset = dw_pcie_get_pcie_cap(imx_pcie->pci);
u32 tmp;
tmp = dw_pcie_readl_dbi(imx_pcie->pci, offset + PCI_EXP_LNKCAP);
@@ -999,7 +999,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 = dw_pcie_get_pcie_cap(pci);
u32 tmp;
int ret;
--
2.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 04/16] PCI: dwc: layerscape-ep: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (2 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 03/16] PCI: dwc: imx6: Use cached PCIe capability offset Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 05/16] PCI: dwc: meson: " Hans Zhang
` (11 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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, Frank Li
Replace the dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) calls in
ls_pcie_ep_probe() and ls_pcie_ep_event_handler() with
dw_pcie_get_pcie_cap().
The probe reads the Link Capabilities register to save the values
configured by the Reset Configuration Word anyway, so the offset is
cached there. The link down event handler runs in hardirq context and
can then simply reuse the cached value instead of walking the
capability list every time the link goes down.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pci-layerscape-ep.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
index 527c57114dcf..113be247b01b 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
@@ -268,7 +268,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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 05/16] PCI: dwc: meson: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (3 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 04/16] PCI: dwc: layerscape-ep: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 06/16] PCI: dwc: rockchip: " Hans Zhang
` (10 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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 the dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) calls in
meson_set_max_payload() and meson_set_max_rd_req_size() with
dw_pcie_get_pcie_cap() and store the offset in a u8, which is the type
used everywhere else for a capability offset.
Both functions are called from meson_pcie_host_init(), which runs after
the controller clocks and resets have been enabled, so the first lookup
happens exactly where the open coded search used to happen.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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 8559d132dcde..03dd1282f3f3 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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 06/16] PCI: dwc: rockchip: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (4 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 05/16] PCI: dwc: meson: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:36 ` Shawn Lin
2026-10-27 12:28 ` [PATCH v4 07/16] PCI: dwc: eswin: " Hans Zhang
` (9 subsequent siblings)
15 siblings, 1 reply; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
rockchip_pcie_enable_l0s() is called from rockchip_pcie_host_init(),
i.e. from the .init callback, which runs after the controller clocks and
resets have been enabled. Replace the capability search with
dw_pcie_get_pcie_cap(), which reads and caches the offset at this very
point.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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 af26a07c0c9e..753606193855 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -373,7 +373,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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 06/16] PCI: dwc: rockchip: Use cached PCIe capability offset
2026-10-27 12:28 ` [PATCH v4 06/16] PCI: dwc: rockchip: " Hans Zhang
@ 2026-10-27 12:36 ` Shawn Lin
0 siblings, 0 replies; 19+ messages in thread
From: Shawn Lin @ 2026-10-27 12:36 UTC (permalink / raw)
To: Hans Zhang, bhelgaas, lpieralisi, kwilczynski, mani, jingoohan1
Cc: shawn.lin, imx, linuxppc-dev, linux-amlogic, linux-rockchip,
linux-arm-msm, sophgo, linux-riscv, spacemit, linux-tegra,
linux-pci, linux-kernel
在 2026/10/27 星期二 20:28, Hans Zhang 写道:
> rockchip_pcie_enable_l0s() is called from rockchip_pcie_host_init(),
> i.e. from the .init callback, which runs after the controller clocks and
> resets have been enabled. Replace the capability search with
> dw_pcie_get_pcie_cap(), which reads and caches the offset at this very
> point.
>
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---
> 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 af26a07c0c9e..753606193855 100644
> --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
> @@ -373,7 +373,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;
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 07/16] PCI: dwc: eswin: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (5 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 06/16] PCI: dwc: rockchip: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 08/16] PCI: dwc: fu740: " Hans Zhang
` (8 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
eswin_pcie_link_up() is the .link_up callback, so it is called on every
link state poll. Replace the dw_pcie_find_capability() call with
dw_pcie_get_pcie_cap() so that the capability list is walked only once,
and store the offset in a u8 as everywhere else.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-eswin.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-eswin.c b/drivers/pci/controller/dwc/pcie-eswin.c
index ce8d64f8a395..3d3275237f3f 100644
--- a/drivers/pci/controller/dwc/pcie-eswin.c
+++ b/drivers/pci/controller/dwc/pcie-eswin.c
@@ -84,7 +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);
+ u8 offset = dw_pcie_get_pcie_cap(pci);
u16 val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
return val & PCI_EXP_LNKSTA_DLLLA;
--
2.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 08/16] PCI: dwc: fu740: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (6 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 07/16] PCI: dwc: eswin: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 09/16] PCI: dwc: intel-gw: " Hans Zhang
` (7 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
fu740_pcie_start_link() is the .start_link callback. It runs after the
controller has been powered up, so replace the capability search with
dw_pcie_get_pcie_cap() to cache the offset.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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..61e2daa20b19 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 = dw_pcie_get_pcie_cap(pci);
int ret;
u32 orig, tmp;
--
2.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 09/16] PCI: dwc: intel-gw: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (7 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 08/16] PCI: dwc: fu740: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 10/16] PCI: dwc: qcom-ep: " Hans Zhang
` (6 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
intel_pcie_link_setup() is called from intel_pcie_host_setup(), which
runs from the .init callback after the controller resources have been
enabled. Replace the capability search with dw_pcie_get_pcie_cap().
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 10/16] PCI: dwc: qcom-ep: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (8 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 09/16] PCI: dwc: intel-gw: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 11/16] PCI: dwc: qcom: " Hans Zhang
` (5 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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 the three dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) calls in
the qcom-ep driver with dw_pcie_get_pcie_cap().
qcom_pcie_perst_deassert() is the point where the controller resources
have just been enabled and DBI becomes accessible, so the offset is
looked up and cached there. Both the L0s and the L1 exit latency are
then programmed using that same cached offset instead of walking the
capability list again.
qcom_pcie_ep_icc_update() may run from the global IRQ handler, which is
requested before the PERST# IRQ. The helper performs its lookup at that
point of use, i.e. exactly where the open coded search happened before,
so this change neither adds nor moves a DBI access and does not
introduce a new race with the PERST# handler.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-qcom-ep.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c
index 56184e6ca6e6..413a1582f300 100644
--- a/drivers/pci/controller/dwc/pcie-qcom-ep.c
+++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c
@@ -307,14 +307,15 @@ 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;
+ u8 offset;
+ u32 status;
int speed, width;
int ret;
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);
@@ -397,7 +398,8 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci)
{
struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci);
struct device *dev = pci->dev;
- u32 val, offset;
+ u32 val;
+ u8 offset;
int ret;
ret = pm_runtime_resume_and_get(dev);
@@ -492,13 +494,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 = dw_pcie_get_pcie_cap(pci);
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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 11/16] PCI: dwc: qcom: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (9 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 10/16] PCI: dwc: qcom-ep: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 12/16] PCI: dwc: sophgo: " Hans Zhang
` (4 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
Convert the dw_pcie_find_capability(pci, PCI_CAP_ID_EXP) users in the
Qualcomm host driver to dw_pcie_get_pcie_cap():
qcom_pcie_clear_aspm_l0s()
qcom_pcie_set_slot_cap()
qcom_pcie_post_init_2_3_3()
qcom_pcie_post_init_2_9_0()
qcom_pcie_link_up()
qcom_pcie_icc_opp_update()
Note that the .post_init callbacks of struct qcom_pcie_ops run from
qcom_pcie_host_init() before qcom_pcie_clear_aspm_l0s(), so relying on
that function to populate the cache would have left the offset
uninitialized for them. Doing the lazy lookup inside each function
makes the ordering irrelevant: the capability is searched exactly where
the register is accessed, i.e. where the open coded
dw_pcie_find_capability() call used to be, and every one of these paths
runs after qcom_pcie_init_*() has enabled clocks, resets and power.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-qcom.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index b58a607b713f..cec36c989a88 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -359,13 +359,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);
@@ -378,7 +378,7 @@ static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci)
static void qcom_pcie_set_slot_cap(struct dw_pcie *pci)
{
- u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u8 offset = dw_pcie_get_pcie_cap(pci);
u32 val;
dw_pcie_dbi_ro_wr_en(pci);
@@ -959,7 +959,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 = dw_pcie_get_pcie_cap(pci);
u32 val;
/* Force PHY out of lowest power state */
@@ -1281,7 +1281,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 = dw_pcie_get_pcie_cap(pci);
u32 val;
int i;
@@ -1327,7 +1327,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);
+ u8 offset = dw_pcie_get_pcie_cap(pci);
u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
return val & PCI_EXP_LNKSTA_DLLLA;
@@ -1690,14 +1690,15 @@ 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;
+ u8 offset;
+ 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);
+ offset = dw_pcie_get_pcie_cap(pci);
status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
/* Only update constraints if link is up. */
--
2.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 12/16] PCI: dwc: sophgo: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (10 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 11/16] PCI: dwc: qcom: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 13/16] PCI: dwc: spacemit-k1: " Hans Zhang
` (3 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
sophgo_pcie_disable_l0s_l1() runs from the .init callback with the
controller already enabled. Replace the capability search with
dw_pcie_get_pcie_cap() and store the offset in a u8.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 13/16] PCI: dwc: spacemit-k1: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (11 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 12/16] PCI: dwc: sophgo: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 14/16] PCI: dwc: spear13xx: " Hans Zhang
` (2 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
k1_pcie_disable_aspm_l1() runs from the .init callback with the
controller already enabled. Replace the capability search with
dw_pcie_get_pcie_cap().
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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 0564c46e2f48..a22a6d4dd2e5 100644
--- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
+++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
@@ -113,7 +113,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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 14/16] PCI: dwc: spear13xx: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (12 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 13/16] PCI: dwc: spacemit-k1: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 15/16] PCI: dwc: tegra194: " Hans Zhang
2026-10-27 12:28 ` [PATCH v4 16/16] PCI: dwc: ultrarisc: " Hans Zhang
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
spear13xx_pcie_host_init() runs from the .init callback with the
controller already enabled. Replace the capability search with
dw_pcie_get_pcie_cap() and store the offset in a u8.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 15/16] PCI: dwc: tegra194: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (13 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 14/16] PCI: dwc: spear13xx: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
2026-10-27 12:28 ` [PATCH v4 16/16] PCI: dwc: ultrarisc: " Hans Zhang
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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 the two dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP)
calls in tegra_pcie_dw_host_init() and pex_ep_event_pex_rst_deassert()
with dw_pcie_get_pcie_cap() so that the driver-private pcie_cap_base is
filled from the same cached value.
tegra_pcie_dw_host_init() is called from .start_link, i.e. after the
controller has been initialized, and the PERST# deassert handler runs
after the endpoint has been brought out of reset with its clocks and
power enabled. The helper therefore performs its single DBI read at the
same point as the open coded search, and the private copy keeps working
unchanged.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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 63a0f56cad8e..965e15f55e22 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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v4 16/16] PCI: dwc: ultrarisc: Use cached PCIe capability offset
2026-10-27 12:28 [PATCH v4 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
` (14 preceding siblings ...)
2026-10-27 12:28 ` [PATCH v4 15/16] PCI: dwc: tegra194: " Hans Zhang
@ 2026-10-27 12:28 ` Hans Zhang
15 siblings, 0 replies; 19+ messages in thread
From: Hans Zhang @ 2026-10-27 12:28 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
ultrarisc_pcie_host_init() runs from the .init callback with the
controller already enabled. Replace the capability search with
dw_pcie_get_pcie_cap(). Since the lookup is performed lazily at the
point of use, the driver no longer depends on any earlier caching step
and the offset is always valid here.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
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 51e89180490d..85373b479b64 100644
--- a/drivers/pci/controller/dwc/pcie-ultrarisc.c
+++ b/drivers/pci/controller/dwc/pcie-ultrarisc.c
@@ -56,7 +56,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.43.0
_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic
^ permalink raw reply [flat|nested] 19+ messages in thread