diff options
author | Nico Huber <nico.h@gmx.de> | 2022-08-05 13:02:52 +0200 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2022-08-17 16:29:39 +0000 |
commit | 9099feaa94670af2dd558de35b74452570452028 (patch) | |
tree | a10e50cee146747362bce93800f985a397263d26 /src | |
parent | 5ffc2c8a3f38fbb7be2faadf207590acd3999205 (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')
-rw-r--r-- | src/device/pciexp_device.c | 29 | ||||
-rw-r--r-- | src/include/device/pci_def.h | 1 | ||||
-rw-r--r-- | src/include/device/pciexp.h | 2 |
3 files changed, 32 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 diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h index fa520674a8..0eedd513b2 100644 --- a/src/include/device/pci_def.h +++ b/src/include/device/pci_def.h @@ -460,6 +460,7 @@ #define PCI_EXT_CAP_ID_VC 2 #define PCI_EXT_CAP_ID_DSN 3 #define PCI_EXT_CAP_ID_PWR 4 +#define PCI_EXT_CAP_ID_VNDR 0x0b /* Extended Capability lists*/ #define PCIE_EXT_CAP_OFFSET 0x100 diff --git a/src/include/device/pciexp.h b/src/include/device/pciexp.h index 5a996834d2..d8162405ad 100644 --- a/src/include/device/pciexp.h +++ b/src/include/device/pciexp.h @@ -34,6 +34,8 @@ extern struct device_operations default_pciexp_hotplug_ops_bus; unsigned int pciexp_find_extended_cap(const struct device *dev, unsigned int cap, unsigned int offset); +unsigned int pciexp_find_ext_vendor_cap(const struct device *dev, unsigned int cap, + unsigned int offset); static inline bool pciexp_is_downstream_port(int type) { |