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
This commit is contained in:
John Baldwin 2024-02-14 14:07:32 -08:00
parent e05436d577
commit 055c1fe230
2 changed files with 67 additions and 36 deletions

View file

@ -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 */

View file

@ -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);
}