summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2016-08-01 14:17:00 +0000
committerpatrick <patrick@openbsd.org>2016-08-01 14:17:00 +0000
commit0ffbfca45c62a5ad651139c1dbdf5fb395902d4c (patch)
tree658dd07e401fa5056d3265d90a9d151fd59de8d6 /sys
parentMark shared producer and consumer indices volatile (diff)
downloadwireguard-openbsd-0ffbfca45c62a5ad651139c1dbdf5fb395902d4c.tar.xz
wireguard-openbsd-0ffbfca45c62a5ad651139c1dbdf5fb395902d4c.zip
Implement an FDT-aware interrupt establish API. This means the drivers
don't need to know where to attach to. Instead the API will take care of finding the correct interrupt establish for a given device node and will call it with the correct data. Adapted from the OFW GPIO framework. ok kettenis@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/armv7/armv7/intr.c120
-rw-r--r--sys/arch/armv7/include/intr.h19
2 files changed, 137 insertions, 2 deletions
diff --git a/sys/arch/armv7/armv7/intr.c b/sys/arch/armv7/armv7/intr.c
index 5227ae9d46f..a0b93a2bc14 100644
--- a/sys/arch/armv7/armv7/intr.c
+++ b/sys/arch/armv7/armv7/intr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr.c,v 1.5 2016/04/03 10:29:41 jsg Exp $ */
+/* $OpenBSD: intr.c,v 1.6 2016/08/01 14:17:00 patrick Exp $ */
/*
* Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
*
@@ -19,12 +19,15 @@
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/timetc.h>
+#include <sys/malloc.h>
#include <dev/clock_subr.h>
#include <arm/cpufunc.h>
#include <machine/cpu.h>
#include <machine/intr.h>
+#include <dev/ofw/openfirm.h>
+
int arm_dflt_splraise(int);
int arm_dflt_spllower(int);
void arm_dflt_splx(int);
@@ -37,6 +40,7 @@ const char *arm_dflt_intr_string(void *cookie);
void arm_dflt_intr(void *);
void arm_intr(void *);
+int OF_get_interrupt_controller(int);
#define SI_TO_IRQBIT(x) (1 << (x))
uint32_t arm_smask[NIPL];
@@ -80,6 +84,120 @@ const char *arm_intr_string(void *cookie)
return arm_intr_func.intr_string(cookie);
}
+/*
+ * Find the interrupt controller either via:
+ * - node's property "interrupt-parrent"
+ * - parent's property "interrupt-parrent"
+ */
+int
+OF_get_interrupt_controller(int node)
+{
+ int phandle;
+
+ if (node == 0)
+ return 0;
+
+ do {
+ if ((phandle = OF_getpropint(node, "interrupt-parent", 0))) {
+ node = OF_getnodebyphandle(phandle);
+ } else {
+ node = OF_parent(node);
+ }
+ } while (node && OF_getproplen(node, "#interrupt-cells") < 0);
+
+ return node;
+}
+
+LIST_HEAD(, interrupt_controller) interrupt_controllers =
+ LIST_HEAD_INITIALIZER(interrupt_controllers);
+
+void
+arm_intr_register_fdt(struct interrupt_controller *ic)
+{
+ ic->ic_cells = OF_getpropint(ic->ic_node, "#interrupt-cells", 0);
+ ic->ic_phandle = OF_getpropint(ic->ic_node, "phandle", 0);
+ if (ic->ic_cells == 0 || ic->ic_phandle == 0)
+ return;
+
+ LIST_INSERT_HEAD(&interrupt_controllers, ic, ic_list);
+}
+
+void *
+arm_intr_establish_fdt(int phandle, int level, int (*func)(void *),
+ void *cookie, char *name)
+{
+ return arm_intr_establish_fdt_idx(phandle, 0, level, func, cookie, name);
+}
+
+void *
+arm_intr_establish_fdt_idx(int phandle, int idx, int level, int (*func)(void *),
+ void *cookie, char *name)
+{
+ struct interrupt_controller *ic;
+ uint32_t *cell, *cells;
+ int i, len, ncells, node, extended = 1;
+ void *val = NULL;
+
+ len = OF_getproplen(phandle, "interrupts-extended");
+ if (len <= 0) {
+ len = OF_getproplen(phandle, "interrupts");
+ extended = 0;
+ }
+ if (len <= 0 || (len % sizeof(uint32_t) != 0))
+ return NULL;
+
+ /* Old style. */
+ if (!extended) {
+ node = OF_get_interrupt_controller(phandle);
+ if (node == 0)
+ return NULL;
+
+ LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
+ if (ic->ic_phandle == node)
+ break;
+ }
+
+ if (ic == NULL)
+ return NULL;
+ }
+
+ cell = cells = malloc(len, M_TEMP, M_WAITOK);
+ if (extended)
+ OF_getpropintarray(phandle, "interrupts-extended", cells, len);
+ else
+ OF_getpropintarray(phandle, "interrupts", cells, len);
+ ncells = len / sizeof(uint32_t);
+
+ for (i = 0; i <= idx && ncells > 0; i++) {
+ if (extended) {
+ node = cell[0];
+
+ LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
+ if (ic->ic_phandle == node)
+ break;
+ }
+
+ if (ic == NULL)
+ break;
+
+ cell++;
+ ncells--;
+ }
+
+ if (i == idx && ncells >= ic->ic_cells && ic->ic_establish) {
+ val = ic->ic_establish(ic->ic_cookie, cell, level,
+ func, cookie, name);
+ break;
+ }
+
+ cell += ic->ic_cells;
+ ncells -= ic->ic_cells;
+ }
+
+ free(cells, M_TEMP, len);
+ return val;
+}
+
int
arm_dflt_splraise(int newcpl)
{
diff --git a/sys/arch/armv7/include/intr.h b/sys/arch/armv7/include/intr.h
index 4d8b42ea449..76f694b4a72 100644
--- a/sys/arch/armv7/include/intr.h
+++ b/sys/arch/armv7/include/intr.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr.h,v 1.2 2015/09/19 02:13:05 jsg Exp $ */
+/* $OpenBSD: intr.h,v 1.3 2016/08/01 14:17:00 patrick Exp $ */
/* $NetBSD: intr.h,v 1.12 2003/06/16 20:00:59 thorpej Exp $ */
/*
@@ -145,6 +145,23 @@ const char *arm_intr_string(void *cookie);
void arm_clock_register(void (*)(void), void (*)(u_int), void (*)(int),
void (*)(void));
+struct interrupt_controller {
+ int ic_node;
+ void *ic_cookie;
+ void *(*ic_establish)(void *, int *, int, int (*)(void *),
+ void *, char *);
+
+ LIST_ENTRY(interrupt_controller) ic_list;
+ uint32_t ic_phandle;
+ uint32_t ic_cells;
+};
+
+void arm_intr_register_fdt(struct interrupt_controller *);
+void *arm_intr_establish_fdt(int, int, int (*)(void *),
+ void *, char *);
+void *arm_intr_establish_fdt_idx(int, int, int, int (*)(void *),
+ void *, char *);
+
#ifdef DIAGNOSTIC
/*
* Although this function is implemented in MI code, it must be in this MD