> Date: Tue, 24 Jan 2023 20:57:48 +0100
> From: Patrick Wildt <patr...@blueri.se>
> 
> Am Mon, Jan 23, 2023 at 04:34:27PM -0600 schrieb Scott Cheloha:
> > 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?
> 
> Should we just get rid of it?  It's only used on OMAP3, which was
> already outdated when I started my ARMv7 endeavour a decade ago.
> I never had that machine, drahn@ might have one in the attic.
> 
> The relevant platforms were the Pandaboard (OMAP4) and the BeagleBone
> Black (AM335x).  But the OMAP3, did this thing ever work?

Might as well commit this such that we have it in the attic just in
case someone wants to revive OMAP3?

> > 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