> Date: Fri, 09 Dec 2022 18:46:13 +0100 > From: Mark Kettenis <mark.kette...@xs4all.nl> > > > 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.
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); > > } > > > > > >