powerpc, macppc: switch to clockintr
authorcheloha <cheloha@openbsd.org>
Tue, 29 Nov 2022 00:58:05 +0000 (00:58 +0000)
committercheloha <cheloha@openbsd.org>
Tue, 29 Nov 2022 00:58:05 +0000 (00:58 +0000)
- 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
sys/arch/powerpc/include/_types.h
sys/arch/powerpc/include/cpu.h

index 707164a..eb61a28 100644 (file)
@@ -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 <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/autoconf.h>
@@ -46,6 +48,8 @@
 #include <dev/clock_subr.h>
 #include <dev/ofw/openfirm.h>
 
+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);
+}
index d036388..1cfd400 100644 (file)
@@ -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];
index ce6b7a1..e80d74e 100644 (file)
@@ -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 <machine/frame.h>
 
+#include <sys/clockintr.h>
 #include <sys/device.h>
 #include <sys/sched.h>
 #include <sys/srp.h>
@@ -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