Whoops, missed one.  This is the fifth and (I think) last armv7 clock
interrupt driver that needs to switch to clockintr.  gptimer(4) is
nearly identical to dmtimer(4).

Notable changes:

- Switch stathz from 128 to hz.
- Switch profhz from 1024 to (stathz * 10).

Everything else in the patch is just normal clockintr switching stuff
or duplicated from the dmtimer(4) patch.

jca@ has compile-tested this.

I would appreciate a test to confirm that the GENERIC boots.  I don't
think we need to do a full release build.

... if nobody knows where to find a board with gptimer(4), I am
looking for permission to just commit this as-is.  I cannot find any
entries in the dmesg mails of any machines with gptimer(4).  kettenis@
was uncertain whether we actually support any of the machines that have
this clock.

Preferences?  ok?

Index: gptimer.c
===================================================================
RCS file: /cvs/src/sys/arch/armv7/omap/gptimer.c,v
retrieving revision 1.17
diff -u -p -r1.17 gptimer.c
--- gptimer.c   22 Jan 2023 18:36:38 -0000      1.17
+++ gptimer.c   22 Jan 2023 23:52:32 -0000
@@ -23,9 +23,11 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/clockintr.h>
 #include <sys/kernel.h>
 #include <sys/evcount.h>
 #include <sys/device.h>
+#include <sys/stdint.h>
 #include <sys/timetc.h>
 #include <machine/bus.h>
 #include <armv7/armv7/armv7var.h>
@@ -93,14 +95,12 @@
 
 #define TIMER_FREQUENCY                        32768   /* 32kHz is used, 
selectable */
 
-static struct evcount clk_count;
-static struct evcount stat_count;
-
 void gptimer_attach(struct device *parent, struct device *self, void *args);
 int gptimer_intr(void *frame);
 void gptimer_wait(int reg);
 void gptimer_cpu_initclocks(void);
 void gptimer_delay(u_int);
+void gptimer_reset_tisr(void);
 void gptimer_setstatclockrate(int newhz);
 
 bus_space_tag_t gptimer_iot;
@@ -120,13 +120,16 @@ static struct timecounter gptimer_timeco
        .tc_user = 0,
 };
 
-volatile u_int32_t nexttickevent;
-volatile u_int32_t nextstatevent;
-u_int32_t      ticks_per_second;
-u_int32_t      ticks_per_intr;
-u_int32_t      ticks_err_cnt;
-u_int32_t      ticks_err_sum;
-u_int32_t      statvar, statmin;
+uint64_t gptimer_nsec_cycle_ratio;
+uint64_t gptimer_nsec_max;
+
+void gptimer_rearm(void *, uint64_t);
+void gptimer_trigger(void *);
+
+const struct intrclock gptimer_intrclock = {
+       .ic_rearm = gptimer_rearm,
+       .ic_trigger = gptimer_trigger
+};
 
 const struct cfattach  gptimer_ca = {
        sizeof (struct device), NULL, gptimer_attach
@@ -177,98 +180,10 @@ gptimer_attach(struct device *parent, st
            gptimer_setstatclockrate, NULL);
 }
 
-/*
- * See comment in arm/xscale/i80321_clock.c
- *
- * counter is count up, but with autoreload timers it is not possible
- * to detect how many  interrupts passed while interrupts were blocked.
- * also it is not possible to atomically add to the register
- * get get it to precisely fire at a non-fixed interval.
- *
- * To work around this two timers are used, GPT1 is used as a reference
- * clock without reload , however we just ignore the interrupt it
- * would (may?) generate.
- *
- * Internally this keeps track of when the next timer should fire
- * and based on that time and the current value of the reference
- * clock a number is written into the timer count register to schedule
- * the next event.
- */
-
 int
 gptimer_intr(void *frame)
 {
-       u_int32_t now, r;
-       u_int32_t nextevent, duration;
-
-       /* clear interrupt */
-       now = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
-
-       while ((int32_t) (nexttickevent - now) < 0) {
-               nexttickevent += ticks_per_intr;
-               ticks_err_sum += ticks_err_cnt;
-#if 0
-               if (ticks_err_sum  > hz) {
-                       u_int32_t match_error;
-                       match_error = ticks_err_sum / hz
-                       ticks_err_sum -= (match_error * hz);
-               }
-#else
-               /* looping a few times is faster than divide */
-               while (ticks_err_sum  > hz) {
-                       nexttickevent += 1;
-                       ticks_err_sum -= hz;
-               }
-#endif
-               clk_count.ec_count++;
-               hardclock(frame);
-       }
-       while ((int32_t) (nextstatevent - now) < 0) {
-               do {
-                       r = random() & (statvar -1);
-               } while (r == 0); /* random == 0 not allowed */
-               nextstatevent += statmin + r;
-               /* XXX - correct nextstatevent? */
-               stat_count.ec_count++;
-               statclock(frame);
-       }
-       if ((nexttickevent - now) < (nextstatevent - now))
-                nextevent = nexttickevent;
-        else
-                nextevent = nextstatevent;
-
-/* XXX */
-       duration = nextevent -
-           bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
-#if 0
-       printf("duration 0x%x %x %x\n", nextevent -
-           bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR),
-           bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TCRR),
-           bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR));
-#endif
-
-
-        if (duration <= 0)
-                duration = 1; /* trigger immediately. */
-
-        if (duration > ticks_per_intr) {
-                /*
-                 * If interrupts are blocked too long, like during
-                 * the root prompt or ddb, the timer can roll over,
-                 * this will allow the system to continue to run
-                 * even if time is lost.
-                 */
-                duration = ticks_per_intr;
-                nexttickevent = now;
-                nextstatevent = now;
-        }
-
-       gptimer_wait(GP_TWPS_ALL);
-       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR,
-               bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR));
-       gptimer_wait(GP_TWPS_ALL);
-        bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -duration);
- 
+       clockintr_dispatch(frame);
        return 1;
 }
 
