pci_device: Add a function to find PCI capability ID recursively

Some PCI capabilities should only be enabled if it is available not
only on a device, but also all bridge upstream of it. Checking only
the device and the bridge just above it may not be enough.

Signed-off-by: Bill XIE <persmule@hardenedlinux.org>
Change-Id: I1237d3b4b86dd0ae5eb586e3c3c407362e6ca291
Reviewed-on: https://review.coreboot.org/c/coreboot/+/66383
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index fda088b..44c47a7 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -6,6 +6,7 @@
  */
 
 #include <acpi/acpi.h>
+#include <assert.h>
 #include <device/pci_ops.h>
 #include <bootmode.h>
 #include <console/console.h>
@@ -1299,6 +1300,29 @@
 }
 
 /**
+ * Test whether a capability is available along the whole path from the given
+ * device to the host bridge.
+ *
+ * @param dev Pointer to the device structure.
+ * @param cap PCI_CAP_LIST_ID of the PCI capability we're looking for.
+ * @return The next matching capability of the given device, if it is available
+ * along the whole path, or zero if not.
+ */
+uint16_t pci_find_cap_recursive(const struct device *dev, uint16_t cap)
+{
+	assert(dev->bus);
+	uint16_t pos = pci_find_capability(dev, cap);
+	const struct device *bridge = dev->bus->dev;
+	while (bridge && (bridge->path.type == DEVICE_PATH_PCI)) {
+		assert(bridge->bus);
+		if (!pci_find_capability(bridge, cap))
+			return 0;
+		bridge = bridge->bus->dev;
+	}
+	return pos;
+}
+
+/**
  * PCI devices that are marked as "hidden" do not get probed. However, the same
  * initialization logic is still performed as if it were. This is useful when
  * devices would like to be described in the devicetree.cb file, and/or present