ARMv7 has four interrupt clocks available.  I think it'll be easier to
review/test if we do the clockintr switch driver by driver instead of
all at once in a massive single email.  When all four driver patches
are confirmed to work, I'll commit them.

Here's a patch to switch agtimer(4/armv7) to clockintr.

- Remove agtimer-specific clock interrupt scheduling bits
  and randomized statclock bits.

- Wire up agtimer_intrclock.

I am looking for a tester to help me get it compiling, and then run it
through a kernel-release-upgrade cycle.

Index: sys/arch/arm/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/arm/include/cpu.h,v
retrieving revision 1.61
diff -u -p -r1.61 cpu.h
--- sys/arch/arm/include/cpu.h  6 Jul 2021 09:34:06 -0000       1.61
+++ sys/arch/arm/include/cpu.h  7 Dec 2022 21:44:08 -0000
@@ -149,6 +149,7 @@ void        arm32_vector_init(vaddr_t, int);
  * Per-CPU information.  For now we assume one CPU.
  */
 
+#include <sys/clockintr.h>
 #include <sys/device.h>
 #include <sys/sched.h>
 #include <sys/srp.h>
@@ -198,7 +199,7 @@ struct cpu_info {
 #ifdef GPROF
        struct gmonparam *ci_gmon;
 #endif
-
+       struct clockintr_queue  ci_queue;
        char                    ci_panicbuf[512];
 };
 
Index: sys/arch/arm/include/_types.h
===================================================================
RCS file: /cvs/src/sys/arch/arm/include/_types.h,v
retrieving revision 1.19
diff -u -p -r1.19 _types.h
--- sys/arch/arm/include/_types.h       5 Mar 2018 01:15:25 -0000       1.19
+++ sys/arch/arm/include/_types.h       7 Dec 2022 21:44:08 -0000
@@ -35,6 +35,8 @@
 #ifndef _ARM__TYPES_H_
 #define _ARM__TYPES_H_
 
+#define        __HAVE_CLOCKINTR
+
 #if defined(_KERNEL)
 typedef struct label_t {
        long val[11];
Index: sys/arch/arm/cortex/agtimer.c
===================================================================
RCS file: /cvs/src/sys/arch/arm/cortex/agtimer.c,v
retrieving revision 1.15
diff -u -p -r1.15 agtimer.c
--- sys/arch/arm/cortex/agtimer.c       12 Mar 2022 14:40:41 -0000      1.15
+++ sys/arch/arm/cortex/agtimer.c       7 Dec 2022 21:44:08 -0000
@@ -17,9 +17,11 @@
  */
 
 #include <sys/param.h>
+#include <sys/clockintr.h>
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/kernel.h>
+#include <sys/stdint.h>
 #include <sys/timetc.h>
 
 #include <machine/intr.h>
@@ -51,28 +53,12 @@ static struct timecounter agtimer_timeco
        .tc_priv = NULL,
 };
 
-struct agtimer_pcpu_softc {
-       uint64_t                pc_nexttickevent;
-       uint64_t                pc_nextstatevent;
-       u_int32_t               pc_ticks_err_sum;
-};
-
 struct agtimer_softc {
        struct device           sc_dev;
        int                     sc_node;
-
-       struct agtimer_pcpu_softc sc_pstat[MAXCPUS];
-
-       u_int32_t               sc_ticks_err_cnt;
        u_int32_t               sc_ticks_per_second;
-       u_int32_t               sc_ticks_per_intr;
-       u_int32_t               sc_statvar;
-       u_int32_t               sc_statmin;
-
-#ifdef AMPTIMER_DEBUG
-       struct evcount          sc_clk_count;
-       struct evcount          sc_stat_count;
-#endif
+       uint64_t                sc_nsec_cycle_ratio;
+       uint64_t                sc_nsec_max;
 };
 
 int            agtimer_match(struct device *, void *, void *);
@@ -81,9 +67,11 @@ uint64_t     agtimer_readcnt64(void);
 int            agtimer_intr(void *);
 void           agtimer_cpu_initclocks(void);
 void           agtimer_delay(u_int);
+void           agtimer_rearm(void *, uint64_t);
 void           agtimer_setstatclockrate(int stathz);
 void           agtimer_set_clockrate(int32_t new_frequency);
 void           agtimer_startclock(void);
