This patch switches powerpc64 to clockintr(9). gkoehler@ has been testing it, I assume on some kind of Raptor Computing Power9. It has survived two parallel release builds and upgrades from the resulting bsd.rd.
Testing on an additional powerpc64 machine would help. Notes: - There are no longer separate interrupt counters for "clock" and "stat". Index: sys/arch/powerpc64/include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/powerpc64/include/cpu.h,v retrieving revision 1.32 diff -u -p -r1.32 cpu.h --- sys/arch/powerpc64/include/cpu.h 9 Aug 2022 04:40:08 -0000 1.32 +++ sys/arch/powerpc64/include/cpu.h 6 Nov 2022 19:50:34 -0000 @@ -46,6 +46,7 @@ #include <machine/psl.h> #include <machine/pte.h> +#include <sys/clockintr.h> #include <sys/device.h> #include <sys/sched.h> #include <sys/srp.h> @@ -71,10 +72,8 @@ struct cpu_info { register_t ci_tempsave[CPUSAVE_LEN]; register_t ci_idle_sp_save; - uint64_t ci_lasttb; - uint64_t ci_nexttimerevent; - uint64_t ci_nextstatevent; - + struct clockintr_queue ci_queue; + volatile int ci_cpl; volatile int ci_dec_deferred; uint32_t ci_ipending; Index: sys/arch/powerpc64/include/_types.h =================================================================== RCS file: /cvs/src/sys/arch/powerpc64/include/_types.h,v retrieving revision 1.2 diff -u -p -r1.2 _types.h --- sys/arch/powerpc64/include/_types.h 27 May 2020 22:22:04 -0000 1.2 +++ sys/arch/powerpc64/include/_types.h 6 Nov 2022 19:50:34 -0000 @@ -34,6 +34,8 @@ #ifndef _MACHINE__TYPES_H_ #define _MACHINE__TYPES_H_ +#define __HAVE_CLOCKINTR + #if defined(_KERNEL) typedef struct label_t { long val[22]; Index: sys/arch/powerpc64/powerpc64/clock.c =================================================================== RCS file: /cvs/src/sys/arch/powerpc64/powerpc64/clock.c,v retrieving revision 1.6 diff -u -p -r1.6 clock.c --- sys/arch/powerpc64/powerpc64/clock.c 5 Nov 2022 16:23:02 -0000 1.6 +++ sys/arch/powerpc64/powerpc64/clock.c 6 Nov 2022 19:50:34 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.6 2022/11/05 16:23:02 cheloha Exp $ */ +/* $OpenBSD: clock.c,v 1.5 2022/08/11 17:15:21 cheloha Exp $ */ /* * Copyright (c) 2020 Mark Kettenis <kette...@openbsd.org> @@ -20,19 +20,26 @@ #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> #include <machine/cpufunc.h> extern uint64_t tb_freq; /* cpu.c */ - -uint64_t tick_increment; -uint64_t statmin; -uint32_t statvar; +uint64_t dec_nsec_cycle_ratio; +uint64_t dec_nsec_max; struct evcount clock_count; -struct evcount stat_count; + +void dec_rearm(void *, uint64_t); +void dec_trigger(void *); + +const struct intrclock dec_intrclock = { + .ic_rearm = dec_rearm, + .ic_trigger = dec_trigger +}; u_int tb_get_timecount(struct timecounter *); @@ -49,6 +56,33 @@ static struct timecounter tb_timecounter void cpu_startclock(void); +void +dec_rearm(void *unused, uint64_t nsecs) +{ + u_long s; + uint32_t cycles; + + if (nsecs > dec_nsec_max) + nsecs = dec_nsec_max; + cycles = (nsecs * dec_nsec_cycle_ratio) >> 32; + if (cycles > UINT32_MAX >> 1) + cycles = UINT32_MAX >> 1; + s = intr_disable(); + mtdec(cycles); + intr_restore(s); +} + +void +dec_trigger(void *unused) +{ + u_long s; + + s = intr_disable(); + mtdec(0); + mtdec(UINT32_MAX); + intr_restore(s); +} + u_int tb_get_timecount(struct timecounter *tc) { @@ -61,15 +95,14 @@ cpu_initclocks(void) tb_timecounter.tc_frequency = tb_freq; tc_init(&tb_timecounter); - tick_increment = tb_freq / hz; + dec_nsec_cycle_ratio = tb_freq * (1ULL << 32) / 1000000000; + dec_nsec_max = UINT64_MAX / dec_nsec_cycle_ratio; stathz = 100; profhz = 1000; /* must be a multiple of stathz */ - - setstatclockrate(stathz); + clockintr_init(CL_RNDSTAT); evcount_attach(&clock_count, "clock", NULL); - evcount_attach(&stat_count, "stat", NULL); cpu_startclock(); } @@ -77,14 +110,8 @@ cpu_initclocks(void) 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); + clockintr_cpu_init(&dec_intrclock); + clockintr_trigger(); intr_enable(); } @@ -92,71 +119,25 @@ 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; + clock_count.ec_count++; + + mtdec(UINT32_MAX >> 1); /* clear DEC exception */ + /* * If the clock interrupt is masked, postpone all work until * it is unmasked in splx(9). */ if (ci->ci_cpl >= IPL_CLOCK) { ci->ci_dec_deferred = 1; - mtdec(UINT32_MAX >> 1); /* clear DEC exception */ return; } ci->ci_dec_deferred = 0; - /* - * 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()); - 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); } @@ -164,25 +145,7 @@ decr_intr(struct trapframe *frame) 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