summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2019-09-29 10:36:53 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2019-09-29 10:36:53 +0000
commit9789f745c132e7f00e7683f264b0e3b6dff03d99 (patch)
treef39354d573348eab5926b32383badc4e6b69719a
parentfc15b7740ae91495b666e1f61157355d99262878 (diff)
Add IPI support. Taken ftrom arm64.
ok patrick@
-rw-r--r--sys/arch/arm/arm/cpu.c8
-rw-r--r--sys/arch/arm/cortex/ampintc.c170
-rw-r--r--sys/arch/armv7/armv7/intr.c46
-rw-r--r--sys/arch/armv7/include/intr.h56
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