diff options
author | Bill XIE <persmule@hardenedlinux.org> | 2022-08-02 22:55:51 +0800 |
---|---|---|
committer | Martin L Roth <gaumless@gmail.com> | 2022-08-07 19:41:38 +0000 |
commit | 513d359dad3a99c13846f4e97b372ec98d245695 (patch) | |
tree | 7cbd42b71dde4c9908bd69058e816bd685f9beab | |
parent | a43380e3d5637b5d2e23b001a5c2519696a21c5d (diff) |
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>
-rw-r--r-- | src/device/pci_device.c | 24 | ||||
-rw-r--r-- | src/include/device/pci.h | 1 |
2 files changed, 25 insertions, 0 deletions
diff --git a/src/device/pci_device.c b/src/device/pci_device.c index fda088b020..44c47a7548 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 @@ unsigned int pci_match_simple_dev(struct device *dev, pci_devfn_t sdev) } /** + * 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 diff --git a/src/include/device/pci.h b/src/include/device/pci.h index f2e250631e..f28f319d8c 100644 --- a/src/include/device/pci.h +++ b/src/include/device/pci.h @@ -97,6 +97,7 @@ void pci_dev_set_subsystem(struct device *dev, unsigned int vendor, unsigned int device); void pci_dev_init(struct device *dev); unsigned int pci_match_simple_dev(struct device *dev, pci_devfn_t sdev); +uint16_t pci_find_cap_recursive(const struct device *dev, uint16_t cap); const char *pin_to_str(int pin); int get_pci_irq_pins(struct device *dev, struct device **parent_bdg); |