From cb992566cac1c44f62a47bbee7ec9f4a2fe7db53 Mon Sep 17 00:00:00 2001 From: jhb Date: Wed, 23 Jun 2004 17:21:02 +0000 Subject: - Defer BUS_CONFIG_INTR() on ACPI IRQ resources until the resources are actually used. For most ACPI devices this means deferring the call until bus_alloc_resource(). - Add a function acpi_config_intr() to call BUS_CONFIG_INTR() for an ACPI IRQ resource using the trigger mode and polarity information stored in the ACPI resource object. - Add a function acpi_lookup_irq_resource() to lookup the ACPI IRQ resource that corresponds to a specified rid and new-bus resource. - Have the ACPI PCI bridge driver call BUS_CONFIG_INTR() on interrupts that it routes through link devices. - Remove needactivate variable from acpi_alloc_resource() by changing the function not modify the flags variable but just mask off RF_ACTIVE when calling rman_reserve_resource(). Reviewed by: njl (1, an earlier version) --- sys/dev/acpica/acpi.c | 77 +++++++++++++++++++++-------------- sys/dev/acpica/acpi_pcib.c | 5 +++ sys/dev/acpica/acpi_resource.c | 91 ++++++++++++++++++++++++++++++++++++++++-- sys/dev/acpica/acpivar.h | 4 ++ 4 files changed, 143 insertions(+), 34 deletions(-) (limited to 'sys/dev/acpica') diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index ffc66d2..510cf55 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -846,12 +846,12 @@ static struct resource * acpi_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { + ACPI_RESOURCE ares; struct acpi_device *ad = device_get_ivars(child); struct resource_list *rl = &ad->ad_rl; struct resource_list_entry *rle; struct resource *res; struct rman *rm; - int needactivate; /* * If this is an allocation of the "default" range for a given RID, and @@ -870,41 +870,56 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid, /* If we don't manage this address, pass the request up to the parent. */ rle = acpi_sysres_find(type, start); if (rle == NULL) { - return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, - start, end, count, flags)); - } + res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, + start, end, count, flags); + } else { - /* We only handle memory and IO resources through rman. */ - switch (type) { - case SYS_RES_IOPORT: - rm = &acpi_rman_io; - break; - case SYS_RES_MEMORY: - rm = &acpi_rman_mem; - break; - default: - panic("acpi_alloc_resource: invalid res type %d", type); - } + /* We only handle memory and IO resources through rman. */ + switch (type) { + case SYS_RES_IOPORT: + rm = &acpi_rman_io; + break; + case SYS_RES_MEMORY: + rm = &acpi_rman_mem; + break; + default: + panic("acpi_alloc_resource: invalid res type %d", type); + } - /* If we do know it, allocate it from the local pool. */ - needactivate = flags & RF_ACTIVE; - flags &= ~RF_ACTIVE; - res = rman_reserve_resource(rm, start, end, count, flags, child); - if (res == NULL) - return (NULL); + /* If we do know it, allocate it from the local pool. */ + res = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, + child); + if (res == NULL) + return (NULL); - /* Copy the bus tag from the pre-allocated resource. */ - rman_set_bustag(res, rman_get_bustag(rle->res)); - if (type == SYS_RES_IOPORT) - rman_set_bushandle(res, res->r_start); + /* Copy the bus tag from the pre-allocated resource. */ + rman_set_bustag(res, rman_get_bustag(rle->res)); + if (type == SYS_RES_IOPORT) + rman_set_bushandle(res, res->r_start); - /* If requested, activate the resource using the parent's method. */ - if (needactivate) - if (bus_activate_resource(child, type, *rid, res) != 0) { - rman_release_resource(res); - return (NULL); - } + /* If requested, activate the resource using the parent's method. */ + if (flags & RF_ACTIVE) + if (bus_activate_resource(child, type, *rid, res) != 0) { + rman_release_resource(res); + return (NULL); + } + } + if (res != NULL && device_get_parent(child) == bus) + switch (type) { + case SYS_RES_IRQ: + /* + * Since bus_config_intr() takes immediate effect, we cannot + * configure the interrupt associated with a device when we + * parse the resources but have to defer it until a driver + * actually allocates the interrupt via bus_alloc_resource(). + * + * XXX: Should we handle the lookup failing? + */ + if (ACPI_SUCCESS(acpi_lookup_irq_resource(child, *rid, res, &ares))) + acpi_config_intr(child, &ares); + break; + } return (res); } diff --git a/sys/dev/acpica/acpi_pcib.c b/sys/dev/acpica/acpi_pcib.c index b14efb2..8eeda8e 100644 --- a/sys/dev/acpica/acpi_pcib.c +++ b/sys/dev/acpica/acpi_pcib.c @@ -121,6 +121,7 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + crsres = NULL; buf.Pointer = NULL; crsbuf.Pointer = NULL; prsbuf.Pointer = NULL; @@ -348,6 +349,7 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, /* XXX Data.Irq and Data.ExtendedIrq are implicitly structure-copied. */ crsbuf.Pointer = NULL; + crsres = NULL; if (prsres->Id == ACPI_RSTYPE_IRQ) { resbuf.Id = ACPI_RSTYPE_IRQ; resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ); @@ -378,6 +380,7 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, AcpiFormatException(status)); goto out; } + crsres = &resbuf; /* Return the interrupt we just routed. */ device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", @@ -386,6 +389,8 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, interrupt = Interrupts[0]; out: + if (PCI_INTERRUPT_VALID(interrupt) && crsres != NULL) + acpi_config_intr(dev, crsres); if (crsbuf.Pointer != NULL) AcpiOsFree(crsbuf.Pointer); if (prsbuf.Pointer != NULL) diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c index 06bf29b..369e183 100644 --- a/sys/dev/acpica/acpi_resource.c +++ b/sys/dev/acpica/acpi_resource.c @@ -46,6 +46,94 @@ __FBSDID("$FreeBSD$"); #define _COMPONENT ACPI_BUS ACPI_MODULE_NAME("RESOURCE") +struct lookup_irq_request { + ACPI_RESOURCE *acpi_res; + struct resource *res; + int counter; + int rid; + int found; +}; + +static ACPI_STATUS +acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context) +{ + struct lookup_irq_request *req; + u_int irqnum, irq; + + switch (res->Id) { + case ACPI_RSTYPE_IRQ: + case ACPI_RSTYPE_EXT_IRQ: + if (res->Id == ACPI_RSTYPE_IRQ) { + irqnum = res->Data.Irq.NumberOfInterrupts; + irq = res->Data.Irq.Interrupts[0]; + } else { + irqnum = res->Data.ExtendedIrq.NumberOfInterrupts; + irq = res->Data.ExtendedIrq.Interrupts[0]; + } + if (irqnum != 1) + break; + req = (struct lookup_irq_request *)context; + if (req->counter != req->rid) { + req->counter++; + break; + } + req->found = 1; + KASSERT(irq == rman_get_start(req->res), + ("IRQ resources do not match")); + bcopy(res, req->acpi_res, sizeof(ACPI_RESOURCE)); + return (AE_CTRL_TERMINATE); + } + return (AE_OK); +} + +ACPI_STATUS +acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res, + ACPI_RESOURCE *acpi_res) +{ + struct lookup_irq_request req; + ACPI_STATUS status; + + req.acpi_res = acpi_res; + req.res = res; + req.counter = 0; + req.rid = rid; + req.found = 0; + status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", + acpi_lookup_irq_handler, &req); + if (ACPI_SUCCESS(status) && req.found == 0) + status = AE_NOT_FOUND; + return (status); +} + +void +acpi_config_intr(device_t dev, ACPI_RESOURCE *res) +{ + u_int irq; + int pol, trig; + + switch (res->Id) { + case ACPI_RSTYPE_IRQ: + KASSERT(res->Data.Irq.NumberOfInterrupts == 1, + ("%s: multiple interrupts", __func__)); + irq = res->Data.Irq.Interrupts[0]; + trig = res->Data.Irq.EdgeLevel; + pol = res->Data.Irq.ActiveHighLow; + break; + case ACPI_RSTYPE_EXT_IRQ: + KASSERT(res->Data.ExtendedIrq.NumberOfInterrupts == 1, + ("%s: multiple interrupts", __func__)); + irq = res->Data.ExtendedIrq.Interrupts[0]; + trig = res->Data.ExtendedIrq.EdgeLevel; + pol = res->Data.ExtendedIrq.ActiveHighLow; + break; + default: + panic("%s: bad resource type %u", __func__, res->Id); + } + BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ? + INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ? + INTR_POLARITY_HIGH : INTR_POLARITY_LOW); +} + /* * Fetch a device's resources and associate them with the device. * @@ -497,9 +585,6 @@ acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count, return; bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); - BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ? - INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ? - INTR_POLARITY_HIGH : INTR_POLARITY_LOW); } static void diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index c0bc481..7d0b1d3 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -268,6 +268,10 @@ struct acpi_parse_resource_set { }; extern struct acpi_parse_resource_set acpi_res_parse_set; + +void acpi_config_intr(device_t dev, ACPI_RESOURCE *res); +ACPI_STATUS acpi_lookup_irq_resource(device_t dev, int rid, + struct resource *res, ACPI_RESOURCE *acpi_res); ACPI_STATUS acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set, void *arg); extern struct rman acpi_rman_io, acpi_rman_mem; -- cgit v1.1