diff options
author | Jonathan Zhang <jonzhang@meta.com> | 2022-10-10 16:27:48 -0700 |
---|---|---|
committer | Martin L Roth <gaumless@gmail.com> | 2022-11-20 17:37:09 +0000 |
commit | 1864f12fdaa62a042341180d7438e2b5daaa0904 (patch) | |
tree | 2b8fea5a518d0635048a0b846d5836517bed77d3 /src | |
parent | 3dcafa8774f215e75b2d13157c1431339e33146c (diff) |
device/pciexp: add pcie_find_dsn()
Add pcie_find_dsn() to detect and match PCIe device serial
number. In addition, vendor ID is matched when provided.
Change-Id: I54b6dc42c8da47cd7b4447ab23a6a21562c7618
Signed-off-by: Jonathan Zhang <jonzhang@meta.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/54510
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Marc Jones <marc@marcjonesconsulting.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/device/pciexp_device.c | 51 | ||||
-rw-r--r-- | src/include/device/pciexp.h | 3 |
2 files changed, 54 insertions, 0 deletions
diff --git a/src/device/pciexp_device.c b/src/device/pciexp_device.c index b03089b8f6..c9441fb22e 100644 --- a/src/device/pciexp_device.c +++ b/src/device/pciexp_device.c @@ -93,6 +93,57 @@ unsigned int pciexp_find_ext_vendor_cap(const struct device *dev, unsigned int c } } +/** + * Find a PCIe device with a given serial number, and a given VID if applicable + * + * @param serial The serial number of the device. + * @param vid Vendor ID of the device, may be 0 if not applicable. + * @param from Pointer to the device structure, used as a starting point in + * the linked list of all_devices, which can be 0 to start at the + * head of the list (i.e. all_devices). + * @return Pointer to the device struct. + */ +struct device *pcie_find_dsn(const uint64_t serial, const uint16_t vid, + struct device *from) +{ + union dsn { + struct { + uint32_t dsn_low; + uint32_t dsn_high; + }; + uint64_t dsn; + } dsn; + unsigned int cap; + uint16_t vendor_id; + + if (!from) + from = all_devices; + else + from = from->next; + + while (from) { + if (from->path.type == DEVICE_PATH_PCI) { + cap = pciexp_find_extended_cap(from, PCI_EXT_CAP_ID_DSN, 0); + /* + * For PCIe device, find extended capability for serial number. + * The capability header is 4 bytes, followed by lower 4 bytes + * of serial number, then higher 4 byes of serial number. + */ + if (cap != 0) { + dsn.dsn_low = pci_read_config32(from, cap + 4); + dsn.dsn_high = pci_read_config32(from, cap + 8); + vendor_id = pci_read_config16(from, PCI_VENDOR_ID); + if ((dsn.dsn == serial) && (vid == 0 || vendor_id == vid)) + return from; + } + } + + from = from->next; + } + + return from; +} + /* * Re-train a PCIe link */ diff --git a/src/include/device/pciexp.h b/src/include/device/pciexp.h index d8162405ad..9f9c28ecb5 100644 --- a/src/include/device/pciexp.h +++ b/src/include/device/pciexp.h @@ -44,6 +44,9 @@ static inline bool pciexp_is_downstream_port(int type) type == PCI_EXP_TYPE_PCIE_BRIDGE; } +struct device *pcie_find_dsn(const uint64_t serial, const uint16_t vid, + struct device *from); + bool pciexp_get_ltr_max_latencies(struct device *dev, u16 *max_snoop, u16 *max_nosnoop); #endif /* DEVICE_PCIEXP_H */ |