agtimer(4/armv7): switch to clockintr
authorcheloha <cheloha@openbsd.org>
Tue, 17 Jan 2023 02:58:22 +0000 (02:58 +0000)
committercheloha <cheloha@openbsd.org>
Tue, 17 Jan 2023 02:58:22 +0000 (02:58 +0000)
- Strip out custom hardclock/statclock scheduling code.
- Remove debug evcount code.  We can no longer differentiate between
  hardclock and statclock in the driver.
- Wire up agtimer_intrclock.

With tweaks from miod@ and jca@.  Tested by jca@ and kettenis@.

Link: https://marc.info/?l=openbsd-tech&m=167044965011140&w=2
ok kettenis@

sys/arch/arm/cortex/agtimer.c

index 6b5505f..77ecfbb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: agtimer.c,v 1.15 2022/03/12 14:40:41 mpi Exp $ */
+/* $OpenBSD: agtimer.c,v 1.16 2023/01/17 02:58:22 cheloha Exp $ */
 /*
  * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
  * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/clockintr.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_timecounter = {
        .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 *);
@@ -93,6 +79,14 @@ struct cfdriver agtimer_cd = {
        NULL, "agtimer", DV_DULL
 };
 
+void agtimer_rearm(void *, uint64_t);
+void agtimer_trigger(void *);
+
+struct intrclock agtimer_intrclock = {
+       .ic_rearm = agtimer_rearm,
+       .ic_trigger = agtimer_trigger
+};
+
 uint64_t
 agtimer_readcnt64(void)
 {
@@ -155,16 +149,13 @@ agtimer_attach(struct device *parent, struct device *self, void *aux)
        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 +166,9 @@ agtimer_attach(struct device *parent, struct device *self, void *aux)
 
        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 +177,30 @@ agtimer_get_timecount(struct timecounter *tc)
        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
-        */
-
-       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;
+       struct agtimer_softc *sc = cookie;
+       uint32_t cycles;
+
+       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 +214,12 @@ agtimer_set_clockrate(int32_t new_frequency)
                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 +228,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 +246,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 +289,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