From 3d121ae1a16751d55006c9b907a283f03c639197 Mon Sep 17 00:00:00 2001 From: Tim Wawrzynczak Date: Thu, 16 Sep 2021 20:18:16 -0600 Subject: [PATCH] device: Add pciexp_find_next_extended_cap function Some PCIe devices have extended capability lists that contain multiples instances of the same capability. This patch provides a function similar to pciexp_find_extended_cap that can be used to search through multiple instances of the same capability by returning the offset of the next extended capability of the given type following the passed-in offset. The base functionality of searching for a given capability from an offset is extracted to a local helper function and both pciexp_find_extended_cap and pciexp_find_next_extended_cap use this helper. Change-Id: Ie68dc26012ba57650484c4f2ff53cc694a5347aa Signed-off-by: Tim Wawrzynczak Reviewed-on: https://review.coreboot.org/c/coreboot/+/57784 Tested-by: build bot (Jenkins) Reviewed-by: Karthik Ramasubramanian Reviewed-by: Nick Vaccaro --- src/device/pciexp_device.c | 32 +++++++++++++++++++++----------- src/include/device/pciexp.h | 2 ++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/device/pciexp_device.c b/src/device/pciexp_device.c index e0b3544874..c52530196d 100644 --- a/src/device/pciexp_device.c +++ b/src/device/pciexp_device.c @@ -8,29 +8,39 @@ #include #include -unsigned int pciexp_find_extended_cap(const struct device *dev, unsigned int cap) +static unsigned int pciexp_get_ext_cap_offset(const struct device *dev, unsigned int cap, + unsigned int offset) { - unsigned int this_cap_offset, next_cap_offset; - unsigned int this_cap, cafe; - - this_cap_offset = PCIE_EXT_CAP_OFFSET; + unsigned int this_cap_offset = offset; + unsigned int next_cap_offset, this_cap, cafe; do { this_cap = pci_read_config32(dev, this_cap_offset); - next_cap_offset = this_cap >> 20; - this_cap &= 0xffff; cafe = pci_read_config32(dev, this_cap_offset + 4); - cafe &= 0xffff; - if (this_cap == cap) + if ((this_cap & 0xffff) == cap) { return this_cap_offset; - else if (cafe == cap) + } else if ((cafe & 0xffff) == cap) { return this_cap_offset + 4; - else + } else { + next_cap_offset = this_cap >> 20; this_cap_offset = next_cap_offset; + } } while (next_cap_offset != 0); return 0; } +unsigned int pciexp_find_next_extended_cap(const struct device *dev, unsigned int cap, + unsigned int pos) +{ + const unsigned int next_cap_offset = pci_read_config32(dev, pos) >> 20; + return pciexp_get_ext_cap_offset(dev, cap, next_cap_offset); +} + +unsigned int pciexp_find_extended_cap(const struct device *dev, unsigned int cap) +{ + return pciexp_get_ext_cap_offset(dev, cap, PCIE_EXT_CAP_OFFSET); +} + /* * Re-train a PCIe link */ diff --git a/src/include/device/pciexp.h b/src/include/device/pciexp.h index a72c2ec2a9..30c2a54620 100644 --- a/src/include/device/pciexp.h +++ b/src/include/device/pciexp.h @@ -31,6 +31,8 @@ void pciexp_hotplug_scan_bridge(struct device *dev); extern struct device_operations default_pciexp_hotplug_ops_bus; unsigned int pciexp_find_extended_cap(const struct device *dev, unsigned int cap); +unsigned int pciexp_find_next_extended_cap(const struct device *dev, unsigned int cap, + unsigned int offset); static inline bool pciexp_is_downstream_port(int type) {