diff options
author | 2020-07-14 20:37:18 +0000 | |
---|---|---|
committer | 2020-07-14 20:37:18 +0000 | |
commit | c5e78cb5501a5b1ccdc079bed4b10fa40589d2bc (patch) | |
tree | 10a3daeeb98d7b6341452aabcc6d0de54df330c0 | |
parent | Convert option handling for openssl(1) verify. (diff) | |
download | wireguard-openbsd-c5e78cb5501a5b1ccdc079bed4b10fa40589d2bc.tar.xz wireguard-openbsd-c5e78cb5501a5b1ccdc079bed4b10fa40589d2bc.zip |
Add FDT interrupt support.
-rw-r--r-- | sys/arch/powerpc64/include/intr.h | 20 | ||||
-rw-r--r-- | sys/arch/powerpc64/powerpc64/intr.c | 104 |
2 files changed, 122 insertions, 2 deletions
diff --git a/sys/arch/powerpc64/include/intr.h b/sys/arch/powerpc64/include/intr.h index 1b44afb95c1..0b0cbb356ec 100644 --- a/sys/arch/powerpc64/include/intr.h +++ b/sys/arch/powerpc64/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.5 2020/06/14 16:12:09 kettenis Exp $ */ +/* $OpenBSD: intr.h,v 1.6 2020/07/14 20:37:18 kettenis Exp $ */ /* * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org> @@ -95,4 +95,22 @@ extern void (*_setipl)(int); #include <machine/softintr.h> +struct interrupt_controller { + int ic_node; + void *ic_cookie; + void *(*ic_establish)(void *, int *, int, struct cpu_info *, + int (*)(void *), void *, char *); + + LIST_ENTRY(interrupt_controller) ic_list; + uint32_t ic_phandle; + uint32_t ic_cells; +}; + +void interrupt_controller_register(struct interrupt_controller *); + +void *fdt_intr_establish_imap(int, int *, int, int, int (*)(void *), + void *, char *); +void *fdt_intr_establish_imap_cpu(int, int *, int, int, + struct cpu_info *, int (*)(void *), void *, char *); + #endif /* _MACHINE_INTR_H_ */ diff --git a/sys/arch/powerpc64/powerpc64/intr.c b/sys/arch/powerpc64/powerpc64/intr.c index 6efaa31f68f..dbe1ffe8abf 100644 --- a/sys/arch/powerpc64/powerpc64/intr.c +++ b/sys/arch/powerpc64/powerpc64/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.2 2020/06/14 16:12:09 kettenis Exp $ */ +/* $OpenBSD: intr.c,v 1.3 2020/07/14 20:37:18 kettenis Exp $ */ /* * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org> @@ -18,10 +18,13 @@ */ #include <sys/param.h> +#include <sys/malloc.h> #include <sys/systm.h> #include <machine/intr.h> +#include <dev/ofw/openfirm.h> + /* Dummy implementations. */ void dummy_hvi(struct trapframe *); void *dummy_intr_establish(uint32_t, int, int, @@ -172,3 +175,102 @@ dummy_setipl(int new) struct cpu_info *ci = curcpu(); ci->ci_cpl = new; } + +/* + * FDT interrupt support. + */ + +#define MAX_INTERRUPT_CELLS 4 + +struct fdt_intr_handle { + struct interrupt_controller *ih_ic; + void *ih_ih; +}; + +LIST_HEAD(, interrupt_controller) interrupt_controllers = + LIST_HEAD_INITIALIZER(interrupt_controllers); + +void +interrupt_controller_register(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_phandle == 0) + return; + KASSERT(ic->ic_cells <= MAX_INTERRUPT_CELLS); + + LIST_INSERT_HEAD(&interrupt_controllers, ic, ic_list); +} + +void * +fdt_intr_establish_imap(int node, int *reg, int nreg, int level, + int (*func)(void *), void *cookie, char *name) +{ + return fdt_intr_establish_imap_cpu(node, reg, nreg, level, NULL, + func, cookie, name); +} + +void * +fdt_intr_establish_imap_cpu(int node, int *reg, int nreg, int level, + struct cpu_info *ci, int (*func)(void *), void *cookie, char *name) +{ + struct interrupt_controller *ic; + struct fdt_intr_handle *ih; + uint32_t *cell; + uint32_t map_mask[4], *map; + int len, acells, ncells; + void *val = NULL; + + if (nreg != sizeof(map_mask)) + return NULL; + + if (OF_getpropintarray(node, "interrupt-map-mask", map_mask, + sizeof(map_mask)) != sizeof(map_mask)) + return NULL; + + len = OF_getproplen(node, "interrupt-map"); + if (len <= 0) + return NULL; + + map = malloc(len, M_DEVBUF, M_WAITOK); + OF_getpropintarray(node, "interrupt-map", map, len); + + cell = map; + ncells = len / sizeof(uint32_t); + while (ncells > 5) { + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_phandle == cell[4]) + break; + } + + if (ic == NULL) + break; + + acells = OF_getpropint(ic->ic_node, "#address-cells", 0); + if (ncells >= (5 + acells + ic->ic_cells) && + (reg[0] & map_mask[0]) == cell[0] && + (reg[1] & map_mask[1]) == cell[1] && + (reg[2] & map_mask[2]) == cell[2] && + (reg[3] & map_mask[3]) == cell[3] && + ic->ic_establish) { + val = ic->ic_establish(ic->ic_cookie, &cell[5 + acells], + level, ci, func, cookie, name); + break; + } + + cell += (5 + acells + ic->ic_cells); + ncells -= (5 + acells + ic->ic_cells); + } + + if (val == NULL) { + free(map, M_DEVBUF, len); + return NULL; + } + + ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); + ih->ih_ic = ic; + ih->ih_ih = val; + + free(map, M_DEVBUF, len); + return ih; +} |