From fa086fd2b58313156e4f69f5c66249130c1733cf Mon Sep 17 00:00:00 2001 From: cheloha Date: Sat, 19 Nov 2022 16:02:37 +0000 Subject: [PATCH] riscv64: switch to clockintr - Remove riscv64-specific clock interrupt scheduling bits from cpu_info. - Remove riscv64-specific randomized statclock() bits from riscv64/clock.c. - Remove the 'stat_count' evcount. All clock interrupts are now counted via the 'clock_count' evcount. - Wire up timer_intrclock. With input from jca@, kettenis@. Tested by jca@. Link: https://marc.info/?l=openbsd-tech&m=166776413003655&w=2 ok kettenis@ jca@ mlarkin@ --- sys/arch/riscv64/include/_types.h | 4 +- sys/arch/riscv64/include/cpu.h | 7 +- sys/arch/riscv64/riscv64/clock.c | 122 ++++++++++-------------------- 3 files changed, 46 insertions(+), 87 deletions(-) diff --git a/sys/arch/riscv64/include/_types.h b/sys/arch/riscv64/include/_types.h index 394d4ab577f..0704283275d 100644 --- a/sys/arch/riscv64/include/_types.h +++ b/sys/arch/riscv64/include/_types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: _types.h,v 1.3 2021/05/12 01:20:52 jsg Exp $ */ +/* $OpenBSD: _types.h,v 1.4 2022/11/19 16:02:37 cheloha Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -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]; diff --git a/sys/arch/riscv64/include/cpu.h b/sys/arch/riscv64/include/cpu.h index b90219e6050..4d0aca11991 100644 --- a/sys/arch/riscv64/include/cpu.h +++ b/sys/arch/riscv64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.14 2022/08/29 02:01:18 jsg Exp $ */ +/* $OpenBSD: cpu.h,v 1.15 2022/11/19 16:02:37 cheloha Exp $ */ /* * Copyright (c) 2019 Mike Larkin @@ -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 #include #include #include @@ -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; diff --git a/sys/arch/riscv64/riscv64/clock.c b/sys/arch/riscv64/riscv64/clock.c index b1ddd387a40..437399e612a 100644 --- a/sys/arch/riscv64/riscv64/clock.c +++ b/sys/arch/riscv64/riscv64/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.5 2022/09/08 03:09:40 cheloha Exp $ */ +/* $OpenBSD: clock.c,v 1.6 2022/11/19 16:02:37 cheloha Exp $ */ /* * Copyright (c) 2020 Mark Kettenis @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -30,13 +31,18 @@ #include 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 -- 2.20.1