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:
Jayachandran C. 2018-11-19 03:02:47 +00:00
parent 697c57e5c7
commit d4d6ad3f05
5 changed files with 69 additions and 25 deletions

View File

@ -72,7 +72,6 @@ __FBSDID("$FreeBSD$");
#ifdef DEV_ACPI #ifdef DEV_ACPI
#include <contrib/dev/acpica/include/acpi.h> #include <contrib/dev/acpica/include/acpi.h>
#include <dev/acpica/acpivar.h> #include <dev/acpica/acpivar.h>
#include "acpi_bus_if.h"
#endif #endif
#define GT_CTRL_ENABLE (1 << 0) #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) 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); BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, rid, irq, 1);
} }

View File

@ -1319,6 +1319,13 @@ acpi_set_resource(device_t dev, device_t child, int type, int rid,
} }
#endif #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 the resource is already allocated, fail. */
if (resource_list_busy(rl, type, rid)) if (resource_list_busy(rl, type, rid))
return (EBUSY); return (EBUSY);

View File

@ -188,6 +188,7 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
lnkdev = NULL;
interrupt = PCI_INVALID_IRQ; interrupt = PCI_INVALID_IRQ;
/* ACPI numbers pins 0-3, not 1-4 like the BIOS. */ /* 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: out:
ACPI_SERIAL_END(pcib); 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); return_VALUE(interrupt);
} }

View File

@ -55,10 +55,13 @@ ACPI_MODULE_NAME("RESOURCE")
struct lookup_irq_request { struct lookup_irq_request {
ACPI_RESOURCE *acpi_res; ACPI_RESOURCE *acpi_res;
struct resource *res; u_int irq;
int counter; int counter;
int rid; int rid;
int found; int found;
int checkrid;
int trig;
int pol;
}; };
static ACPI_STATUS static ACPI_STATUS
@ -66,18 +69,22 @@ acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
{ {
struct lookup_irq_request *req; struct lookup_irq_request *req;
size_t len; size_t len;
u_int irqnum, irq; u_int irqnum, irq, trig, pol;
switch (res->Type) { switch (res->Type) {
case ACPI_RESOURCE_TYPE_IRQ: case ACPI_RESOURCE_TYPE_IRQ:
irqnum = res->Data.Irq.InterruptCount; irqnum = res->Data.Irq.InterruptCount;
irq = res->Data.Irq.Interrupts[0]; irq = res->Data.Irq.Interrupts[0];
len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ); len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
trig = res->Data.Irq.Triggering;
pol = res->Data.Irq.Polarity;
break; break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
irqnum = res->Data.ExtendedIrq.InterruptCount; irqnum = res->Data.ExtendedIrq.InterruptCount;
irq = res->Data.ExtendedIrq.Interrupts[0]; irq = res->Data.ExtendedIrq.Interrupts[0];
len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ); len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
trig = res->Data.ExtendedIrq.Triggering;
pol = res->Data.ExtendedIrq.Polarity;
break; break;
default: default:
return (AE_OK); return (AE_OK);
@ -85,13 +92,20 @@ acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
if (irqnum != 1) if (irqnum != 1)
return (AE_OK); return (AE_OK);
req = (struct lookup_irq_request *)context; req = (struct lookup_irq_request *)context;
if (req->checkrid) {
if (req->counter != req->rid) { if (req->counter != req->rid) {
req->counter++; req->counter++;
return (AE_OK); return (AE_OK);
} }
KASSERT(irq == req->irq, ("IRQ resources do not match"));
} else {
if (req->irq != irq)
return (AE_OK);
}
req->found = 1; req->found = 1;
KASSERT(irq == rman_get_start(req->res), req->pol = pol;
("IRQ resources do not match")); req->trig = trig;
if (req->acpi_res != NULL)
bcopy(res, req->acpi_res, len); bcopy(res, req->acpi_res, len);
return (AE_CTRL_TERMINATE); return (AE_CTRL_TERMINATE);
} }
@ -104,10 +118,11 @@ acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
ACPI_STATUS status; ACPI_STATUS status;
req.acpi_res = acpi_res; req.acpi_res = acpi_res;
req.res = res; req.irq = rman_get_start(res);
req.counter = 0; req.counter = 0;
req.rid = rid; req.rid = rid;
req.found = 0; req.found = 0;
req.checkrid = 1;
status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
acpi_lookup_irq_handler, &req); acpi_lookup_irq_handler, &req);
if (ACPI_SUCCESS(status) && req.found == 0) 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); 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_resource_context {
struct acpi_parse_resource_set *set; struct acpi_parse_resource_set *set;
device_t dev; device_t dev;
@ -591,13 +634,7 @@ acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
if (count != 1) if (count != 1)
return; 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; intr = *irq;
#endif
bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, intr, 1); 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) if (count != 1)
return; 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; intr = *irq;
#endif
bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, intr, 1); bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, intr, 1);
} }

View File

@ -403,6 +403,9 @@ extern struct acpi_parse_resource_set acpi_res_parse_set;
int acpi_identify(void); int acpi_identify(void);
void acpi_config_intr(device_t dev, ACPI_RESOURCE *res); 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, ACPI_STATUS acpi_lookup_irq_resource(device_t dev, int rid,
struct resource *res, ACPI_RESOURCE *acpi_res); struct resource *res, ACPI_RESOURCE *acpi_res);
ACPI_STATUS acpi_parse_resources(device_t dev, ACPI_HANDLE handle, ACPI_STATUS acpi_parse_resources(device_t dev, ACPI_HANDLE handle,