> Date: Fri, 9 Dec 2022 11:28:43 -0600 > From: Scott Cheloha <scottchel...@gmail.com> > > 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. > 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); > } > >