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?


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