Tim Wawrzynczak has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/41384 )
Change subject: device/pci_device: Add notion of "hidden" PCI devices ......................................................................
device/pci_device: Add notion of "hidden" PCI devices
On some SoCs, there are PCI devices that may get hidden from PCI enumeration by platform firmware. Because the Vendor ID reads back as 0xffffffff, it appears that there is no PCI device located at that BDF. However, because the device does exist, designers may wish to hang its PCI resources off of a real __pci_driver, as well as have it participate in ACPI table generation.
This patch extends the semantics of the 'hidden' keyword in devicetree.cb. If a device now uses 'hidden' instead of 'on', then it will be assumed during PCI enumeration that the device indeed does exist, and it will not be removed as a "leftover device." This allows child devices to be enumerated correctly and also PCI resources can be designated from the {read,set}_resources callbacks.
It should be noted that as of this commit, there are precisely 0 devices using 'hidden' in their devicetree.cb files, so this should be a safe thing to do.
Later patches will begin moving PCI resources from random places (typically hung off of fixed SA and LPC) into the PMC device (procedure will vary per- platform).
Change-Id: I16c2d3e1d1433343e63dfc16856cff69cd815e2a Signed-off-by: Tim Wawrzynczak twawrzynczak@chromium.org --- M src/device/pci_device.c 1 file changed, 57 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/84/41384/1
diff --git a/src/device/pci_device.c b/src/device/pci_device.c index 0584871..6350e29 100644 --- a/src/device/pci_device.c +++ b/src/device/pci_device.c @@ -783,6 +783,18 @@ .ops_pci = &pci_bus_ops_pci, };
+/** Default device operations for hidden PCI devices */ +static struct pci_operations hidden_pci_dev_ops = { + .set_subsystem = 0, +}; + +static struct device_operations default_hidden_pci_ops_dev = { + .read_resources = noop_read_resources, + .set_resources = noop_set_resources, + .scan_bus = scan_static_bus, + .ops_pci = &hidden_pci_dev_ops, +}; + /** * Check for compatibility to route legacy VGA cycles through a bridge. * @@ -1195,6 +1207,45 @@ /* First thing setup the device structure. */ dev = pci_scan_get_dev(bus, devfn);
+ /* + * 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 static PCI resources to the allocator, but the + * platform firmware hides the device (makes the device + * invisible to PCI enumeration) before PCI enumeration takes + * place. + * + * The semantics of hidden devices: + * 1) The device is actually present under the specified BDF + * 2) The device has an RO config space and returns its Vendor + * ID as if there were no device there (0xffffffff). + * 3) The device may still consume PCI resources. Typically, + * these would have been hardcoded elsewhere. + */ + if (dev && dev->hidden) { + /* This would normally be run from pci_probe_dev() */ + if (dev->chip_ops && dev->chip_ops->enable_dev) + dev->chip_ops->enable_dev(dev); + + /* + * If chip_ops->enable_dev did not set dev->ops, then + * set to a default .ops, because PCI enumeration is + * effectively being skipped, therefore no PCI driver + * will bind to this device. + */ + if (dev->ops == NULL) + dev->ops = &default_hidden_pci_ops_dev; + + /* This would normally be run from pci_probe_dev() */ + if (dev->ops->enable) + dev->ops->enable(dev); + + /* Skip pci_probe_dev, go to next devfn */ + continue; + } + /* See if a device is present and setup the device structure. */ dev = pci_probe_dev(dev, bus, devfn);
@@ -1218,8 +1269,12 @@
prev = &bus->children; for (dev = bus->children; dev; dev = dev->sibling) { - /* If we read valid vendor id, it is not leftover device. */ - if (dev->vendor != 0) { + /* + * The device is only considered leftover if it is not hidden + * and it has a Vendor ID of 0 (the default for a device that + * could not be probed). + */ + if (dev->vendor != 0 || dev->hidden) { prev = &dev->sibling; continue; }