From: Hans Zhang <18255117159@163.com>
To: bhelgaas@google.com, lpieralisi@kernel.org,
kwilczynski@kernel.org, mani@kernel.org, jingoohan1@gmail.com
Cc: imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
linux-amlogic@lists.infradead.org,
linux-rockchip@lists.infradead.org,
linux-arm-msm@vger.kernel.org, sophgo@lists.linux.dev,
linux-riscv@lists.infradead.org, spacemit@lists.linux.dev,
linux-tegra@vger.kernel.org, linux-pci@vger.kernel.org,
linux-kernel@vger.kernel.org, Hans Zhang <18255117159@163.com>
Subject: [PATCH v5 01/16] PCI: dwc: Add pcie_cap field and caching helper
Date: Wed, 28 Oct 2026 11:06:37 +0800 [thread overview]
Message-ID: <20261028030652.2917756-2-18255117159@163.com> (raw)
In-Reply-To: <20261028030652.2917756-1-18255117159@163.com>
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 the series
does not introduce DBI accesses at points where the controller might not
be accessible. 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.
Reading DBI while the controller is inaccessible (clocks or power gated)
is platform specific: some integrations hang, some return zero and some
return garbage. dw_pcie_find_capability() already rejects offsets below
the standard header, unaligned offsets and entries whose capability ID
does not match, but a transient bogus read could still look valid. To
prevent such a value from being cached for the rest of the lifetime of
the controller, the offset is only cached after the capability ID has
been read back at that offset. If it is not confirmed, the offset is
still returned to the caller for this access but not cached, so the next
call performs the lookup again, just like when the capability is not
found.
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.
Signed-off-by: Hans Zhang <18255117159@163.com>
---
drivers/pci/controller/dwc/pcie-designware.h | 38 ++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 6d788aa000117..dede6b3966585 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -594,6 +594,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)
@@ -832,6 +834,42 @@ 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 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.
+ *
+ * A DBI read issued while the controller is not accessible returns
+ * platform specific data, and a transient bogus value must not stick in
+ * the cache. The offset is therefore only cached once the capability
+ * ID has been read back at that offset. Both the not-found and the
+ * not-confirmed cases leave the cache empty, so the lookup is simply
+ * repeated on the next call.
+ *
+ * Return: the offset of the PCIe Capability, or 0 if it could not be
+ * found or has not been confirmed yet.
+ */
+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);
+ if (cap && dw_pcie_readb_dbi(pci, cap) == 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
next prev parent reply other threads:[~2026-10-28 3:07 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 3:06 [PATCH v5 00/16] PCI: dwc: Cache PCIe capability offset Hans Zhang
2026-10-28 3:06 ` Hans Zhang [this message]
2026-10-28 3:15 ` [PATCH v5 01/16] PCI: dwc: Add pcie_cap field and caching helper sashiko-bot
2026-10-28 3:18 ` Hans Zhang
2026-10-28 3:06 ` [PATCH v5 02/16] PCI: dwc: Use cached PCIe capability offset in core Hans Zhang
2026-10-28 3:06 ` [PATCH v5 03/16] PCI: dwc: imx6: Use cached PCIe capability offset Hans Zhang
2026-10-28 3:06 ` [PATCH v5 04/16] PCI: dwc: layerscape-ep: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 05/16] PCI: dwc: meson: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 06/16] PCI: dwc: rockchip: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 07/16] PCI: dwc: eswin: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 08/16] PCI: dwc: fu740: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 09/16] PCI: dwc: intel-gw: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 10/16] PCI: dwc: qcom-ep: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 11/16] PCI: dwc: qcom: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 12/16] PCI: dwc: sophgo: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 13/16] PCI: dwc: spacemit-k1: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 14/16] PCI: dwc: spear13xx: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 15/16] PCI: dwc: tegra194: " Hans Zhang
2026-10-28 3:06 ` [PATCH v5 16/16] PCI: dwc: ultrarisc: " Hans Zhang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261028030652.2917756-2-18255117159@163.com \
--to=18255117159@163.com \
--cc=bhelgaas@google.com \
--cc=imx@lists.linux.dev \
--cc=jingoohan1@gmail.com \
--cc=kwilczynski@kernel.org \
--cc=linux-amlogic@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=linux-tegra@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=lpieralisi@kernel.org \
--cc=mani@kernel.org \
--cc=sophgo@lists.linux.dev \
--cc=spacemit@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®