From 0ffbfca45c62a5ad651139c1dbdf5fb395902d4c Mon Sep 17 00:00:00 2001 From: patrick Date: Mon, 1 Aug 2016 14:17:00 +0000 Subject: [PATCH] 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@ --- sys/arch/armv7/armv7/intr.c | 120 +++++++++++++++++++++++++++++++++- sys/arch/armv7/include/intr.h | 19 +++++- 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 * @@ -19,12 +19,15 @@ #include #include #include +#include #include #include #include #include +#include + 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 -- 2.20.1