@@ -281,44 +196,31 @@ gptimer_intr(void *frame)
 void
 gptimer_cpu_initclocks(void)
 {
-       stathz = 128;
-       profhz = 1024;
+       stathz = hz;
+       profhz = stathz * 10;
+       clockintr_init(CL_RNDSTAT);
 
-       ticks_per_second = TIMER_FREQUENCY;
-
-       setstatclockrate(stathz);
-
-       ticks_per_intr = ticks_per_second / hz;
-       ticks_err_cnt = ticks_per_second % hz;
-       ticks_err_sum = 0;
+       gptimer_nsec_cycle_ratio = TIMER_FREQUENCY * (1ULL << 32) / 1000000000;
+       gptimer_nsec_max = UINT64_MAX / gptimer_nsec_cycle_ratio;
 
        prcm_setclock(1, PRCM_CLK_SPEED_32);
        prcm_setclock(2, PRCM_CLK_SPEED_32);
+
        /* establish interrupts */
        arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr,
            NULL, "tick");
 
        /* setup timer 0 (hardware timer 2) */
        /* reset? - XXX */
-
-        bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TLDR, 0);
-
-       nexttickevent = nextstatevent = bus_space_read_4(gptimer_iot,
-           gptimer_ioh1, GP_TCRR) + ticks_per_intr;
-
        gptimer_wait(GP_TWPS_ALL);
        bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN);
        gptimer_wait(GP_TWPS_ALL);
        bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN);
        gptimer_wait(GP_TWPS_ALL);
-       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR,
-           GP_TCLR_AR | GP_TCLR_ST);
-       gptimer_wait(GP_TWPS_ALL);
-       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR,
-               bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR));
-       gptimer_wait(GP_TWPS_ALL);
-       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -ticks_per_intr);
-       gptimer_wait(GP_TWPS_ALL);
+
+       /* start the clock interrupt cycle */
+       clockintr_cpu_init(&gptimer_intrclock);
+       clockintr_trigger();
 }
 
 void
@@ -328,6 +230,61 @@ gptimer_wait(int reg)
                ;
 }
 
+/*
+ * Clear all interrupt status bits.
+ */
+void
+gptimer_reset_tisr(void)
+{
+       u_int32_t tisr;
+
+       tisr = bus_space_read_4(gptimer_iot, gptimerioh0, GP_TISR);
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, tisr);
+}
+
+void
+gptimer_rearm(void *unused, uint64_t nsecs)
+{
+       uint32_t cycles;
+       u_long s;
+
+       if (nsecs > gptimer_nsec_max)
+               nsecs = gptimer_nsec_max;
+       cycles = (nsecs * gptimer_nsec_cycle_ratio) >> 32;
+
+       s = intr_disable();
+       gptimer_reset_tisr();
+        bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR,
+           UINT32_MAX - cycles);
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, GP_TCLR_ST);
+       gptimer_wait(GP_TWPS_ALL);
+       intr_restore(s);
+}
+
+void
+gptimer_trigger(void *unused)
+{
+       u_long s;
+
+       s = intr_disable();
+
+       /* stop timer. */
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0);
+       gptimer_wait(GP_TWPS_ALL);
+
+       /* clear interrupt status bits. */
+       gptimer_reset_tisr();
+
+       /* set shortest possible timeout. */
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, UINT32_MAX);
+
+       /* start timer, wait for writes to post. */
+       bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, GP_TCLR_ST);
+       gptimer_wait(GP_TWPS_ALL);
+
+       intr_restore(s);
+}
+
 void
 gptimer_delay(u_int usecs)
 {
@@ -370,26 +327,7 @@ gptimer_delay(u_int usecs)
 void
 gptimer_setstatclockrate(int newhz)
 {
-       int minint, statint;
-       int s;
-       
-       s = splclock();
-
-       statint = ticks_per_second / newhz;
-       /* calculate largest 2^n which is smaller that just over half statint */
-       statvar = 0x40000000; /* really big power of two */
-       minint = statint / 2 + 100;
-       while (statvar > minint)
-               statvar >>= 1;
-
-       statmin = statint - (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);
 }
 
 

Reply via email to