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