git: 055c1fe230ce - main - acpi: Allow child drivers to use bus_set_resource for more resources

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 14 Feb 2024 22:52:43 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=055c1fe230ce5a2997c03a3cc2431baea1594566

commit 055c1fe230ce5a2997c03a3cc2431baea1594566
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-02-14 22:07:32 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-02-14 22:07:32 +0000

    acpi: Allow child drivers to use bus_set_resource for more resources
    
    acpi_set_resource excludes certain types of resources for certain
    devices.  The intention of this is to avoid adding resource entries
    for bogus resources enumerated via _CRS.  However, this also prevents
    drivers from adding those resources explicitly if needed.  To fix
    this, move the logic to exclude these resources into an ignore hook
    used when parsing _CRS to create the initial set of resources for each
    device.
    
    Reviewed by:    imp
    Differential Revision:  https://reviews.freebsd.org/D43892
---
 sys/dev/acpica/acpi.c          | 34 ---------------------
 sys/dev/acpica/acpi_resource.c | 69 ++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 67 insertions(+), 36 deletions(-)

diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 46e9fe084fce..43aed279ab35 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -97,7 +97,6 @@ struct acpi_interface {
 };
 
 static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
-static char *pcilink_ids[] = { "PNP0C0F", NULL };
 
 /* Global mutex for locking access to the ACPI subsystem. */
 struct mtx	acpi_mutex;
@@ -1431,40 +1430,7 @@ acpi_set_resource(device_t dev, device_t child, int type, int rid,
 {
     struct acpi_device *ad = device_get_ivars(child);
     struct resource_list *rl = &ad->ad_rl;
-    ACPI_DEVICE_INFO *devinfo;
     rman_res_t end;
-    int allow;
-
-    /* Ignore IRQ resources for PCI link devices. */
-    if (type == SYS_RES_IRQ &&
-	ACPI_ID_PROBE(dev, child, pcilink_ids, NULL) <= 0)
-	return (0);
-
-    /*
-     * Ignore most resources for PCI root bridges.  Some BIOSes
-     * incorrectly enumerate the memory ranges they decode as plain
-     * memory resources instead of as ResourceProducer ranges.  Other
-     * BIOSes incorrectly list system resource entries for I/O ranges
-     * under the PCI bridge.  Do allow the one known-correct case on
-     * x86 of a PCI bridge claiming the I/O ports used for PCI config
-     * access.
-     */
-    if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
-	if (ACPI_SUCCESS(AcpiGetObjectInfo(ad->ad_handle, &devinfo))) {
-	    if ((devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) {
-#if defined(__i386__) || defined(__amd64__)
-		allow = (type == SYS_RES_IOPORT && start == CONF1_ADDR_PORT);
-#else
-		allow = 0;
-#endif
-		if (!allow) {
-		    AcpiOsFree(devinfo);
-		    return (0);
-		}
-	    }
-	    AcpiOsFree(devinfo);
-	}
-    }
 
 #ifdef INTRNG
     /* map with default for now */
diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c
index 6b77e74d95f1..87b82a574beb 100644
--- a/sys/dev/acpica/acpi_resource.c
+++ b/sys/dev/acpica/acpi_resource.c
@@ -34,6 +34,9 @@
 #include <sys/malloc.h>
 #include <sys/module.h>
 
+#if defined(__i386__) || defined(__amd64__)
+#include <machine/pci_cfgreg.h>
+#endif
 #include <machine/bus.h>
 #include <machine/resource.h>
 #include <sys/rman.h>
@@ -62,6 +65,8 @@ struct lookup_irq_request {
     int		pol;
 };
 
+static char *pcilink_ids[] = { "PNP0C0F", NULL };
+
 static ACPI_STATUS
 acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
 {
@@ -582,6 +587,52 @@ struct acpi_res_context {
     void 	*ar_parent;
 };
 
+/*
+ * Some resources reported via _CRS should not be added as bus
+ * resources.  This function returns true if a resource reported via
+ * _CRS should be ignored.
+ */
+static bool
+acpi_res_ignore(device_t dev, int type, rman_res_t start, rman_res_t count)
+{
+    struct acpi_device *ad = device_get_ivars(dev);
+    ACPI_DEVICE_INFO *devinfo;
+    bool allow;
+
+    /* Ignore IRQ resources for PCI link devices. */
+    if (type == SYS_RES_IRQ &&
+	ACPI_ID_PROBE(device_get_parent(dev), dev, pcilink_ids, NULL) <= 0)
+	return (true);
+
+    /*
+     * Ignore most resources for PCI root bridges.  Some BIOSes
+     * incorrectly enumerate the memory ranges they decode as plain
+     * memory resources instead of as ResourceProducer ranges.  Other
+     * BIOSes incorrectly list system resource entries for I/O ranges
+     * under the PCI bridge.  Do allow the one known-correct case on
+     * x86 of a PCI bridge claiming the I/O ports used for PCI config
+     * access.
+     */
+    if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
+	if (ACPI_SUCCESS(AcpiGetObjectInfo(ad->ad_handle, &devinfo))) {
+	    if ((devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) {
+#if defined(__i386__) || defined(__amd64__)
+		allow = (type == SYS_RES_IOPORT && start == CONF1_ADDR_PORT);
+#else
+		allow = false;
+#endif
+		if (!allow) {
+		    AcpiOsFree(devinfo);
+		    return (true);
+		}
+	    }
+	    AcpiOsFree(devinfo);
+	}
+    }
+
+    return (false);
+}
+
 static void
 acpi_res_set_init(device_t dev, void *arg, void **context)
 {
@@ -612,6 +663,8 @@ acpi_res_set_ioport(device_t dev, void *context, uint64_t base,
 
     if (cp == NULL)
 	return;
+    if (acpi_res_ignore(dev, SYS_RES_IOPORT, base, length))
+	return;
     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
 }
 
@@ -637,6 +690,8 @@ acpi_res_set_iorange(device_t dev, void *context, uint64_t low,
 	    device_printf(dev,
 		"_CRS has fixed I/O port range defined as relocatable\n");
 
+	if (acpi_res_ignore(dev, SYS_RES_IOPORT, low, length))
+	    return;
 	bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, low, length);
 	return;
     }
@@ -652,6 +707,8 @@ acpi_res_set_memory(device_t dev, void *context, uint64_t base,
 
     if (cp == NULL)
 	return;
+    if (acpi_res_ignore(dev, SYS_RES_MEMORY, base, length))
+	return;
     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
 }
 
@@ -676,8 +733,11 @@ acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
     if (cp == NULL || irq == NULL)
 	return;
 
-    for (i = 0; i < count; i++)
+    for (i = 0; i < count; i++) {
+	if (acpi_res_ignore(dev, SYS_RES_IRQ, irq[i], 1))
+	    continue;
         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
+    }
 }
 
 static void
@@ -690,8 +750,11 @@ acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
     if (cp == NULL || irq == NULL)
 	return;
 
-    for (i = 0; i < count; i++)
+    for (i = 0; i < count; i++) {
+	if (acpi_res_ignore(dev, SYS_RES_IRQ, irq[i], 1))
+	    continue;
         bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq[i], 1);
+    }
 }
 
 static void
@@ -706,6 +769,8 @@ acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count)
     if (count != 1)
 	return;
 
+    if (acpi_res_ignore(dev, SYS_RES_DRQ, *drq, 1))
+	return;
     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
 }