+void           agtimer_trigger(void *, uint64_t);
 
 const struct cfattach agtimer_ca = {
        sizeof (struct agtimer_softc), agtimer_match, agtimer_attach
@@ -93,6 +81,11 @@ struct cfdriver agtimer_cd = {
        NULL, "agtimer", DV_DULL
 };
 
+struct intrclock agtimer_intrclock = {
+       .ic_rearm = agtimer_rearm,
+       .ic_trigger = agtimer_trigger
+};
+
 uint64_t
 agtimer_readcnt64(void)
 {
@@ -155,16 +148,13 @@ agtimer_attach(struct device *parent, st
        agtimer_frequency =
            OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency);
        sc->sc_ticks_per_second = agtimer_frequency;
-
+       sc->sc_nsec_cycle_ratio =
+           sc->sc_ticks_per_second * (1ULL << 32) / 1000000000;
+       sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio;
        printf(": %d kHz\n", sc->sc_ticks_per_second / 1000);
 
        /* XXX: disable user access */
 
-#ifdef AMPTIMER_DEBUG
-       evcount_attach(&sc->sc_clk_count, "clock", NULL);
-       evcount_attach(&sc->sc_stat_count, "stat", NULL);
-#endif
-
        /*
         * private timer and interrupts not enabled until
         * timer configures
@@ -175,8 +165,9 @@ agtimer_attach(struct device *parent, st
 
        agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
        agtimer_timecounter.tc_priv = sc;
-
        tc_init(&agtimer_timecounter);
+
+       agtimer_intrclock.ic_cookie = sc;
 }
 
 u_int
@@ -185,72 +176,30 @@ agtimer_get_timecount(struct timecounter
        return agtimer_readcnt64();
 }
 
-int
-agtimer_intr(void *frame)
+void
+agtimer_rearm(void *cookie, uint64_t nsecs)
 {
-       struct agtimer_softc    *sc = agtimer_cd.cd_devs[0];
-       struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
-       uint64_t                 now;
-       uint64_t                 nextevent;
-       uint32_t                 r;
-#if defined(USE_GTIMER_CMP)
-       int                      skip = 1;
-#else
-       int64_t                  delay;
-#endif
-       int                      rc = 0;
-
-       /*
-        * DSR - I know that the tick timer is 64 bits, but the following
-        * code deals with rollover, so there is no point in dealing
-        * with the 64 bit math, just let the 32 bit rollover
-        * do the right thing
-        */
+       struct agtimer_softc *sc = cookie;
+       uint32_t cycles;
 
-       now = agtimer_readcnt64();
-
-       while (pc->pc_nexttickevent <= now) {
-               pc->pc_nexttickevent += sc->sc_ticks_per_intr;
-               pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt;
-
-               /* looping a few times is faster than divide */
-               while (pc->pc_ticks_err_sum > hz) {
-                       pc->pc_nexttickevent += 1;
-                       pc->pc_ticks_err_sum -= hz;
-               }
-
-#ifdef AMPTIMER_DEBUG
-               sc->sc_clk_count.ec_count++;
-#endif
-               rc = 1;
-               hardclock(frame);
-       }
-       while (pc->pc_nextstatevent <= now) {
-               do {
-                       r = random() & (sc->sc_statvar -1);
-               } while (r == 0); /* random == 0 not allowed */
-               pc->pc_nextstatevent += sc->sc_statmin + r;
-
-               /* XXX - correct nextstatevent? */
-#ifdef AMPTIMER_DEBUG
-               sc->sc_stat_count.ec_count++;
-#endif
-               rc = 1;
-               statclock(frame);
-       }
-
-       if (pc->pc_nexttickevent < pc->pc_nextstatevent)
-               nextevent = pc->pc_nexttickevent;
-       else
-               nextevent = pc->pc_nextstatevent;
-
-       delay = nextevent - now;
-       if (delay < 0)
-               delay = 1;
+       if (nsecs > sc->sc_nsec_max)
+               nsecs = sc->sc_nsec_max;
+       cycles = (nsecs * sc->sc_nsec_cycle_ratio) >> 32;
+       if (cycles > INT32_MAX)
+               cycles = INT32_MAX;
+       agtimer_set_tval(cycles);
+}
 
-       agtimer_set_tval(delay);
+void
+agtimer_trigger(void *unused)
+{
+       agtimer_set_tval(0);
+}
 
-       return (rc);
+int
+agtimer_intr(void *frame)
+{
+       return clockintr_dispatch(frame);
 }
 
 void
@@ -264,7 +213,12 @@ agtimer_set_clockrate(int32_t new_freque
                return;
 
        sc->sc_ticks_per_second = agtimer_frequency;
+       sc->sc_nsec_cycle_ratio =
+           sc->sc_ticks_per_second * (1ULL << 32) / 1000000000;
+       sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio;
+
        agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
+
        printf("agtimer0: adjusting clock: new rate %d kHz\n",
            sc->sc_ticks_per_second / 1000);
 }
@@ -273,22 +227,17 @@ void
 agtimer_cpu_initclocks(void)
 {
        struct agtimer_softc    *sc = agtimer_cd.cd_devs[0];
-       struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
        uint32_t                 reg;
-       uint64_t                 next;
 
        stathz = hz;
-       profhz = hz * 10;
+       profhz = stathz * 10;
+       clockintr_init(CL_RNDSTAT);
 
        if (sc->sc_ticks_per_second != agtimer_frequency) {
                agtimer_set_clockrate(agtimer_frequency);
        }
 
-       agtimer_setstatclockrate(stathz);
-
-       sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz;
-       sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
-       pc->pc_ticks_err_sum = 0;
+       clockintr_cpu_init(&agtimer_intrclock);
 
        /* Setup secure and non-secure timer IRQs. */
        arm_intr_establish_fdt_idx(sc->sc_node, 0, IPL_CLOCK,
@@ -296,14 +245,13 @@ agtimer_cpu_initclocks(void)
        arm_intr_establish_fdt_idx(sc->sc_node, 1, IPL_CLOCK,
            agtimer_intr, NULL, "tick");
 
-       next = agtimer_readcnt64() + sc->sc_ticks_per_intr;
-       pc->pc_nexttickevent = pc->pc_nextstatevent = next;
-
        reg = agtimer_get_ctrl();
        reg &= ~GTIMER_CNTP_CTL_IMASK;
        reg |= GTIMER_CNTP_CTL_ENABLE;
-       agtimer_set_tval(sc->sc_ticks_per_second);
+       agtimer_set_tval(INT32_MAX);
        agtimer_set_ctrl(reg);
+
+       clockintr_trigger();
 }
 
 void
@@ -340,45 +288,23 @@ agtimer_delay(u_int usecs)
 void
 agtimer_setstatclockrate(int newhz)
 {
-       struct agtimer_softc    *sc = agtimer_cd.cd_devs[0];
-       int                      minint, statint;
-       int                      s;
-
-       s = splclock();
-
-       statint = sc->sc_ticks_per_second / newhz;
-       /* calculate largest 2^n which is smaller that just over half statint */
-       sc->sc_statvar = 0x40000000; /* really big power of two */
-       minint = statint / 2 + 100;
-       while (sc->sc_statvar > minint)
-               sc->sc_statvar >>= 1;
-
-       sc->sc_statmin = statint - (sc->sc_statvar >> 1);
-
-       splx(s);
-
-       /*
-        * XXX this allows the next stat timer to occur then it switches
-        * to the new frequency. Rather than switching instantly.
-        */
+       clockintr_setstatclockrate(newhz);
 }
 
 void
 agtimer_startclock(void)
 {
-       struct agtimer_softc    *sc = agtimer_cd.cd_devs[0];
-       struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
-       uint64_t nextevent;
        uint32_t reg;
 
-       nextevent = agtimer_readcnt64() + sc->sc_ticks_per_intr;
-       pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent;
+       clockintr_cpu_init(&agtimer_intrclock);
 
        reg = agtimer_get_ctrl();
        reg &= ~GTIMER_CNTP_CTL_IMASK;
        reg |= GTIMER_CNTP_CTL_ENABLE;
-       agtimer_set_tval(sc->sc_ticks_per_second);
+       agtimer_set_tval(INT32_MAX);
        agtimer_set_ctrl(reg);
+
+       clockintr_trigger();
 }
 
 void

Reply via email to