summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Wawrzynczak <twawrzynczak@chromium.org>2020-05-13 16:15:08 -0600
committerPatrick Georgi <pgeorgi@google.com>2020-05-20 09:47:35 +0000
commitdbcf7b16219df0c04401b8fcd6a780174a7df305 (patch)
tree0ab8141306f5c7a7135337fc899f704ac825e5d0
parent17118a833a2df130ed24c2547ca903cac9fac0e0 (diff)
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> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41384 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Furquan Shaikh <furquan@google.com>
-rw-r--r--src/device/pci_device.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index 689325d2a9..5f50a31460 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -778,6 +778,13 @@ struct device_operations default_pci_ops_bus = {
.reset_bus = pci_bus_reset,
};
+/** Default device operations for PCI devices marked 'hidden' */
+static struct device_operations default_hidden_pci_ops_dev = {
+ .read_resources = noop_read_resources,
+ .set_resources = noop_set_resources,
+ .scan_bus = scan_static_bus,
+};
+
/**
* Check for compatibility to route legacy VGA cycles through a bridge.
*
@@ -1147,6 +1154,46 @@ unsigned int pci_match_simple_dev(struct device *dev, pci_devfn_t sdev)
}
/**
+ * 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
+ * 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 expected semantics of PCI devices marked as 'hidden':
+ * 1) The device is actually present under the specified BDF
+ * 2) The device config space can still be accessed somehow, but the Vendor ID
+ * indicates there is no device there (it reads as 0xffffffff).
+ * 3) The device may still consume PCI resources. Typically, these would have
+ * been hardcoded elsewhere.
+ *
+ * @param dev Pointer to the device structure.
+ */
+static void pci_scan_hidden_device(struct device *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. However, children may want to
+ * be enumerated, so this provides scan_static_bus for the .scan_bus
+ * callback.
+ */
+ if (dev->ops == NULL)
+ dev->ops = &default_hidden_pci_ops_dev;
+
+ if (dev->ops->enable)
+ dev->ops->enable(dev);
+
+ /* Display the device almost as if it were probed normally */
+ printk(BIOS_DEBUG, "%s [0000/%04x] hidden%s\n", dev_path(dev),
+ dev->device, dev->ops ? "" : " No operations");
+}
+
+/**
* Scan a PCI bus.
*
* Determine the existence of devices and bridges on a PCI bus. If there are
@@ -1190,6 +1237,14 @@ void pci_scan_bus(struct bus *bus, unsigned int min_devfn,
/* First thing setup the device structure. */
dev = pci_scan_get_dev(bus, devfn);
+ /* Devices marked 'hidden' do not get probed */
+ if (dev && dev->hidden) {
+ pci_scan_hidden_device(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);
@@ -1213,8 +1268,12 @@ void pci_scan_bus(struct bus *bus, unsigned int min_devfn,
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;
}