aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arm/arm/generic_timer.c19
-rw-r--r--sys/arm64/arm64/nexus.c32
-rw-r--r--sys/conf/files.arm641
-rw-r--r--sys/dev/acpica/acpi.c4
-rw-r--r--sys/dev/acpica/acpi_bus_if.m67
-rw-r--r--sys/dev/acpica/acpi_resource.c24
-rw-r--r--sys/dev/acpica/acpivar.h13
7 files changed, 152 insertions, 8 deletions
diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c
index 5e9cabab14d1..b13080d57bbe 100644
--- a/sys/arm/arm/generic_timer.c
+++ b/sys/arm/arm/generic_timer.c
@@ -72,6 +72,7 @@ __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)
@@ -313,6 +314,15 @@ arm_tmr_fdt_probe(device_t dev)
#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;
@@ -336,12 +346,9 @@ arm_tmr_acpi_identify(driver_t *driver, device_t parent)
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);
diff --git a/sys/arm64/arm64/nexus.c b/sys/arm64/arm64/nexus.c
index 31ec8f091002..3de441a9001f 100644
--- a/sys/arm64/arm64/nexus.c
+++ b/sys/arm64/arm64/nexus.c
@@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$");
#ifdef DEV_ACPI
#include <contrib/dev/acpica/include/acpi.h>
#include <dev/acpica/acpivar.h>
+#include "acpi_bus_if.h"
#endif
extern struct bus_space memmap_bus;
@@ -460,11 +461,16 @@ nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
#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_acpi_attach(device_t dev)
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
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index a4e86bc35ffb..d45e5577c3e8 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -167,6 +167,7 @@ armv8_crypto_wrap.o optional armv8crypto \
clean "armv8_crypto_wrap.o"
crypto/blowfish/bf_enc.c optional crypto | ipsec | ipsec_support
crypto/des/des_enc.c optional crypto | ipsec | ipsec_support | netsmb
+dev/acpica/acpi_bus_if.m optional acpi
dev/acpica/acpi_if.m optional acpi
dev/ahci/ahci_generic.c optional ahci
dev/axgbe/if_axgbe.c optional axgbe
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index cda93b6bc2c8..c6559579f3a9 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -1358,7 +1358,9 @@ static struct resource *
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;
@@ -1385,6 +1387,7 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
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
@@ -1397,6 +1400,7 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
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
diff --git a/sys/dev/acpica/acpi_bus_if.m b/sys/dev/acpica/acpi_bus_if.m
new file mode 100644
index 000000000000..df3f930af086
--- /dev/null
+++ b/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 <sys/types.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+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 be 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;
diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c
index 078ecce1eb0a..0a1b69ac93b5 100644
--- a/sys/dev/acpica/acpi_resource.c
+++ b/sys/dev/acpica/acpi_resource.c
@@ -45,6 +45,10 @@ __FBSDID("$FreeBSD$");
#include <dev/acpica/acpivar.h>
+#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 @@ acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
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 @@ acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count,
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 @@ acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
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 @@ acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count,
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
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 647e59b8d171..6b26cf455f55 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -36,6 +36,9 @@
#include "acpi_if.h"
#include "bus_if.h"
#include <sys/eventhandler.h>
+#ifdef INTRNG
+#include <sys/intr.h>
+#endif
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -91,6 +94,16 @@ struct acpi_device {
struct resource_list ad_rl;
};
+#ifdef INTRNG
+struct intr_map_data_acpi {
+ struct intr_map_data hdr;
+ u_int irq;
+ u_int pol;
+ u_int trig;
+};
+
+#endif
+
/* Track device (/dev/{apm,apmctl} and /dev/acpi) notification status. */
struct apm_clone_data {
STAILQ_ENTRY(apm_clone_data) entries;