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 <twawrzynczak@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/57784
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
Reviewed-by: Nick Vaccaro <nvaccaro@google.com>
This commit is contained in:
Tim Wawrzynczak 2021-09-16 20:18:16 -06:00 committed by Felix Held
parent 49be1a9346
commit 3d121ae1a1
2 changed files with 23 additions and 11 deletions

View File

@ -8,29 +8,39 @@
#include <device/pci_ops.h> #include <device/pci_ops.h>
#include <device/pciexp.h> #include <device/pciexp.h>
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_offset = offset;
unsigned int this_cap, cafe; unsigned int next_cap_offset, this_cap, cafe;
this_cap_offset = PCIE_EXT_CAP_OFFSET;
do { do {
this_cap = pci_read_config32(dev, this_cap_offset); 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 = pci_read_config32(dev, this_cap_offset + 4);
cafe &= 0xffff; if ((this_cap & 0xffff) == cap) {
if (this_cap == cap)
return this_cap_offset; return this_cap_offset;
else if (cafe == cap) } else if ((cafe & 0xffff) == cap) {
return this_cap_offset + 4; return this_cap_offset + 4;
else } else {
next_cap_offset = this_cap >> 20;
this_cap_offset = next_cap_offset; this_cap_offset = next_cap_offset;
}
} while (next_cap_offset != 0); } while (next_cap_offset != 0);
return 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 * Re-train a PCIe link
*/ */

View File

@ -31,6 +31,8 @@ void pciexp_hotplug_scan_bridge(struct device *dev);
extern struct device_operations default_pciexp_hotplug_ops_bus; 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_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) static inline bool pciexp_is_downstream_port(int type)
{ {