diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2019-09-29 10:36:53 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2019-09-29 10:36:53 +0000 |
commit | 9789f745c132e7f00e7683f264b0e3b6dff03d99 (patch) | |
tree | f39354d573348eab5926b32383badc4e6b69719a | |
parent | fc15b7740ae91495b666e1f61157355d99262878 (diff) |
Add IPI support. Taken ftrom arm64.
ok patrick@
-rw-r--r-- | sys/arch/arm/arm/cpu.c | 8 | ||||
-rw-r--r-- | sys/arch/arm/cortex/ampintc.c | 170 | ||||
-rw-r--r-- | sys/arch/armv7/armv7/intr.c | 46 | ||||
-rw-r--r-- | sys/arch/armv7/include/intr.h | 56 |
4 files changed, 247 insertions, 33 deletions
diff --git a/sys/arch/arm/arm/cpu.c b/sys/arch/arm/arm/cpu.c index 16602583f52..73f4b03ba42 100644 --- a/sys/arch/arm/arm/cpu.c +++ b/sys/arch/arm/arm/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.48 2019/09/23 18:10:43 kettenis Exp $ */ +/* $OpenBSD: cpu.c,v 1.49 2019/09/29 10:36:52 kettenis Exp $ */ /* $NetBSD: cpu.c,v 1.56 2004/04/14 04:01:49 bsh Exp $ */ @@ -401,12 +401,6 @@ cpu_alloc_idle_pcb(struct cpu_info *ci) } #endif /* MULTIPROCESSOR */ -void -intr_barrier(void *ih) -{ - sched_barrier(NULL); -} - /* * Dynamic voltage and frequency scaling implementation. */ diff --git a/sys/arch/arm/cortex/ampintc.c b/sys/arch/arm/cortex/ampintc.c index c3a99c85cbc..8ee33b0546d 100644 --- a/sys/arch/arm/cortex/ampintc.c +++ b/sys/arch/arm/cortex/ampintc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ampintc.c,v 1.26 2019/09/25 09:21:49 kettenis Exp $ */ +/* $OpenBSD: ampintc.c,v 1.27 2019/09/29 10:36:52 kettenis Exp $ */ /* * Copyright (c) 2007,2009,2011 Dale Rahn <drahn@openbsd.org> * @@ -144,6 +144,8 @@ struct ampintc_softc { uint8_t sc_cpu_mask[ICD_ICTR_CPU_M + 1]; struct evcount sc_spur; struct interrupt_controller sc_ic; + int sc_ipi_reason[ICD_ICTR_CPU_M + 1]; + int sc_ipi_num[2]; }; struct ampintc_softc *ampintc; @@ -169,6 +171,7 @@ struct intrq { int ampintc_match(struct device *, void *, void *); void ampintc_attach(struct device *, struct device *, void *); +void ampintc_cpuinit(void); int ampintc_spllower(int); void ampintc_splx(int); int ampintc_splraise(int); @@ -190,6 +193,12 @@ void ampintc_intr_enable(int); void ampintc_intr_disable(int); void ampintc_intr_config(int, int); void ampintc_route(int, int, struct cpu_info *); +void ampintc_route_irq(void *, int, struct cpu_info *); + +int ampintc_ipi_combined(void *); +int ampintc_ipi_nop(void *); +int ampintc_ipi_ddb(void *); +void ampintc_send_ipi(struct cpu_info *, int); struct cfattach ampintc_ca = { sizeof (struct ampintc_softc), ampintc_match, ampintc_attach @@ -227,6 +236,9 @@ ampintc_attach(struct device *parent, struct device *self, void *aux) struct fdt_attach_args *faa = aux; int i, nintr, ncpu; uint32_t ictr; +#ifdef MULTIPROCESSOR + int nipi, ipiirq[2]; +#endif ampintc = sc; @@ -294,6 +306,66 @@ ampintc_attach(struct device *parent, struct device *self, void *aux) ampintc_setipl, ampintc_intr_establish_ext, ampintc_intr_disestablish, ampintc_intr_string, ampintc_irq_handler); +#ifdef MULTIPROCESSOR + /* setup IPI interrupts */ + + /* + * Ideally we want two IPI interrupts, one for NOP and one for + * DDB, however we can survive if only one is available it is + * possible that most are not available to the non-secure OS. + */ + nipi = 0; + for (i = 0; i < 16; i++) { + int reg, oldreg; + + oldreg = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, + ICD_IPRn(i)); + bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), + oldreg ^ 0x20); + + /* if this interrupt is not usable, route will be zero */ + reg = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i)); + if (reg == oldreg) + continue; + + /* return to original value, will be set when used */ + bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), + oldreg); + + if (nipi == 0) + printf(" ipi: %d", i); + else + printf(", %d", i); + ipiirq[nipi++] = i; + if (nipi == 2) + break; + } + + if (nipi == 0) + panic ("no irq available for IPI"); + + switch (nipi) { + case 1: + ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING, + IPL_IPI|IPL_MPSAFE, ampintc_ipi_combined, sc, "ipi"); + sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0]; + sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[0]; + break; + case 2: + ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING, + IPL_IPI|IPL_MPSAFE, ampintc_ipi_nop, sc, "ipinop"); + sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0]; + ampintc_intr_establish(ipiirq[1], IST_EDGE_RISING, + IPL_IPI|IPL_MPSAFE, ampintc_ipi_ddb, sc, "ipiddb"); + sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1]; + break; + default: + panic("nipi unexpected number %d", nipi); + } + + intr_send_ipi_func = ampintc_send_ipi; +#endif + /* enable interrupts */ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3); bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1); @@ -303,6 +375,8 @@ ampintc_attach(struct device *parent, struct device *self, void *aux) sc->sc_ic.ic_cookie = self; sc->sc_ic.ic_establish = ampintc_intr_establish_fdt; sc->sc_ic.ic_disestablish = ampintc_intr_disestablish; + sc->sc_ic.ic_route = ampintc_route_irq; + sc->sc_ic.ic_cpu_enable = ampintc_cpuinit; arm_intr_register_fdt(&sc->sc_ic); /* attach GICv2M frame controller */ @@ -505,6 +579,47 @@ ampintc_route(int irq, int enable, struct cpu_info *ci) } void +ampintc_cpuinit(void) +{ + struct ampintc_softc *sc = ampintc; + int i; + + /* XXX - this is the only cpu specific call to set this */ + if (sc->sc_cpu_mask[cpu_number()] == 0) { + for (i = 0; i < 32; i++) { + int cpumask = + bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, + ICD_IPTRn(i)); + + if (cpumask != 0) { + sc->sc_cpu_mask[cpu_number()] = cpumask; + break; + } + } + } + + if (sc->sc_cpu_mask[cpu_number()] == 0) + panic("could not determine cpu target mask"); +} + +void +ampintc_route_irq(void *v, int enable, struct cpu_info *ci) +{ + struct ampintc_softc *sc = ampintc; + struct intrhand *ih = v; + + bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1); + bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(ih->ih_irq), 0); + if (enable) { + ampintc_set_priority(ih->ih_irq, + sc->sc_handler[ih->ih_irq].iq_irq_min); + ampintc_intr_enable(ih->ih_irq); + } + + ampintc_route(ih->ih_irq, enable, ci); +} + +void ampintc_irq_handler(void *frame) { struct ampintc_softc *sc = ampintc; @@ -634,7 +749,8 @@ ampintc_intr_establish(int irqno, int type, int level, int (*func)(void *), ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); ih->ih_func = func; ih->ih_arg = arg; - ih->ih_ipl = level; + ih->ih_ipl = level & IPL_IRQMASK; + ih->ih_flags = level & IPL_FLAGMASK; ih->ih_irq = irqno; ih->ih_name = name; @@ -803,3 +919,53 @@ ampintc_intr_disestablish_msi(void *cookie) ampintc_intr_disestablish(*(void **)cookie); *(void **)cookie = NULL; } + +#ifdef MULTIPROCESSOR +int +ampintc_ipi_ddb(void *v) +{ + /* XXX */ + db_enter(); + return 1; +} + +int +ampintc_ipi_nop(void *v) +{ + /* Nothing to do here, just enough to wake up from WFI */ + return 1; +} + +int +ampintc_ipi_combined(void *v) +{ + struct ampintc_softc *sc = (struct ampintc_softc *)v; + + if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_DDB) { + sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP; + return ampintc_ipi_ddb(v); + } else { + return ampintc_ipi_nop(v); + } +} + +void +ampintc_send_ipi(struct cpu_info *ci, int id) +{ + struct ampintc_softc *sc = ampintc; + int sendmask; + + if (ci == curcpu() && id == ARM_IPI_NOP) + return; + + /* never overwrite IPI_DDB with IPI_NOP */ + if (id == ARM_IPI_DDB) + sc->sc_ipi_reason[ci->ci_cpuid] = id; + + /* currently will only send to one cpu */ + sendmask = 1 << (16 + ci->ci_cpuid); + sendmask |= sc->sc_ipi_num[id]; + + bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_SGIR, sendmask); +} +#endif diff --git a/sys/arch/armv7/armv7/intr.c b/sys/arch/armv7/armv7/intr.c index 0e81fc4d54f..ef4fc809c45 100644 --- a/sys/arch/armv7/armv7/intr.c +++ b/sys/arch/armv7/armv7/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.14 2018/08/08 11:06:33 patrick Exp $ */ +/* $OpenBSD: intr.c,v 1.15 2019/09/29 10:36:52 kettenis Exp $ */ /* * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org> * @@ -507,6 +507,16 @@ arm_intr_route(void *cookie, int enable, struct cpu_info *ci) ic->ic_route(ih->ih_ih, enable, ci); } +void +arm_intr_cpu_enable(void) +{ + struct interrupt_controller *ic; + + LIST_FOREACH(ic, &interrupt_controllers, ic_list) + if (ic->ic_cpu_enable) + ic->ic_cpu_enable(); +} + int arm_dflt_splraise(int newcpl) { @@ -754,6 +764,15 @@ cpu_initclocks(void) } void +cpu_startclock(void) +{ + if (arm_clock_func.mpstartclock == NULL) + panic("startclock function not initialized yet"); + + arm_clock_func.mpstartclock(); +} + +void arm_dflt_delay(u_int usecs) { int j; @@ -858,3 +877,28 @@ setstatclockrate(int new) } arm_clock_func.setstatclockrate(new); } + +void +intr_barrier(void *ih) +{ + sched_barrier(NULL); +} + +/* + * IPI implementation + */ + +void arm_no_send_ipi(struct cpu_info *ci, int id); +void (*intr_send_ipi_func)(struct cpu_info *, int) = arm_no_send_ipi; + +void +arm_send_ipi(struct cpu_info *ci, int id) +{ + (*intr_send_ipi_func)(ci, id); +} + +void +arm_no_send_ipi(struct cpu_info *ci, int id) +{ + panic("arm_send_ipi() called: no ipi function"); +} diff --git a/sys/arch/armv7/include/intr.h b/sys/arch/armv7/include/intr.h index be2035aaca6..e08b4942927 100644 --- a/sys/arch/armv7/include/intr.h +++ b/sys/arch/armv7/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.11 2019/05/06 03:34:43 mlarkin Exp $ */ +/* $OpenBSD: intr.h,v 1.12 2019/09/29 10:36:52 kettenis Exp $ */ /* $NetBSD: intr.h,v 1.12 2003/06/16 20:00:59 thorpej Exp $ */ /* @@ -41,27 +41,29 @@ #ifdef _KERNEL -/* Interrupt priority "levels". */ +/* Interrupt priority `levels'; not mutually exclusive. */ #define IPL_NONE 0 /* nothing */ -#define IPL_SOFT 1 /* generic software interrupts */ -#define IPL_SOFTCLOCK 2 /* software clock interrupt */ -#define IPL_SOFTNET 3 /* software network interrupt */ -#define IPL_SOFTTTY 4 /* software serial interrupt */ +#define IPL_SOFT 1 /* soft interrupts */ +#define IPL_SOFTCLOCK 2 /* soft clock interrupts */ +#define IPL_SOFTNET 3 /* soft network interrupts */ +#define IPL_SOFTTTY 4 /* soft terminal interrupts */ #define IPL_BIO 5 /* block I/O */ #define IPL_NET 6 /* network */ -#define IPL_TTY 7 /* terminals */ +#define IPL_TTY 7 /* terminal */ #define IPL_VM 8 /* memory allocation */ -#define IPL_AUDIO 9 /* audio device */ -#define IPL_CLOCK 10 /* clock interrupt */ -#define IPL_STATCLOCK 11 /* statistics clock interrupt */ -#define IPL_SCHED 12 /* everything */ -#define IPL_HIGH 12 /* everything */ - -#define NIPL 13 - -/* Interrupt priority "flags". */ -#define IPL_MPSAFE 0 /* no "mpsafe" interrupts */ -#define IPL_MPFLOOR IPL_NONE /* no MP on armv7 */ +#define IPL_AUDIO 9 /* audio */ +#define IPL_CLOCK 10 /* clock */ +#define IPL_SCHED IPL_CLOCK +#define IPL_STATCLOCK IPL_CLOCK +#define IPL_HIGH 11 /* everything */ +#define IPL_IPI 12 /* interprocessor interrupt */ +#define NIPL 13 /* number of levels */ + +#define IPL_MPFLOOR IPL_TTY +/* Interrupt priority 'flags'. */ +#define IPL_IRQMASK 0xf /* priority only */ +#define IPL_FLAGMASK 0xf00 /* flags only*/ +#define IPL_MPSAFE 0x100 /* 'mpsafe' interrupt, no kernel lock */ /* Interrupt sharing types. */ #define IST_NONE 0 /* none */ @@ -69,11 +71,11 @@ #define IST_EDGE 2 /* edge-triggered */ #define IST_LEVEL 3 /* level-triggered */ -#define IST_LEVEL_LOW IST_LEVEL -#define IST_LEVEL_HIGH 4 -#define IST_EDGE_FALLING IST_EDGE -#define IST_EDGE_RISING 5 -#define IST_EDGE_BOTH 6 +#define IST_LEVEL_LOW IST_LEVEL +#define IST_LEVEL_HIGH 4 +#define IST_EDGE_FALLING IST_EDGE +#define IST_EDGE_RISING 5 +#define IST_EDGE_BOTH 6 #ifndef _LOCORE #include <sys/device.h> @@ -158,6 +160,7 @@ struct interrupt_controller { void (*ic_enable)(void *); void (*ic_disable)(void *); void (*ic_route)(void *, int, struct cpu_info *); + void (*ic_cpu_enable)(void); LIST_ENTRY(interrupt_controller) ic_list; uint32_t ic_phandle; @@ -178,11 +181,18 @@ void arm_intr_disestablish_fdt(void *); void arm_intr_enable(void *); void arm_intr_disable(void *); void arm_intr_route(void *, int, struct cpu_info *); +void arm_intr_cpu_enable(void); void *arm_intr_parent_establish_fdt(void *, int *, int, int (*)(void *), void *, char *); void arm_intr_parent_disestablish_fdt(void *); +void arm_send_ipi(struct cpu_info *, int); +extern void (*intr_send_ipi_func)(struct cpu_info *, int); + +#define ARM_IPI_NOP 0 +#define ARM_IPI_DDB 1 + #ifdef DIAGNOSTIC /* * Although this function is implemented in MI code, it must be in this MD |