> Date: Fri, 09 Dec 2022 18:46:13 +0100
> From: Mark Kettenis <[email protected]>
>
> > Date: Fri, 9 Dec 2022 11:28:43 -0600
> > From: Scott Cheloha <[email protected]>
> >
> > sxitimer(4) is the fourth and final armv7 clock interrupt driver that
> > needs to switch to clockintr.
> >
> > - Remove everything related to STATTIMER. We can multiplex TICKTIMER
> > to handle all clock interrupt events.
> > - Remove sxitimer-specific clock interrupt scheduling bits and randomized
> > statclock bits.
> > - Wire up sxitimer_intrclock.
> >
> > This is not compile-tested. When we get it to compile, it ought to
> > survive a release build if that's practical for machines sporting
> > sxitimer(4).
> >
> > What sort of machine has one of these?
>
> I have a board with an allwinner A10 here that has it. I'll see if I
> can dig it out over the weekend.
I've hit a (2nd) snag that means it will take some more time for me to
bring the machine to -current.
So no test of this diff yet.
> > 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 9 Dec 2022 17:27:13 -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 9 Dec 2022 17:27:13 -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/armv7/sunxi/sxitimer.c
> > ===================================================================
> > RCS file: /cvs/src/sys/arch/armv7/sunxi/sxitimer.c,v
> > retrieving revision 1.18
> > diff -u -p -r1.18 sxitimer.c
> > --- sys/arch/armv7/sunxi/sxitimer.c 24 Oct 2021 17:52:28 -0000 1.18
> > +++ sys/arch/armv7/sunxi/sxitimer.c 9 Dec 2022 17:27:14 -0000
> > @@ -20,7 +20,9 @@
> > #include <sys/param.h>
> > #include <sys/systm.h>
> > #include <sys/kernel.h>
> > +#include <sys/clockintr.h>
> > #include <sys/device.h>
> > +#include <sys/stdint.h>
> > #include <sys/timetc.h>
> >
> > #include <machine/bus.h>
> > @@ -94,6 +96,17 @@ static struct timecounter sxitimer_timec
> > .tc_user = 0,
> > };
> >
> > +uint64_t sxitimer_nsec_cycle_ratio;
> > +uint64_t sxitimer_nsec_max;
> > +
> > +void sxitimer_rearm(void *, uint64_t);
> > +void sxitimer_trigger(void *);
> > +
> > +const struct intrclock sxitimer_intrclock = {
> > + .ic_rearm = sxitimer_rearm,
> > + .ic_trigger = sxitimer_trigger
> > +};
> > +
> > bus_space_tag_t sxitimer_iot;
> > bus_space_handle_t sxitimer_ioh;
> >
> > @@ -111,11 +124,6 @@ uint32_t sxitimer_irq[] = {
> > 0
> > };
> >
> > -uint32_t sxitimer_stat_tpi, sxitimer_tick_tpi;
> > -uint32_t sxitimer_statvar, sxitimer_statmin;
> > -uint32_t sxitimer_tick_nextevt, sxitimer_stat_nextevt;
> > -uint32_t sxitimer_ticks_err_cnt, sxitimer_ticks_err_sum;
> > -
> > struct sxitimer_softc {
> > struct device sc_dev;
> > };
> > @@ -147,7 +155,6 @@ void
> > sxitimer_attach(struct device *parent, struct device *self, void *aux)
> > {
> > struct fdt_attach_args *faa = aux;
> > - uint32_t freq, ival, now;
> >
> > KASSERT(faa->fa_nreg > 0);
> >
> > @@ -163,61 +170,32 @@ sxitimer_attach(struct device *parent, s
> > & CNT64_CLR_EN)
> > continue;
> >
> > - /* timers are down-counters, from interval to 0 */
> > - now = 0xffffffff; /* known big value */
> > - freq = sxitimer_freq[TICKTIMER];
> > -
> > /* stop timer, and set clk src */
> > bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > TIMER_CTRL(TICKTIMER), TIMER_OSC24M);
> >
> > - ival = sxitimer_tick_tpi = freq / hz;
> > - sxitimer_tick_nextevt = now - ival;
> > -
> > - sxitimer_ticks_err_cnt = freq % hz;
> > - sxitimer_ticks_err_sum = 0;
> > -
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_INTV(TICKTIMER), ival);
> > -
> > - /* timers are down-counters, from interval to 0 */
> > - now = 0xffffffff; /* known big value */
> > - freq = sxitimer_freq[STATTIMER];
> > -
> > - /* stop timer, and set clk src */
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(STATTIMER), TIMER_OSC24M);
> > + sxitimer_nsec_cycle_ratio =
> > + sxitimer_freq[TICKTIMER] * (1ULL << 32) / 1000000000;
> > + sxitimer_nsec_max = UINT64_MAX / sxitimer_nsec_cycle_ratio;
> >
> > /* 100/1000 or 128/1024 ? */
> > stathz = 128;
> > profhz = 1024;
> > - sxitimer_setstatclockrate(stathz);
> > -
> > - ival = sxitimer_stat_tpi = freq / stathz;
> > - sxitimer_stat_nextevt = now - ival;
> > -
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_INTV(STATTIMER), ival);
> > -
> > - /* timers are down-counters, from interval to 0 */
> > - now = 0xffffffff; /* known big value */
> > - freq = sxitimer_freq[CNTRTIMER];
> > + clockintr_init(CL_RNDSTAT);
> >
> > /* stop timer, and set clk src */
> > bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > TIMER_CTRL(CNTRTIMER), TIMER_OSC24M);
> > + bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_INTV(CNTRTIMER), UINT32_MAX);
> >
> > - ival = now;
> > -
> > - sxitimer_timecounter.tc_frequency = freq;
> > + sxitimer_timecounter.tc_frequency = sxitimer_freq[CNTRTIMER];
> > tc_init(&sxitimer_timecounter);
> > +
> > arm_clock_register(sxitimer_cpu_initclocks, sxitimer_delay,
> > sxitimer_setstatclockrate, NULL);
> >
> > - printf(": %d kHz", freq / 1000);
> > -
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_INTV(CNTRTIMER), ival);
> > + printf(": %d kHz", sxitimer_freq[CNTRTIMER] / 1000);
> >
> > printf("\n");
> > }
> > @@ -233,20 +211,18 @@ sxitimer_cpu_initclocks(void)
> > {
> > uint32_t isr, ier, ctrl;
> >
> > - /* establish interrupts */
> > + /* establish interrupt */
> > arm_intr_establish(sxitimer_irq[TICKTIMER], IPL_CLOCK,
> > sxitimer_tickintr, NULL, "tick");
> > - arm_intr_establish(sxitimer_irq[STATTIMER], IPL_STATCLOCK,
> > - sxitimer_statintr, NULL, "stattick");
> >
> > /* clear timer interrupt pending bits */
> > isr = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR);
> > - isr |= TIMER_IRQ(STATTIMER) | TIMER_IRQ(TICKTIMER);
> > + isr |= TIMER_IRQ(TICKTIMER);
> > bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR, isr);
> >
> > - /* enable timer IRQs */
> > + /* enable timer IRQ */
> > ier = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_IER);
> > - ier |= TIMER_IRQ(STATTIMER) | TIMER_IRQ(TICKTIMER);
> > + ier |= TIMER_IRQ(TICKTIMER);
> > bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_IER, ier);
> >
> > /* enable timers */
> > @@ -256,153 +232,21 @@ sxitimer_cpu_initclocks(void)
> > TIMER_CTRL(CNTRTIMER),
> > ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_CONTINOUS);
> >
> > - ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(STATTIMER));
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(STATTIMER),
> > - ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
> > -
> > - ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(TICKTIMER));
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(TICKTIMER),
> > - ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
> > + /* start clock interrupt cycle */
> > + clockintr_cpu_init(&sxitimer_intrclock);
> > + clockintr_trigger();
> > }
> >
> > -/*
> > - * 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.
> > - *
> > - * To work around this two timers are used, one is used as a reference
> > - * clock without reload, however we just disable the interrupt it
> > - * could 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.
> > - */
> > -/* XXX update above comment */
> > int
> > sxitimer_tickintr(void *frame)
> > {
> > - uint32_t now, nextevent;
> > - uint32_t val;
> > - int rc = 0;
> > -
> > splassert(IPL_CLOCK);
> >
> > /* clear timer pending interrupt bit */
> > bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > TIMER_ISR, TIMER_IRQ(TICKTIMER));
> >
> > - now = sxitimer_readcnt32();
> > -
> > - while ((int32_t)(now - sxitimer_tick_nextevt) < 0) {
> > - sxitimer_tick_nextevt -= sxitimer_tick_tpi;
> > - sxitimer_ticks_err_sum += sxitimer_ticks_err_cnt;
> > -
> > - while (sxitimer_ticks_err_sum > hz) {
> > - sxitimer_tick_nextevt += 1;
> > - sxitimer_ticks_err_sum -= hz;
> > - }
> > -
> > - rc = 1;
> > - hardclock(frame);
> > - }
> > - nextevent = now - sxitimer_tick_nextevt;
> > - if (nextevent < 10 /* XXX */)
> > - nextevent = 10;
> > -
> > - if (nextevent > sxitimer_tick_tpi) {
> > - /*
> > - * 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.
> > - */
> > - nextevent = sxitimer_tick_tpi;
> > - sxitimer_tick_nextevt = now;
> > - }
> > -
> > - val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(TICKTIMER));
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(TICKTIMER), val & ~TIMER_ENABLE);
> > -
> > - sxitimer_sync();
> > -
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_INTV(TICKTIMER), nextevent);
> > -
> > - val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(TICKTIMER));
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(TICKTIMER),
> > - val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
> > -
> > - return rc;
> > -}
> > -
> > -int
> > -sxitimer_statintr(void *frame)
> > -{
> > - uint32_t now, nextevent, r;
> > - uint32_t val;
> > - int rc = 0;
> > -
> > - splassert(IPL_STATCLOCK);
> > -
> > - /* clear timer pending interrupt bit */
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_ISR, TIMER_IRQ(STATTIMER));
> > -
> > - now = sxitimer_readcnt32();
> > - while ((int32_t)(now - sxitimer_stat_nextevt) < 0) {
> > - do {
> > - r = random() & (sxitimer_statvar -1);
> > - } while (r == 0); /* random == 0 not allowed */
> > - sxitimer_stat_nextevt -= sxitimer_statmin + r;
> > - rc = 1;
> > - statclock(frame);
> > - }
> > -
> > - nextevent = now - sxitimer_stat_nextevt;
> > -
> > - if (nextevent < 10 /* XXX */)
> > - nextevent = 10;
> > -
> > - if (nextevent > sxitimer_stat_tpi) {
> > - /*
> > - * 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.
> > - */
> > - nextevent = sxitimer_stat_tpi;
> > - sxitimer_stat_nextevt = now;
> > - }
> > -
> > - val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(STATTIMER));
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(STATTIMER), val & ~TIMER_ENABLE);
> > -
> > - sxitimer_sync();
> > -
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_INTV(STATTIMER), nextevent);
> > -
> > - val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(STATTIMER));
> > - bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > - TIMER_CTRL(STATTIMER),
> > - val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
> > -
> > - return rc;
> > + return clockintr_dispatch(frame);
> > }
> >
> > uint64_t
> > @@ -457,29 +301,62 @@ sxitimer_delay(u_int usecs)
> > void
> > sxitimer_setstatclockrate(int newhz)
> > {
> > - int minint, statint, s;
> > -
> > - s = splstatclock();
> > -
> > - statint = sxitimer_freq[STATTIMER] / newhz;
> > - /* calculate largest 2^n which is smaller than just over half statint */
> > - sxitimer_statvar = 0x40000000; /* really big power of two */
> > - minint = statint / 2 + 100;
> > - while (sxitimer_statvar > minint)
> > - sxitimer_statvar >>= 1;
> > -
> > - sxitimer_statmin = statint - (sxitimer_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);
> > }
> >
> > u_int
> > sxitimer_get_timecount(struct timecounter *tc)
> > {
> > return (u_int)UINT_MAX - sxitimer_readcnt32();
> > +}
> > +
> > +void
> > +sxitimer_rearm(void *unused, uint64_t nsecs)
> > +{
> > + uint32_t ctrl, cycles;
> > +
> > + if (nsecs > sxitimer_nsec_max)
> > + nsecs = sxitimer_nsec_max;
> > + cycles = (nsecs * sxitimer_nsec_cycle_ratio) >> 32;
> > + if (cycles < 10)
> > + cycles = 10; /* XXX Why do we need to round up to 10? */
> > +
> > + ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_CTRL(TICKTIMER));
> > + bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_CTRL(TICKTIMER), ctrl & ~TIMER_ENABLE);
> > +
> > + sxitimer_sync();
> > +
> > + bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_INTV(TICKTIMER), cycles);
> > +
> > + ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_CTRL(TICKTIMER));
> > + bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_CTRL(TICKTIMER),
> > + ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
> > +}
> > +
> > +void
> > +sxitimer_trigger(void *unused)
> > +{
> > + uint32_t ctrl;
> > +
> > + ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_CTRL(TICKTIMER));
> > + bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_CTRL(TICKTIMER), ctrl & ~TIMER_ENABLE);
> > +
> > + sxitimer_sync();
> > +
> > + /* XXX Why do we need to round up to 10? */
> > + bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_INTV(TICKTIMER), 10);
> > +
> > + ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_CTRL(TICKTIMER));
> > + bus_space_write_4(sxitimer_iot, sxitimer_ioh,
> > + TIMER_CTRL(TICKTIMER),
> > + ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
> > }
> >
> >
>
>