From 9d06d93cdcec29b480c5d9140c5b936db1b962be Mon Sep 17 00:00:00 2001 From: cheloha Date: Tue, 29 Nov 2022 00:58:05 +0000 Subject: [PATCH] powerpc, macppc: switch to clockintr - Remove powerpc-specific clock interrupt scheduling bits from cpu_info. - Remove macppc-specific randomized statclock() bits from macppc/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@. The patch has survived five or six kernel-release-upgrade cycles on my dual-core PowerMac3,6. Link: https://marc.info/?l=openbsd-tech&m=166776385003520&w=2 ok gkoehler@ mlarkin@ --- sys/arch/macppc/macppc/clock.c | 178 +++++++++--------------------- sys/arch/powerpc/include/_types.h | 4 +- sys/arch/powerpc/include/cpu.h | 9 +- 3 files changed, 60 insertions(+), 131 deletions(-) diff --git a/sys/arch/macppc/macppc/clock.c b/sys/arch/macppc/macppc/clock.c index 707164aa874..eb61a28bd6f 100644 --- a/sys/arch/macppc/macppc/clock.c +++ b/sys/arch/macppc/macppc/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.50 2022/09/08 03:06:33 cheloha Exp $ */ +/* $OpenBSD: clock.c,v 1.51 2022/11/29 00:58:05 cheloha Exp $ */ /* $NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $ */ /* @@ -35,7 +35,9 @@ #include #include #include +#include #include +#include #include #include @@ -46,6 +48,8 @@ #include #include +void dec_rearm(void *, uint64_t); +void dec_trigger(void *); void decr_intr(struct clockframe *frame); u_int tb_get_timecount(struct timecounter *); @@ -54,7 +58,14 @@ u_int tb_get_timecount(struct timecounter *); */ u_int32_t ticks_per_sec = 3125000; u_int32_t ns_per_tick = 320; -static int32_t ticks_per_intr; +uint64_t dec_nsec_cycle_ratio; +uint64_t dec_nsec_max; +int clock_initialized; + +const struct intrclock dec_intrclock = { + .ic_rearm = dec_rearm, + .ic_trigger = dec_trigger +}; static struct timecounter tb_timecounter = { .tc_get_timecount = tb_get_timecount, @@ -75,15 +86,8 @@ static const char *calibrate_tc_models[] = { time_read_t *time_read; time_write_t *time_write; -/* vars for stats */ -int statint; -u_int32_t statvar; -u_int32_t statmin; - static struct evcount clk_count; -static struct evcount stat_count; static int clk_irq = PPC_CLK_IRQ; -static int stat_irq = PPC_STAT_IRQ; extern todr_chip_handle_t todr_handle; struct todr_chip_handle rtc_todr; @@ -115,18 +119,16 @@ rtc_settime(struct todr_chip_handle *handle, struct timeval *tv) void decr_intr(struct clockframe *frame) { - u_int64_t tb; - u_int64_t nextevent; struct cpu_info *ci = curcpu(); - int nstats; int s; - /* - * Check whether we are initialized. - */ - if (!ticks_per_intr) + if (!clock_initialized) return; + clk_count.ec_count++; /* XXX not atomic */ + + ppc_mtdec(UINT32_MAX >> 1); /* clear DEC exception */ + /* * We can't actually mask DEC interrupts at or above IPL_CLOCK * without masking other essential interrupts. To simulate @@ -135,73 +137,15 @@ decr_intr(struct clockframe *frame) */ if (ci->ci_cpl >= IPL_CLOCK) { ci->ci_dec_deferred = 1; - ppc_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 = ppc_mftb(); - while (ci->ci_nexttimerevent <= tb) - ci->ci_nexttimerevent += ticks_per_intr; - - ci->ci_prevtb = ci->ci_nexttimerevent - ticks_per_intr; - - for (nstats = 0; ci->ci_nextstatevent <= tb; nstats++) { - int r; - do { - r = random() & (statvar -1); - } while (r == 0); /* random == 0 not allowed */ - ci->ci_nextstatevent += statmin + r; - } - - /* only count timer ticks for CLK_IRQ */ - stat_count.ec_count += nstats; - - if (ci->ci_nexttimerevent < ci->ci_nextstatevent) - nextevent = ci->ci_nexttimerevent; - else - nextevent = ci->ci_nextstatevent; - - /* - * Need to work about the near constant skew this introduces??? - * reloading tb here could cause a missed tick. - */ - ppc_mtdec(nextevent - tb); - - nstats += ci->ci_statspending; - ci->ci_statspending = 0; - s = splclock(); - - /* - * Reenable interrupts - */ ppc_intr_enable(1); - - /* - * Do standard timer interrupt stuff. - */ - while (ci->ci_lasttb < ci->ci_prevtb) { - /* sync lasttb with hardclock */ - ci->ci_lasttb += ticks_per_intr; - clk_count.ec_count++; - hardclock(frame); - } - - while (nstats-- > 0) - statclock(frame); - + clockintr_dispatch(frame); splx(s); (void) ppc_intr_disable(); - - /* if a tick has occurred while dealing with these, - * dont service it now, delay until the next tick. - */ } void cpu_startclock(void); @@ -210,7 +154,6 @@ void cpu_initclocks(void) { int intrstate; - int minint; u_int32_t first_tb, second_tb; time_t first_sec, sec; int calibrate = 0, n; @@ -242,6 +185,7 @@ cpu_initclocks(void) ticks_per_sec); #endif } + ns_per_tick = 1000000000 / ticks_per_sec; tb_timecounter.tc_frequency = ticks_per_sec; tc_init(&tb_timecounter); @@ -252,23 +196,16 @@ cpu_initclocks(void) intrstate = ppc_intr_disable(); - ticks_per_intr = ticks_per_sec / hz; - stathz = 100; profhz = 1000; /* must be a multiple of stathz */ + clockintr_init(CL_RNDSTAT); - /* init secondary clock to stathz */ - statint = ticks_per_sec / stathz; - statvar = 0x40000000; /* really big power of two */ - /* find largest 2^n which is nearly smaller than statint/2 */ - minint = statint / 2 + 100; - while (statvar > minint) - statvar >>= 1; - statmin = statint - (statvar >> 1); + dec_nsec_cycle_ratio = ticks_per_sec * (1ULL << 32) / 1000000000; + dec_nsec_max = UINT64_MAX / dec_nsec_cycle_ratio; evcount_attach(&clk_count, "clock", &clk_irq); - evcount_attach(&stat_count, "stat", &stat_irq); + clock_initialized = 1; cpu_startclock(); ppc_intr_enable(intrstate); @@ -277,21 +214,8 @@ cpu_initclocks(void) void cpu_startclock(void) { - struct cpu_info *ci = curcpu(); - u_int64_t nextevent; - - ci->ci_lasttb = ppc_mftb(); - - /* - * no point in having random on the first tick, - * it just complicates the code. - */ - ci->ci_nexttimerevent = ci->ci_lasttb + ticks_per_intr; - nextevent = ci->ci_nextstatevent = ci->ci_nexttimerevent; - - ci->ci_statspending = 0; - - ppc_mtdec(nextevent - ci->ci_lasttb); + clockintr_cpu_init(&dec_intrclock); + clockintr_trigger(); } /* @@ -308,31 +232,10 @@ delay(unsigned n) ; } -/* - * Nothing to do. - */ void setstatclockrate(int newhz) { - int minint; - int intrstate; - - intrstate = ppc_intr_disable(); - - statint = ticks_per_sec / newhz; - statvar = 0x40000000; /* really big power of two */ - /* find largest 2^n which is nearly smaller than statint/2 */ - minint = statint / 2 + 100; - while (statvar > minint) - statvar >>= 1; - - statmin = statint - (statvar >> 1); - ppc_intr_enable(intrstate); - - /* - * XXX this allows the next stat timer to occur then it switches - * to the new frequency. Rather than switching instantly. - */ + clockintr_setstatclockrate(newhz); } u_int @@ -340,3 +243,30 @@ tb_get_timecount(struct timecounter *tc) { return ppc_mftbl(); } + +void +dec_rearm(void *unused, uint64_t nsecs) +{ + uint32_t cycles; + int s; + + 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 = ppc_intr_disable(); + ppc_mtdec(cycles); + ppc_intr_enable(s); +} + +void +dec_trigger(void *unused) +{ + int s; + + s = ppc_intr_disable(); + ppc_mtdec(0); + ppc_mtdec(UINT32_MAX); + ppc_intr_enable(s); +} diff --git a/sys/arch/powerpc/include/_types.h b/sys/arch/powerpc/include/_types.h index d036388d798..1cfd400c153 100644 --- a/sys/arch/powerpc/include/_types.h +++ b/sys/arch/powerpc/include/_types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: _types.h,v 1.23 2018/03/05 01:15:25 deraadt Exp $ */ +/* $OpenBSD: _types.h,v 1.24 2022/11/29 00:58:05 cheloha Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -35,6 +35,8 @@ #ifndef _POWERPC__TYPES_H_ #define _POWERPC__TYPES_H_ +#define __HAVE_CLOCKINTR + #if defined(_KERNEL) typedef struct label_t { long val[25]; diff --git a/sys/arch/powerpc/include/cpu.h b/sys/arch/powerpc/include/cpu.h index ce6b7a1d8f1..e80d74e059f 100644 --- a/sys/arch/powerpc/include/cpu.h +++ b/sys/arch/powerpc/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.73 2022/10/21 21:26:49 gkoehler Exp $ */ +/* $OpenBSD: cpu.h,v 1.74 2022/11/29 00:58:05 cheloha Exp $ */ /* $NetBSD: cpu.h,v 1.1 1996/09/30 16:34:21 ws Exp $ */ /* @@ -36,6 +36,7 @@ #include +#include #include #include #include @@ -72,11 +73,7 @@ struct cpu_info { #define DISISAVE_LEN 4 register_t ci_disisave[DISISAVE_LEN]; - volatile u_int64_t ci_nexttimerevent; - volatile u_int64_t ci_prevtb; - volatile u_int64_t ci_lasttb; - volatile u_int64_t ci_nextstatevent; - int ci_statspending; + struct clockintr_queue ci_queue; volatile int ci_ddb_paused; #define CI_DDB_RUNNING 0 -- 2.20.1