From 8e0e405509b3c6fc60a570e4b1ea6509597eb6d6 Mon Sep 17 00:00:00 2001 From: "Jayachandran C." Date: Wed, 18 Sep 2019 07:09:16 +0000 Subject: [PATCH] MFC r340598: 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 --- sys/arm/arm/generic_timer.c | 3 -- sys/dev/acpica/acpi.c | 7 ++++ sys/dev/acpica/acpi_pcib.c | 8 +++- sys/dev/acpica/acpi_resource.c | 73 ++++++++++++++++++++++++---------- sys/dev/acpica/acpivar.h | 3 ++ 5 files changed, 69 insertions(+), 25 deletions(-) diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c index 0b4586f20bd..4ab3dec0d1b 100644 --- a/sys/arm/arm/generic_timer.c +++ b/sys/arm/arm/generic_timer.c @@ -72,7 +72,6 @@ __FBSDID("$FreeBSD$"); #ifdef DEV_ACPI #include #include -#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); } diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 7712a4c1826..380ac6e7ac3 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -1318,6 +1318,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); diff --git a/sys/dev/acpica/acpi_pcib.c b/sys/dev/acpica/acpi_pcib.c index bf1fc79b2d6..745f9cec139 100644 --- a/sys/dev/acpica/acpi_pcib.c +++ b/sys/dev/acpica/acpi_pcib.c @@ -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); } diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c index 6ad7670c8e2..5ba3a8efc81 100644 --- a/sys/dev/acpica/acpi_resource.c +++ b/sys/dev/acpica/acpi_resource.c @@ -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; @@ -601,13 +644,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); } @@ -625,13 +662,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); } diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index 7e0f6cebd5f..0d791f753d9 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -399,6 +399,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, -- 2.45.0