From: cheloha Date: Tue, 29 Nov 2022 01:04:44 +0000 (+0000) Subject: powerpc64: switch to clockintr X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=aca18452b3e5efd8fd47a100cc3cfd33ce5c9671;p=openbsd powerpc64: switch to clockintr - Remove powerpc64-specific clock interrupt scheduling bits from cpu_info. - Remove powerpc64-specific randomized statclock() bits from powerpc64/clock.c. - Remove the 'stat_count' evcount. All clock interrupts are now counted via the 'clock_count' evcount. - Wire up dec_intrclock. Bringup help from gkoehler@. Tested by gkoehler@: this patch has survived four kernel-release-upgrade cycles on a Raptor Talos II T2P9S01 sporting a quad-core POWER9 CPU. Link: https://marc.info/?l=openbsd-tech&m=166776404803622&w=2 ok gkoehler@ mlarkin@ --- diff --git a/sys/arch/powerpc64/include/_types.h b/sys/arch/powerpc64/include/_types.h index c93d8b0d84e..63fd7c9c63b 100644 --- a/sys/arch/powerpc64/include/_types.h +++ b/sys/arch/powerpc64/include/_types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: _types.h,v 1.2 2020/05/27 22:22:04 gkoehler Exp $ */ +/* $OpenBSD: _types.h,v 1.3 2022/11/29 01:04:44 cheloha Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -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]; diff --git a/sys/arch/powerpc64/include/cpu.h b/sys/arch/powerpc64/include/cpu.h index 7df5a2ba921..0a8cdb33631 100644 --- a/sys/arch/powerpc64/include/cpu.h +++ b/sys/arch/powerpc64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.32 2022/08/09 04:40:08 cheloha Exp $ */ +/* $OpenBSD: cpu.h,v 1.33 2022/11/29 01:04:44 cheloha Exp $ */ /* * Copyright (c) 2020 Mark Kettenis @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -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; diff --git a/sys/arch/powerpc64/powerpc64/clock.c b/sys/arch/powerpc64/powerpc64/clock.c index 20e81c62414..87ec0650067 100644 --- a/sys/arch/powerpc64/powerpc64/clock.c +++ b/sys/arch/powerpc64/powerpc64/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.6 2022/11/05 16:23:02 cheloha Exp $ */ +/* $OpenBSD: clock.c,v 1.7 2022/11/29 01:04:44 cheloha Exp $ */ /* * Copyright (c) 2020 Mark Kettenis @@ -20,19 +20,26 @@ #include #include #include +#include #include +#include #include #include 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