Index: sys/arm/arm/generic_timer.c =================================================================== --- sys/arm/arm/generic_timer.c +++ sys/arm/arm/generic_timer.c @@ -70,6 +70,7 @@ #ifdef DEV_ACPI #include #include +#include "acpi_bus_if.h" #endif #define GT_CTRL_ENABLE (1 << 0) @@ -305,6 +306,15 @@ #ifdef DEV_ACPI 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); +} + +static void arm_tmr_acpi_identify(driver_t *driver, device_t parent) { ACPI_TABLE_GTDT *gtdt; @@ -328,12 +338,9 @@ goto out; } - BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 0, - gtdt->SecureEl1Interrupt, 1); - BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 1, - gtdt->NonSecureEl1Interrupt, 1); - BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 2, - gtdt->VirtualTimerInterrupt, 1); + arm_tmr_acpi_add_irq(parent, dev, 0, gtdt->SecureEl1Interrupt); + arm_tmr_acpi_add_irq(parent, dev, 1, gtdt->NonSecureEl1Interrupt); + arm_tmr_acpi_add_irq(parent, dev, 2, gtdt->VirtualTimerInterrupt); out: acpi_unmap_table(gtdt); Index: sys/arm64/arm64/nexus.c =================================================================== --- sys/arm64/arm64/nexus.c +++ sys/arm64/arm64/nexus.c @@ -72,6 +72,7 @@ #ifdef DEV_ACPI #include #include +#include "acpi_bus_if.h" #endif extern struct bus_space memmap_bus; @@ -460,11 +461,16 @@ #endif #ifdef DEV_ACPI +static int nexus_acpi_map_intr(device_t dev, device_t child, u_int irq, int trig, int pol); + static device_method_t nexus_acpi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, nexus_acpi_probe), DEVMETHOD(device_attach, nexus_acpi_attach), + /* ACPI interface */ + DEVMETHOD(acpi_bus_map_intr, nexus_acpi_map_intr), + DEVMETHOD_END, }; @@ -495,4 +501,30 @@ nexus_add_child(dev, 10, "acpi", 0); return (nexus_attach(dev)); } + +static int +nexus_acpi_map_intr(device_t dev, device_t child, u_int irq, int trig, int pol) +{ + struct intr_map_data_acpi *acpi_data; + size_t len; + + len = sizeof(*acpi_data); + acpi_data = (struct intr_map_data_acpi *)intr_alloc_map_data( + INTR_MAP_DATA_ACPI, len, M_WAITOK | M_ZERO); + acpi_data->irq = irq; + acpi_data->pol = pol; + acpi_data->trig = trig; + + /* + * TODO: This will only handle a single interrupt controller. + * ACPI will map multiple controllers into a single virtual IRQ + * space. Each controller has a System Vector Base to hold the + * first irq it handles in this space. As such the correct way + * to handle interrupts with ACPI is to search through the + * controllers for the largest base value that is no larger than + * the IRQ value. + */ + irq = intr_map_irq(NULL, 0, (struct intr_map_data *)acpi_data); + return (irq); +} #endif Index: sys/conf/files.arm64 =================================================================== --- sys/conf/files.arm64 +++ sys/conf/files.arm64 @@ -145,6 +145,7 @@ crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/acpica/acpi_if.m optional acpi +dev/acpica/acpi_bus_if.m optional acpi dev/ahci/ahci_generic.c optional ahci fdt dev/cpufreq/cpufreq_dt.c optional cpufreq fdt dev/hwpmc/hwpmc_arm64.c optional hwpmc Index: sys/dev/acpica/acpi.c =================================================================== --- sys/dev/acpica/acpi.c +++ sys/dev/acpica/acpi.c @@ -1349,7 +1349,9 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { +#ifndef INTRNG ACPI_RESOURCE ares; +#endif struct acpi_device *ad; struct resource_list_entry *rle; struct resource_list *rl; @@ -1376,6 +1378,7 @@ resource_list_add(rl, type, *rid, start, end, count); res = resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags); +#ifndef INTRNG if (res != NULL && type == SYS_RES_IRQ) { /* * Since bus_config_intr() takes immediate effect, we cannot @@ -1388,6 +1391,7 @@ if (ACPI_SUCCESS(acpi_lookup_irq_resource(child, *rid, res, &ares))) acpi_config_intr(child, &ares); } +#endif /* * If this is an allocation of the "default" range for a given Index: sys/dev/acpica/acpi_bus_if.m =================================================================== --- /dev/null +++ sys/dev/acpica/acpi_bus_if.m @@ -0,0 +1,67 @@ +#- +# Copyright (c) 2016 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Andrew Turner under +# sponsorship from the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +#include +#include +#include + +INTERFACE acpi_bus; + +CODE { + static acpi_bus_map_intr_t acpi_bus_default_map_intr; + + int + acpi_bus_default_map_intr(device_t bus, device_t dev, u_int irq, + int trig, int pol) + { + device_t parent; + + /* Pass up the hierarchy */ + parent = device_get_parent(bus); + if (parent != NULL) + return (ACPI_BUS_MAP_INTR(parent, dev, irq, trig, pol)); + + panic("Unable to map interrupt %u", irq); + } +}; + +# Map an interrupt from ACPI space to the FreeBSD IRQ space. Note that +# both of these may be different than the pysical interrupt space as this +# may bt local to each interrupt controller. +# +# This method also associates interrupt metadata with the interrupt, +# removing the need for a post hoc configure step. +METHOD int map_intr { + device_t bus; + device_t dev; + u_int irq; + int trig; + int pol; +} DEFAULT acpi_bus_default_map_intr; Index: sys/dev/acpica/acpi_resource.c =================================================================== --- sys/dev/acpica/acpi_resource.c +++ sys/dev/acpica/acpi_resource.c @@ -45,6 +45,10 @@ #include +#ifdef INTRNG +#include "acpi_bus_if.h" +#endif + /* Hooks for the ACPI CA debugging infrastructure */ #define _COMPONENT ACPI_BUS ACPI_MODULE_NAME("RESOURCE") @@ -556,6 +560,7 @@ int trig, int pol) { struct acpi_res_context *cp = (struct acpi_res_context *)context; + rman_res_t intr; if (cp == NULL || irq == NULL) return; @@ -564,7 +569,14 @@ if (count != 1) return; - bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); +#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); } static void @@ -572,6 +584,7 @@ int trig, int pol) { struct acpi_res_context *cp = (struct acpi_res_context *)context; + rman_res_t intr; if (cp == NULL || irq == NULL) return; @@ -580,7 +593,14 @@ if (count != 1) return; - bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1); +#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); } static void Index: sys/sys/intr.h =================================================================== --- sys/sys/intr.h +++ sys/sys/intr.h @@ -56,6 +56,13 @@ enum intr_map_data_type type; }; +struct intr_map_data_acpi { + struct intr_map_data hdr; + u_int irq; + u_int pol; + u_int trig; +}; + struct intr_map_data_msi { struct intr_map_data hdr; struct intr_irqsrc *isrc;