On Mon, Jul 18, 2016 at 02:41:10PM +0200, Mark Kettenis wrote:
> Currently on my Olimex A10s-Olinuxino Micro, the kernel hangs after
> printing:
>
> simplebus0 at mainbus0: "soc"
> sxiuart0 at simplebus0
> sxie0 at simplebus0, address 02:d3:08:c1:74:6f
> sxiuart1 at simplebus0: console
> sxiuart2 at simplebus0
>
> It seems I get only two clock interrupts before it hangs. Looking at
> the Linux code, it seems to always explicitly stop the timer before
> reloading. And after stopping the timer, it explicitly syncs by
> waiting for 3 clock ticks. The diff below makes the tickclock and
> statclock interrupt handlers do the same, which makes the hang
> disappear.
>
> The diff also fixes an issue with reloading the timers, where it would
> lose the clock source setting.
>
> ok?
>
Yes, originally it was the gpio led toggling that enabled the timer to
work at all. This was the sun4i regression i've been trying to hint at.
personally i had temporarily fixed this with something like:
#define TIMER_MIN_CYCLES 0x20 /* 'feel good' value */
int
sxitimer_intr(void *frame)
{
uint64_t now;
uint32_t next;
now = sxitimer_readcnt64();
while (tick_nextevt < now) {
tick_nextevt += tick_tpi;
#if (SXITIMER_FREQ != 24000000)
ticks_err_sum += ticks_err_cnt;
while (ticks_err_sum > hz) {
tick_nextevt += 1;
ticks_err_sum -= hz;
}
#endif
hardclock(frame);
}
now = sxitimer_readcnt64();
next = tick_nextevt - now;
if (next < TIMER_MIN_CYCLES)
next = TIMER_MIN_CYCLES;
else if (next > tick_tpi) {
next = tick_tpi;
tick_nextevt = now + TIMER_MIN_CYCLES;
}
/* clear pending */
bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR, TMR_IRQ(0));
/* load */
bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_INTV(0), next);
/* start */
bus_space_write_4(sxitimer_iot, sxitimer_ioh,
TIMER_CTRL(0), TMR_START | TMR_RELOAD);
return 1;
}
avoiding the busywait, which might not be equally cheap on all boards/dtbs
based on timer clk src, 3ticks@24hmhz vs 3ticks@32khz. which obv. won't be
an issue for you atm. as is, so busywait or not, please go ahead and fix it.
thanks:)
-Artturi
>
> Index: sxitimer.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/armv7/sunxi/sxitimer.c,v
> retrieving revision 1.5
> diff -u -p -r1.5 sxitimer.c
> --- sxitimer.c 1 Feb 2016 23:31:34 -0000 1.5
> +++ sxitimer.c 18 Jul 2016 12:33:39 -0000
> @@ -76,6 +76,8 @@
> #define STATTIMER 1
> #define CNTRTIMER 2
>
> +#define TIMER_SYNC 3
> +
> void sxitimer_attach(struct device *, struct device *, void *);
> int sxitimer_tickintr(void *);
> int sxitimer_statintr(void *);
> @@ -83,6 +85,7 @@ void sxitimer_cpu_initclocks(void);
> void sxitimer_setstatclockrate(int);
> uint64_t sxitimer_readcnt64(void);
> uint32_t sxitimer_readcnt32(void);
> +void sxitimer_sync(void);
> void sxitimer_delay(u_int);
>
> u_int sxitimer_get_timecount(struct timecounter *);
> @@ -267,6 +270,7 @@ int
> sxitimer_tickintr(void *frame)
> {
> uint32_t now, nextevent;
> + uint32_t val;
> int rc = 0;
>
> splassert(IPL_CLOCK);
> @@ -304,12 +308,21 @@ sxitimer_tickintr(void *frame)
> 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),
> - TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
> + val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
>
> return rc;
> }
> @@ -318,6 +331,7 @@ int
> sxitimer_statintr(void *frame)
> {
> uint32_t now, nextevent, r;
> + uint32_t val;
> int rc = 0;
>
> splassert(IPL_STATCLOCK);
> @@ -352,12 +366,21 @@ sxitimer_statintr(void *frame)
> 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),
> - TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
> + val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
>
> return rc;
> }
> @@ -388,6 +411,15 @@ sxitimer_readcnt32(void)
> {
> return bus_space_read_4(sxitimer_iot, sxitimer_ioh,
> TIMER_CURR(CNTRTIMER));
> +}
> +
> +void
> +sxitimer_sync(void)
> +{
> + uint32_t now = sxitimer_readcnt32();
> +
> + while ((now - sxitimer_readcnt32()) < TIMER_SYNC)
> + CPU_BUSY_CYCLE();
> }
>
> void
>