summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Zhang <jonzhang@meta.com>2022-10-10 16:27:48 -0700
committerMartin L Roth <gaumless@gmail.com>2022-11-20 17:37:09 +0000
commit1864f12fdaa62a042341180d7438e2b5daaa0904 (patch)
tree2b8fea5a518d0635048a0b846d5836517bed77d3 /src
parent3dcafa8774f215e75b2d13157c1431339e33146c (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.c51
-rw-r--r--src/include/device/pciexp.h3
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 */