summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2020-06-10 19:06:53 +0000
committerkettenis <kettenis@openbsd.org>2020-06-10 19:06:53 +0000
commitff56acc25e8db3a5cb1bd6491e816eb5452e11af (patch)
tree279302e63d8ba883f51cac2bf6f50eaa853b4378
parentAllocate MSIs from the range provided by the device tree and bind them (diff)
downloadwireguard-openbsd-ff56acc25e8db3a5cb1bd6491e816eb5452e11af.tar.xz
wireguard-openbsd-ff56acc25e8db3a5cb1bd6491e816eb5452e11af.zip
Add clock interrupt support, adapted from the randomized dual clock
implementation from Dale Rahn but relicensed (with his permission) under our standard ISC license.
-rw-r--r--sys/arch/powerpc64/conf/files.powerpc643
-rw-r--r--sys/arch/powerpc64/include/cpu.h8
-rw-r--r--sys/arch/powerpc64/powerpc64/clock.c186
-rw-r--r--sys/arch/powerpc64/powerpc64/cpu.c13
-rw-r--r--sys/arch/powerpc64/powerpc64/machdep.c14
-rw-r--r--sys/arch/powerpc64/powerpc64/trap.c13
6 files changed, 209 insertions, 28 deletions
diff --git a/sys/arch/powerpc64/conf/files.powerpc64 b/sys/arch/powerpc64/conf/files.powerpc64
index e54b7bd7bfa..24919fd4741 100644
--- a/sys/arch/powerpc64/conf/files.powerpc64
+++ b/sys/arch/powerpc64/conf/files.powerpc64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.powerpc64,v 1.10 2020/06/10 15:10:51 kettenis Exp $
+# $OpenBSD: files.powerpc64,v 1.11 2020/06/10 19:06:53 kettenis Exp $
maxpartitions 16
maxusers 2 8 128
@@ -7,6 +7,7 @@ file arch/powerpc64/powerpc64/locore.S
file arch/powerpc64/powerpc64/autoconf.c
file arch/powerpc64/powerpc64/bus_dma.c
file arch/powerpc64/powerpc64/bus_space.c
+file arch/powerpc64/powerpc64/clock.c
file arch/powerpc64/powerpc64/conf.c
file arch/powerpc64/powerpc64/cpu.c
file arch/powerpc64/powerpc64/db_disasm.c ddb
diff --git a/sys/arch/powerpc64/include/cpu.h b/sys/arch/powerpc64/include/cpu.h
index edabe01e045..51791d5fdde 100644
--- a/sys/arch/powerpc64/include/cpu.h
+++ b/sys/arch/powerpc64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.8 2020/06/09 18:58:58 kettenis Exp $ */
+/* $OpenBSD: cpu.h,v 1.9 2020/06/10 19:06:53 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -49,6 +49,12 @@ struct cpu_info {
#define CPUSAVE_LEN 9
register_t ci_tempsave[CPUSAVE_LEN];
+ uint64_t ci_lasttb;
+ uint64_t ci_nexttimerevent;
+ uint64_t ci_nextstatevent;
+ int ci_statspending;
+
+ volatile int ci_cpl;
uint32_t ci_ipending;
#ifdef DIAGNOSTIC
int ci_mutex_level;
diff --git a/sys/arch/powerpc64/powerpc64/clock.c b/sys/arch/powerpc64/powerpc64/clock.c
new file mode 100644
index 00000000000..2b1d1705972
--- /dev/null
+++ b/sys/arch/powerpc64/powerpc64/clock.c
@@ -0,0 +1,186 @@
+/* $OpenBSD: clock.c,v 1.1 2020/06/10 19:06:53 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
+ * Copyright (c) 2003 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/evcount.h>
+#include <sys/timetc.h>
+
+#include <machine/cpufunc.h>
+
+extern uint64_t tb_freq; /* cpu.c */
+
+uint64_t tick_increment;
+uint64_t statmin;
+uint32_t statvar;
+
+struct evcount clock_count;
+struct evcount stat_count;
+
+u_int tb_get_timecount(struct timecounter *);
+
+static struct timecounter tb_timecounter = {
+ tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL
+};
+
+void cpu_startclock(void);
+
+u_int
+tb_get_timecount(struct timecounter *tc)
+{
+ return mftb();
+}
+
+void
+cpu_initclocks(void)
+{
+ tick_increment = tb_freq / hz;
+
+ stathz = 100;
+ profhz = 1000; /* must be a multiple of stathz */
+
+ setstatclockrate(stathz);
+
+ evcount_attach(&clock_count, "clock", NULL);
+ evcount_attach(&stat_count, "stat", NULL);
+
+ cpu_startclock();
+
+ tb_timecounter.tc_frequency = tb_freq;
+ tc_init(&tb_timecounter);
+}
+
+void
+cpu_startclock(void)
+{
+ struct cpu_info *ci = curcpu();
+ uint64_t nextevent;
+
+ ci->ci_lasttb = mftb();
+ ci->ci_nexttimerevent = ci->ci_lasttb + tick_increment;
+ nextevent = ci->ci_nextstatevent = ci->ci_nexttimerevent;
+
+ mtdec(nextevent - ci->ci_lasttb);
+ intr_enable();
+}
+
+void
+decr_intr(struct trapframe *frame)
+{
+ struct cpu_info *ci = curcpu();
+ uint64_t tb, prevtb;
+ uint64_t nextevent;
+ uint32_t r;
+ int nstats;
+ int s;
+
+ /*
+ * Based on the actual time delay since the last decrementer reload,
+ * we arrange for earlier interrupt next time.
+ */
+
+ tb = mftb();
+
+ while (ci->ci_nexttimerevent <= tb)
+ ci->ci_nexttimerevent += tick_increment;
+
+ prevtb = ci->ci_nexttimerevent - tick_increment;
+
+ for (nstats = 0; ci->ci_nextstatevent <= tb; nstats++) {
+ do {
+ r = random() & (statvar - 1);
+ } while (r == 0); /* random == 0 not allowed */
+ ci->ci_nextstatevent += statmin + r;
+ }
+ stat_count.ec_count += nstats;
+
+ if (ci->ci_nexttimerevent < ci->ci_nextstatevent)
+ nextevent = ci->ci_nexttimerevent;
+ else
+ nextevent = ci->ci_nextstatevent;
+
+ /*
+ * Transition of the MSB will trigger a decrementer interrupt.
+ * So the next sequence is guaranteed to do the job without a
+ * systematic skew.
+ */
+ mtdec(nextevent - tb);
+ mtdec(nextevent - mftb());
+
+ if (ci->ci_cpl >= IPL_CLOCK) {
+ ci->ci_statspending += nstats;
+ } else {
+ nstats += ci->ci_statspending;
+ ci->ci_statspending = 0;
+
+ s = splclock();
+ intr_enable();
+
+ /*
+ * Do standard timer interrupt stuff.
+ */
+ while (ci->ci_lasttb < prevtb) {
+ ci->ci_lasttb += tick_increment;
+ clock_count.ec_count++;
+ hardclock((struct clockframe *)frame);
+ }
+
+ while (nstats-- > 0)
+ statclock((struct clockframe *)frame);
+
+ intr_disable();
+ splx(s);
+ }
+}
+
+void
+setstatclockrate(int newhz)
+{
+ uint64_t stat_increment;
+ uint64_t min_increment;
+ uint32_t var;
+ u_long msr;
+
+ msr = intr_disable();
+
+ stat_increment = tb_freq / newhz;
+ var = 0x40000000; /* really big power of two */
+ /* Find largest 2^n which is nearly smaller than statint/2. */
+ min_increment = stat_increment / 2 + 100;
+ while (var > min_increment)
+ var >>= 1;
+
+ /* Not atomic, but we can probably live with that. */
+ statmin = stat_increment - (var >> 1);
+ statvar = var;
+
+ intr_restore(msr);
+}
+
+void
+delay(u_int us)
+{
+ uint64_t tb;
+
+ tb = mftb();
+ tb += (us * tb_freq + 999999) / 1000000;
+ while (tb > mftb())
+ continue;
+}
diff --git a/sys/arch/powerpc64/powerpc64/cpu.c b/sys/arch/powerpc64/powerpc64/cpu.c
index e768f032323..26bdf0c0c7c 100644
--- a/sys/arch/powerpc64/powerpc64/cpu.c
+++ b/sys/arch/powerpc64/powerpc64/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.5 2020/06/07 20:50:24 kettenis Exp $ */
+/* $OpenBSD: cpu.c,v 1.6 2020/06/10 19:06:53 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -77,14 +77,3 @@ cpu_attach(struct device *parent, struct device *dev, void *aux)
/* Update timebase frequency to reflect reality. */
tb_freq = OF_getpropint(faa->fa_node, "timebase-frequency", tb_freq);
}
-
-void
-delay(u_int us)
-{
- uint64_t tb;
-
- tb = mftb();
- tb += (us * tb_freq + 999999) / 1000000;
- while (tb > mftb())
- continue;
-}
diff --git a/sys/arch/powerpc64/powerpc64/machdep.c b/sys/arch/powerpc64/powerpc64/machdep.c
index 91878121606..3e086fc0af8 100644
--- a/sys/arch/powerpc64/powerpc64/machdep.c
+++ b/sys/arch/powerpc64/powerpc64/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.18 2020/06/08 18:37:16 kettenis Exp $ */
+/* $OpenBSD: machdep.c,v 1.19 2020/06/10 19:06:53 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -444,18 +444,6 @@ cpu_startup(void)
}
void
-cpu_initclocks(void)
-{
- printf("%s\n", __func__);
-}
-
-void
-setstatclockrate(int new)
-{
- printf("%s\n", __func__);
-}
-
-void
setregs(struct proc *p, struct exec_package *pack, u_long stack,
register_t *retval)
{
diff --git a/sys/arch/powerpc64/powerpc64/trap.c b/sys/arch/powerpc64/powerpc64/trap.c
index 7f37d556d7c..07f8020c5d7 100644
--- a/sys/arch/powerpc64/powerpc64/trap.c
+++ b/sys/arch/powerpc64/powerpc64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.3 2020/05/27 22:22:04 gkoehler Exp $ */
+/* $OpenBSD: trap.c,v 1.4 2020/06/10 19:06:53 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -24,9 +24,17 @@
#endif
#include <machine/trap.h>
+void decr_intr(struct trapframe *); /* clock.c */
+
void
trap(struct trapframe *frame)
{
+ switch (frame->exc) {
+ case EXC_DECR:
+ decr_intr(frame);
+ return;
+ }
+
#ifdef DDB
/* At a trap instruction, enter the debugger. */
if (frame->exc == EXC_PGM && (frame->srr1 & EXC_PGM_TRAP)) {
@@ -36,5 +44,8 @@ trap(struct trapframe *frame)
}
#endif
+ if (frame->exc == EXC_DSI)
+ printf("dsisr %lx dar %lx\n", frame->dsisr, frame->dar);
+
panic("trap type %lx at lr %lx", frame->exc, frame->lr);
}