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, ok.
Though CPU_BUSY_CYCLE() should really be changed to use cpu_sleep() on
arm which ends up doing a wfi instruction via armv7_cpu_sleep.
>
>
> 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
>