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
> 

Reply via email to