This patch switches riscv64 to clockintr(9).
jca@ has been testing it (on a SiFive board?). It has survived two
parallel release builds and upgrades from the resulting bsd.rd.
It could use testing on another machine. Are there other practical
machines aside from SiFive?
Index: sys/arch/riscv64/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/riscv64/include/cpu.h,v
retrieving revision 1.14
diff -u -p -r1.14 cpu.h
--- sys/arch/riscv64/include/cpu.h 29 Aug 2022 02:01:18 -0000 1.14
+++ sys/arch/riscv64/include/cpu.h 6 Nov 2022 19:34:10 -0000
@@ -68,6 +68,7 @@
#define PROC_PC(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sepc)
#define PROC_STACK(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sp)
+#include <sys/clockintr.h>
#include <sys/device.h>
#include <sys/sched.h>
#include <sys/srp.h>
@@ -89,9 +90,7 @@ struct cpu_info {
struct pcb *ci_curpcb;
struct pcb *ci_idle_pcb;
- uint64_t ci_lasttb;
- uint64_t ci_nexttimerevent;
- uint64_t ci_nextstatevent;
+ struct clockintr_queue ci_queue;
volatile int ci_timer_deferred;
uint32_t ci_cpl;
Index: sys/arch/riscv64/include/_types.h
===================================================================
RCS file: /cvs/src/sys/arch/riscv64/include/_types.h,v
retrieving revision 1.3
diff -u -p -r1.3 _types.h
--- sys/arch/riscv64/include/_types.h 12 May 2021 01:20:52 -0000 1.3
+++ sys/arch/riscv64/include/_types.h 6 Nov 2022 19:34:10 -0000
@@ -35,6 +35,8 @@
#ifndef _MACHINE__TYPES_H_
#define _MACHINE__TYPES_H_
+#define __HAVE_CLOCKINTR
+
#if defined(_KERNEL)
typedef struct label_t {
long val[14];
Index: sys/arch/riscv64/riscv64/clock.c
===================================================================
RCS file: /cvs/src/sys/arch/riscv64/riscv64/clock.c,v
retrieving revision 1.5
diff -u -p -r1.5 clock.c
--- sys/arch/riscv64/riscv64/clock.c 8 Sep 2022 03:09:40 -0000 1.5
+++ sys/arch/riscv64/riscv64/clock.c 6 Nov 2022 19:34:10 -0000
@@ -20,6 +20,7 @@
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
+#include <sys/clockintr.h>
#include <sys/evcount.h>
#include <sys/stdint.h>
#include <sys/timetc.h>
@@ -30,13 +31,18 @@
#include <riscv64/dev/riscv_cpu_intc.h>
extern uint64_t tb_freq; /* machdep.c */
-
-uint64_t tick_increment;
-uint64_t statmin;
-uint32_t statvar;
+uint64_t timer_nsec_max;
+uint64_t timer_nsec_cycle_ratio;
struct evcount clock_count;
-struct evcount stat_count;
+
+void timer_rearm(void *, uint64_t);
+void timer_trigger(void *);
+
+const struct intrclock timer_intrclock = {
+ .ic_rearm = timer_rearm,
+ .ic_trigger = timer_trigger
+};
u_int tb_get_timecount(struct timecounter *);
@@ -54,6 +60,23 @@ static struct timecounter tb_timecounter
void cpu_startclock(void);
int clock_intr(void *);
+void
+timer_rearm(void *unused, uint64_t nsecs)
+{
+ uint32_t cycles;
+
+ if (nsecs > timer_nsec_max)
+ nsecs = timer_nsec_max;
+ cycles = (nsecs * timer_nsec_cycle_ratio) >> 32;
+ sbi_set_timer(rdtime() + cycles);
+}
+
+void
+timer_trigger(void *unused)
+{
+ sbi_set_timer(0);
+}
+
u_int
tb_get_timecount(struct timecounter *tc)
{
@@ -66,18 +89,17 @@ cpu_initclocks(void)
tb_timecounter.tc_frequency = tb_freq;
tc_init(&tb_timecounter);
- tick_increment = tb_freq / hz;
+ timer_nsec_cycle_ratio = tb_freq * (1ULL << 32) / 1000000000;
+ timer_nsec_max = UINT64_MAX / timer_nsec_cycle_ratio;
stathz = 100;
profhz = 1000; /* must be a multiple of stathz */
-
- setstatclockrate(stathz);
+ clockintr_init(CL_RNDSTAT);
riscv_intc_intr_establish(IRQ_TIMER_SUPERVISOR, 0,
clock_intr, NULL, NULL);
evcount_attach(&clock_count, "clock", NULL);
- evcount_attach(&stat_count, "stat", NULL);
cpu_startclock();
}
@@ -85,14 +107,8 @@ cpu_initclocks(void)
void
cpu_startclock(void)
{
- struct cpu_info *ci = curcpu();
- uint64_t nextevent;
-
- ci->ci_lasttb = rdtime();
- ci->ci_nexttimerevent = ci->ci_lasttb + tick_increment;
- nextevent = ci->ci_nextstatevent = ci->ci_nexttimerevent;
-
- sbi_set_timer(nextevent);
+ clockintr_cpu_init(&timer_intrclock);
+ clockintr_trigger();
csr_set(sie, SIE_STIE);
}
@@ -100,93 +116,35 @@ int
clock_intr(void *frame)
{
struct cpu_info *ci = curcpu();
- uint64_t tb, prevtb;
- uint64_t nextevent;
- uint32_t r;
- int nstats;
int s;
+ sbi_set_timer(UINT64_MAX); /* clear timer interrupt */
+
/*
* If the clock interrupt is masked, defer all clock interrupt
* work until the clock interrupt is unmasked from splx(9).
*/
if (ci->ci_cpl >= IPL_CLOCK) {
ci->ci_timer_deferred = 1;
- sbi_set_timer(UINT64_MAX);
return 0;
}
ci->ci_timer_deferred = 0;
- /*
- * Based on the actual time delay since the last clock interrupt,
- * we arrange for earlier interrupt next time.
- */
-
- tb = rdtime();
-
- 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;
-
- sbi_set_timer(nextevent);
-
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);
-
+ clockintr_dispatch(frame);
intr_disable();
splx(s);
+ clock_count.ec_count++;
+
return 0;
}
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);
+ clockintr_setstatclockrate(newhz);
}
void