pciexp_device: Propagate above-4G flag to all hotplug devices

The `IORESOURCE_ABOVE_4G` flag was only explicitly set for our dummy
device that reserves resources behind a hotplug port. The current re-
source allocator implicitly extends this to all devices below the port,
including real ones. Let's make that explicit, so future changes to the
allocator can't break this rule.

Change-Id: Id4c90b60682cf5c8949cde25362d286625b3e953
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/66719
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Eric Lai <eric_lai@quanta.corp-partner.google.com>
diff --git a/src/device/device_util.c b/src/device/device_util.c
index 8097484..45dbccc 100644
--- a/src/device/device_util.c
+++ b/src/device/device_util.c
@@ -5,6 +5,7 @@
 #include <device/path.h>
 #include <device/pci_def.h>
 #include <device/resource.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -939,6 +940,15 @@
 	return type_name;
 }
 
+bool dev_path_hotplug(const struct device *dev)
+{
+	for (dev = dev->bus->dev; dev != dev->bus->dev; dev = dev->bus->dev) {
+		if (dev->hotplug_port)
+			return true;
+	}
+	return false;
+}
+
 void log_resource(const char *type, const struct device *dev, const struct resource *res,
 			const char *srcfile, const int line)
 {
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index 232328d..52107f2f 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -164,8 +164,12 @@
 		/* A Memory mapped base address. */
 		attr &= PCI_BASE_ADDRESS_MEM_ATTR_MASK;
 		resource->flags |= IORESOURCE_MEM;
-		if (attr & PCI_BASE_ADDRESS_MEM_PREFETCH)
+		if (attr & PCI_BASE_ADDRESS_MEM_PREFETCH) {
 			resource->flags |= IORESOURCE_PREFETCH;
+			if (CONFIG(PCIEXP_HOTPLUG_PREFETCH_MEM_ABOVE_4G)
+			    && dev_path_hotplug(dev))
+				resource->flags |= IORESOURCE_ABOVE_4G;
+		}
 		attr &= PCI_BASE_ADDRESS_MEM_LIMIT_MASK;
 		if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_32) {
 			/* 32bit limit. */
diff --git a/src/device/pciexp_device.c b/src/device/pciexp_device.c
index c8ac391..6023497 100644
--- a/src/device/pciexp_device.c
+++ b/src/device/pciexp_device.c
@@ -646,6 +646,7 @@
 
 void pciexp_hotplug_scan_bridge(struct device *dev)
 {
+	dev->hotplug_port = 1;
 	dev->hotplug_buses = CONFIG_PCIEXP_HOTPLUG_BUSES;
 
 	/* Normal PCIe Scan */
diff --git a/src/include/device/device.h b/src/include/device/device.h
index 43ac66d..cd08f1d 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -128,6 +128,7 @@
 	unsigned int    hidden : 1;
 	/* set if this device is used even in minimum PCI cases */
 	unsigned int    mandatory : 1;
+	unsigned int	hotplug_port : 1;
 	u8 command;
 	uint16_t hotplug_buses; /* Number of hotplug buses to allocate */
 
@@ -207,6 +208,9 @@
 bool is_dev_enabled(const struct device *const dev);
 bool is_devfn_enabled(unsigned int devfn);
 
+/* Returns whether there is a hotplug port on the path to the given device. */
+extern bool dev_path_hotplug(const struct device *);
+
 /* Option ROM helper functions */
 void run_bios(struct device *dev, unsigned long addr);