aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2024-02-14 22:07:32 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2024-02-14 22:07:32 +0000
commit055c1fe230ce5a2997c03a3cc2431baea1594566 (patch)
tree206952693d8387c2250f5f629e4097515eeb052d
parente05436d577de98944b97b9cf510b29c4d2091b3f (diff)
downloadsrc-055c1fe230ce5a2997c03a3cc2431baea1594566.tar.gz
src-055c1fe230ce5a2997c03a3cc2431baea1594566.zip
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
-rw-r--r--sys/dev/acpica/acpi.c34
-rw-r--r--sys/dev/acpica/acpi_resource.c69
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);
}