Subject: Re: clock drift
To: Jason Meinzer <jason.meinzer@reed.edu>
From: Marius Strobl <marius@alchemy.franken.de>
List: port-cobalt
Date: 08/11/2003 03:47:09
--MGYHOYXEY6WxJCY8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Sun, Aug 03, 2003 at 09:11:14AM -0700, Jason Meinzer wrote:
> I am using a RaQ 1 and my clock drifts almost 30 seconds too fast every 
> five minutes.  Is this happening for anyone else?  All I can find is an 

This is a long standig bug. The NetBSD kernel doesn't initialise the
timers/counters of the Galileo system controller but then reads the
current value of the write-only timer0 register in microtime(). On
Qube2/Raq2 the firmware already initialises timer0 to 100Hz and its
interrupt is caught by the kernel in cpu_intr(). I can't remember if
the Qube1/ Raq1 firmware doesn't initialise the timer at all or to
another value, at least initialising the timer by the kernel solves
the issue. I'm not sure why the bug in microtime() doesn't seem to be
noticeable (on Qube2/Raq2).

> old posting about a patch, but that is marked 2001 and seems to apply 
> to 1.5.1.

I'm not sure what patch you are refering to but I did one in 2001,
it's attached. It was for Soeren Joervang and the lengthy comments
should explain to him how to set up the timers. One should change it
to respect "options HZ" in the kernel config file, one could/should
also use another timer (there are four of them in the Galileo chip)
for a stat clock. The patch was also tested by Eric Berls to have "no
ill effects on Raq2".
The relevant files haven't changed much since then, so the patch
should still solve your problem.


--MGYHOYXEY6WxJCY8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="cobalt_clock.diff"

Index: cobalt/clock.c
===================================================================
RCS file: /usr/data/bsd/cvs/nbsd/src/sys/arch/cobalt/cobalt/clock.c,v
retrieving revision 1.6
diff -u -u -r1.6 clock.c
--- cobalt/clock.c	15 Jul 2003 01:29:22 -0000	1.6
+++ cobalt/clock.c	11 Aug 2003 01:40:14 -0000
@@ -46,7 +46,49 @@
 void
 cpu_initclocks()
 {
-	inittodr(0);
+	stathz = 0;	/* No statistics clock, yet. */
+	hz = 100;	/* We will set up a 100 ticks per second interrupt. */
+
+	/*
+	 * Disable timer0 of the Galileo chip, it should be in disabled state
+	 * but this wont't hurt...
+	 *
+	 * According to the Galileo datasheet the procedure is:
+	 * disable timer -> load timer value -> enable timer
+	 */
+	*((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000864)) =
+		(*((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000864)) &
+		~0x1) | 0x1;
+
+	/*
+	 * Load the timer0 value, the timers work at the 50MHz TClk frequency
+	 * of the Galileo chip, so if we put a value of 500000 into the register
+	 * we will get 100 ticks per second.
+	 *
+	 * XXX The counter/timer value cannot be read directly, this register
+	 *     will _always_ _read_ 0xffffff, regardless of the current value!
+	 */
+	*((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000850)) = 500000;
+
+	/*
+	 * Unmask the timer0 interrupt, it will show up in the Galileo
+	 * interrupt cause register at offset 0xc18 as bit 8.
+	 * The interrupt is hardcoded caught in cpu_intr() so we do not need
+	 * to establish an ISR here.
+	 */
+	*((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000c1c)) =
+		(*((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000c1c)) &
+		~0x100) | 0x100;
+		
+	/*
+	 * Switch timer0 to timer mode (defaults to counter mode, the difference
+	 * is that it will reload itself to the value set at offset 0x850 and
+	 * continue to count every time it is exhausted) and enable it.
+	 * The timer will issue an interrupt on terminal count (= one tick).
+	 */
+	*((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000864)) =
+		(*((volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000864)) &
+		~0x3) | 0x3;
 
 	return;
 }
Index: cobalt/machdep.c
===================================================================
RCS file: /usr/data/bsd/cvs/nbsd/src/sys/arch/cobalt/cobalt/machdep.c,v
retrieving revision 1.44
diff -u -u -r1.44 machdep.c
--- cobalt/machdep.c	15 Jul 2003 01:29:22 -0000	1.44
+++ cobalt/machdep.c	11 Aug 2003 00:17:42 -0000
@@ -386,26 +386,20 @@
 {
 	int s = splclock();
 	static struct timeval lasttime;
-	u_int32_t counter0;
 
 	*tvp = time;
 
-	counter0 = *(volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000850);
-
-	/*
-	 * XXX
-	 */
-
-	counter0 /= 50;
-	counter0 %= 10000;
-
-	if (counter0 > 9999) {
-		counter0 = 9999;
+	if (tvp->tv_usec >= 1000000) {
+		tvp->tv_usec -= 1000000;
+		 tvp->tv_sec++;
 	}
 
-	tvp->tv_usec -= tvp->tv_usec % 10000;
-	tvp->tv_usec += 10000 - counter0;
-
+	if (tvp->tv_sec == lasttime.tv_sec &&
+	    tvp->tv_usec <= lasttime.tv_usec &&
+	    (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
+		tvp->tv_sec++;
+		tvp->tv_usec -= 1000000;
+	}
 	lasttime = *tvp;
 	splx(s);
 }

--MGYHOYXEY6WxJCY8--