powerpc64: switch to clockintr
authorcheloha <cheloha@openbsd.org>
Tue, 29 Nov 2022 01:04:44 +0000 (01:04 +0000)
committercheloha <cheloha@openbsd.org>
Tue, 29 Nov 2022 01:04:44 +0000 (01:04 +0000)
- 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@

sys/arch/powerpc64/include/_types.h
sys/arch/powerpc64/include/cpu.h
sys/arch/powerpc64/powerpc64/clock.c

index c93d8b0..63fd7c9 100644 (file)
@@ -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];
index 7df5a2b..0a8cdb3 100644 (file)
@@ -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 <kettenis@openbsd.org>
@@ -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 20e81c6..87ec065 100644 (file)
@@ -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 <kettenis@openbsd.org>
 #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