summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2004-06-23 17:21:02 +0000
committerjhb <jhb@FreeBSD.org>2004-06-23 17:21:02 +0000
commitcb992566cac1c44f62a47bbee7ec9f4a2fe7db53 (patch)
tree4678bf05661b8093ed227e74131c0db158f84795 /sys/dev/acpica
parent22d8e1a72ee83a4d20da2cc201b27d2d2494eba5 (diff)
downloadFreeBSD-src-cb992566cac1c44f62a47bbee7ec9f4a2fe7db53.zip
FreeBSD-src-cb992566cac1c44f62a47bbee7ec9f4a2fe7db53.tar.gz
- 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)
Diffstat (limited to 'sys/dev/acpica')
-rw-r--r--sys/dev/acpica/acpi.c77
-rw-r--r--sys/dev/acpica/acpi_pcib.c5
-rw-r--r--sys/dev/acpica/acpi_resource.c91
-rw-r--r--sys/dev/acpica/acpivar.h4
4 files changed, 143 insertions, 34 deletions
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;
OpenPOWER on IntegriCloud