-/* $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>
*
#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);
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];
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)
{
-/* $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 $ */
/*
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