summaryrefslogtreecommitdiff
path: root/src/device
diff options
context:
space:
mode:
authorNico Huber <nico.h@gmx.de>2022-08-05 13:02:52 +0200
committerFelix Held <felix-coreboot@felixheld.de>2022-08-17 16:29:39 +0000
commit9099feaa94670af2dd558de35b74452570452028 (patch)
treea10e50cee146747362bce93800f985a397263d26 /src/device
parent5ffc2c8a3f38fbb7be2faadf207590acd3999205 (diff)
pciexp_device: Introduce pciexp_find_ext_vendor_cap()
Vendors can choose to add non-standard capabilities inside a Vendor-Specific Extended Capability. These are identified by the Extended Capability ID 0x0b. Change-Id: Idd6dd0e98bd53b19077afdd4c402114578bec966 Signed-off-by: Nico Huber <nico.h@gmx.de> Reviewed-on: https://review.coreboot.org/c/coreboot/+/66454 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Diffstat (limited to 'src/device')
-rw-r--r--src/device/pciexp_device.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/src/device/pciexp_device.c b/src/device/pciexp_device.c
index ea0ec1a39b..bc4012503a 100644
--- a/src/device/pciexp_device.c
+++ b/src/device/pciexp_device.c
@@ -55,6 +55,35 @@ unsigned int pciexp_find_extended_cap(const struct device *dev, unsigned int cap
return pciexp_get_ext_cap_offset(dev, cap, next_cap_offset);
}
+/*
+ * Search for a vendor-specific extended capability,
+ * with the vendor-specific ID `cap`.
+ *
+ * Returns the offset of the vendor-specific header,
+ * i.e. the offset of the extended capability + 4,
+ * or 0 if none is found.
+ *
+ * A new search is started with `offset == 0`.
+ * To continue a search, the prior return value
+ * should be passed as `offset`.
+ */
+unsigned int pciexp_find_ext_vendor_cap(const struct device *dev, unsigned int cap,
+ unsigned int offset)
+{
+ /* Reconstruct capability offset from vendor-specific header offset. */
+ if (offset >= 4)
+ offset -= 4;
+
+ for (;;) {
+ offset = pciexp_find_extended_cap(dev, PCI_EXT_CAP_ID_VNDR, offset);
+ if (!offset)
+ return 0;
+
+ const unsigned int vndr_cap = pci_read_config32(dev, offset + 4);
+ if ((vndr_cap & 0xffff) == cap)
+ return offset + 4;
+ }
+}
/*
* Re-train a PCIe link