acpica: rework INTRNG interrupts
On arm64 (where INTRNG is enabled), the interrupts have to be mapped with ACPI_BUS_MAP_INTR() before adding them as resources to devices. The earlier code did the mapping before calling acpi_set_resource(), which bypassed code that checked for PCI link interrupts. To fix this, move the call to map interrupts into acpi_set_resource() and that requires additional work to lookup interrupt properties. The changes here are to: * extend acpi_lookup_irq_handler() to lookup an irq in the ACPI resources * create a helper function acpi_map_intr() which uses the updated acpi_lookup_irq_handler() to look up an irq, and then map it with ACPI_BUS_MAP_INTR() * use acpi_map_intr() in acpi_pcib_route_interrupt() to map pci link interrupts. With these changes, we can drop the ifdefs in acpi_resource.c, and we can also drop the call for mapping interrupts in generic_timer.c Reviewed by: andrew Differential Revision: https://reviews.freebsd.org/D17790
This commit is contained in:
parent
697c57e5c7
commit
d4d6ad3f05
@ -72,7 +72,6 @@ __FBSDID("$FreeBSD$");
|
||||
#ifdef DEV_ACPI
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <dev/acpica/acpivar.h>
|
||||
#include "acpi_bus_if.h"
|
||||
#endif
|
||||
|
||||
#define GT_CTRL_ENABLE (1 << 0)
|
||||
@ -340,8 +339,6 @@ static void
|
||||
arm_tmr_acpi_add_irq(device_t parent, device_t dev, int rid, u_int irq)
|
||||
{
|
||||
|
||||
irq = ACPI_BUS_MAP_INTR(parent, dev, irq,
|
||||
INTR_TRIGGER_LEVEL, INTR_POLARITY_HIGH);
|
||||
BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, rid, irq, 1);
|
||||
}
|
||||
|
||||
|
@ -1319,6 +1319,13 @@ acpi_set_resource(device_t dev, device_t child, int type, int rid,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INTRNG
|
||||
/* map with default for now */
|
||||
if (type == SYS_RES_IRQ)
|
||||
start = (rman_res_t)acpi_map_intr(child, (u_int)start,
|
||||
acpi_get_handle(child));
|
||||
#endif
|
||||
|
||||
/* If the resource is already allocated, fail. */
|
||||
if (resource_list_busy(rl, type, rid))
|
||||
return (EBUSY);
|
||||
|
@ -188,6 +188,7 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
|
||||
|
||||
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
|
||||
|
||||
lnkdev = NULL;
|
||||
interrupt = PCI_INVALID_IRQ;
|
||||
|
||||
/* ACPI numbers pins 0-3, not 1-4 like the BIOS. */
|
||||
@ -252,7 +253,12 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
|
||||
|
||||
out:
|
||||
ACPI_SERIAL_END(pcib);
|
||||
|
||||
#ifdef INTRNG
|
||||
if (PCI_INTERRUPT_VALID(interrupt)) {
|
||||
interrupt = acpi_map_intr(dev, interrupt, lnkdev);
|
||||
KASSERT(PCI_INTERRUPT_VALID(interrupt), ("mapping fail"));
|
||||
}
|
||||
#endif
|
||||
return_VALUE(interrupt);
|
||||
}
|
||||
|
||||
|
@ -55,10 +55,13 @@ ACPI_MODULE_NAME("RESOURCE")
|
||||
|
||||
struct lookup_irq_request {
|
||||
ACPI_RESOURCE *acpi_res;
|
||||
struct resource *res;
|
||||
u_int irq;
|
||||
int counter;
|
||||
int rid;
|
||||
int found;
|
||||
int checkrid;
|
||||
int trig;
|
||||
int pol;
|
||||
};
|
||||
|
||||
static ACPI_STATUS
|
||||
@ -66,18 +69,22 @@ acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
|
||||
{
|
||||
struct lookup_irq_request *req;
|
||||
size_t len;
|
||||
u_int irqnum, irq;
|
||||
u_int irqnum, irq, trig, pol;
|
||||
|
||||
switch (res->Type) {
|
||||
case ACPI_RESOURCE_TYPE_IRQ:
|
||||
irqnum = res->Data.Irq.InterruptCount;
|
||||
irq = res->Data.Irq.Interrupts[0];
|
||||
len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
|
||||
trig = res->Data.Irq.Triggering;
|
||||
pol = res->Data.Irq.Polarity;
|
||||
break;
|
||||
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
|
||||
irqnum = res->Data.ExtendedIrq.InterruptCount;
|
||||
irq = res->Data.ExtendedIrq.Interrupts[0];
|
||||
len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
|
||||
trig = res->Data.ExtendedIrq.Triggering;
|
||||
pol = res->Data.ExtendedIrq.Polarity;
|
||||
break;
|
||||
default:
|
||||
return (AE_OK);
|
||||
@ -85,14 +92,21 @@ acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
|
||||
if (irqnum != 1)
|
||||
return (AE_OK);
|
||||
req = (struct lookup_irq_request *)context;
|
||||
if (req->counter != req->rid) {
|
||||
req->counter++;
|
||||
return (AE_OK);
|
||||
if (req->checkrid) {
|
||||
if (req->counter != req->rid) {
|
||||
req->counter++;
|
||||
return (AE_OK);
|
||||
}
|
||||
KASSERT(irq == req->irq, ("IRQ resources do not match"));
|
||||
} else {
|
||||
if (req->irq != irq)
|
||||
return (AE_OK);
|
||||
}
|
||||
req->found = 1;
|
||||
KASSERT(irq == rman_get_start(req->res),
|
||||
("IRQ resources do not match"));
|
||||
bcopy(res, req->acpi_res, len);
|
||||
req->pol = pol;
|
||||
req->trig = trig;
|
||||
if (req->acpi_res != NULL)
|
||||
bcopy(res, req->acpi_res, len);
|
||||
return (AE_CTRL_TERMINATE);
|
||||
}
|
||||
|
||||
@ -104,10 +118,11 @@ acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
|
||||
ACPI_STATUS status;
|
||||
|
||||
req.acpi_res = acpi_res;
|
||||
req.res = res;
|
||||
req.irq = rman_get_start(res);
|
||||
req.counter = 0;
|
||||
req.rid = rid;
|
||||
req.found = 0;
|
||||
req.checkrid = 1;
|
||||
status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
|
||||
acpi_lookup_irq_handler, &req);
|
||||
if (ACPI_SUCCESS(status) && req.found == 0)
|
||||
@ -155,6 +170,34 @@ acpi_config_intr(device_t dev, ACPI_RESOURCE *res)
|
||||
INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
|
||||
}
|
||||
|
||||
#ifdef INTRNG
|
||||
int
|
||||
acpi_map_intr(device_t dev, u_int irq, ACPI_HANDLE handle)
|
||||
{
|
||||
struct lookup_irq_request req;
|
||||
int trig, pol;
|
||||
|
||||
trig = ACPI_LEVEL_SENSITIVE;
|
||||
pol = ACPI_ACTIVE_HIGH;
|
||||
if (handle != NULL) {
|
||||
req.found = 0;
|
||||
req.acpi_res = NULL;
|
||||
req.irq = irq;
|
||||
req.counter = 0;
|
||||
req.rid = 0;
|
||||
req.checkrid = 0;
|
||||
AcpiWalkResources(handle, "_CRS", acpi_lookup_irq_handler, &req);
|
||||
if (req.found != 0) {
|
||||
trig = req.trig;
|
||||
pol = req.pol;
|
||||
}
|
||||
}
|
||||
return ACPI_BUS_MAP_INTR(device_get_parent(dev), dev, irq,
|
||||
(trig == ACPI_EDGE_SENSITIVE) ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL,
|
||||
(pol == ACPI_ACTIVE_HIGH) ? INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct acpi_resource_context {
|
||||
struct acpi_parse_resource_set *set;
|
||||
device_t dev;
|
||||
@ -591,13 +634,7 @@ acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
|
||||
if (count != 1)
|
||||
return;
|
||||
|
||||
#ifdef INTRNG
|
||||
intr = ACPI_BUS_MAP_INTR(device_get_parent(dev), dev, *irq,
|
||||
(trig == ACPI_EDGE_SENSITIVE) ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL,
|
||||
(pol == ACPI_ACTIVE_HIGH) ? INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
|
||||
#else
|
||||
intr = *irq;
|
||||
#endif
|
||||
bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, intr, 1);
|
||||
}
|
||||
|
||||
@ -615,13 +652,7 @@ acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
|
||||
if (count != 1)
|
||||
return;
|
||||
|
||||
#ifdef INTRNG
|
||||
intr = ACPI_BUS_MAP_INTR(device_get_parent(dev), dev, *irq,
|
||||
(trig == ACPI_EDGE_SENSITIVE) ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL,
|
||||
(pol == ACPI_ACTIVE_HIGH) ? INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
|
||||
#else
|
||||
intr = *irq;
|
||||
#endif
|
||||
bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, intr, 1);
|
||||
}
|
||||
|
||||
|
@ -403,6 +403,9 @@ extern struct acpi_parse_resource_set acpi_res_parse_set;
|
||||
|
||||
int acpi_identify(void);
|
||||
void acpi_config_intr(device_t dev, ACPI_RESOURCE *res);
|
||||
#ifdef INTRNG
|
||||
int acpi_map_intr(device_t dev, u_int irq, ACPI_HANDLE handle);
|
||||
#endif
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user