Subject: Timecounter patch for testing
To: None <port-arm@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: port-arm
Date: 01/13/2008 00:47:13
--zYM0uCDKw75PZbzx
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,
please test the attached patch on your or evbarm boards.
It is compile-tested only and I am not sure about the hardware in all
cases. A good test is running "date; sleep 10; date" and "time sleep 1",
which should show the real time. Another test is
src/regress/sys/kern/time. That should be usable on a netbsd-4 world as
well.

I plan to commit this next Sunday.

Joerg

--zYM0uCDKw75PZbzx
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="evbarm-tc.diff"

Index: arm/ep93xx/epclk.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/ep93xx/epclk.c,v
retrieving revision 1.10
diff -u -p -r1.10 epclk.c
--- arm/ep93xx/epclk.c	6 Jan 2007 16:18:18 -0000	1.10
+++ arm/ep93xx/epclk.c	7 Jan 2008 17:45:29 -0000
@@ -54,6 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: epclk.c,v 1.
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 #include <sys/device.h>
 
 #include <machine/bus.h>
@@ -69,8 +70,11 @@ __KERNEL_RCSID(0, "$NetBSD: epclk.c,v 1.
 
 #include "opt_hz.h"
 
+#define	TIMER_FREQ	983040
+
 static int	epclk_match(struct device *, struct cfdata *, void *);
 static void	epclk_attach(struct device *, struct device *, void *);
+static u_int	epclk_get_timecount(struct timecounter *);
 
 void		rtcinit(void);
 
@@ -88,35 +92,18 @@ struct epclk_softc {
 	int			sc_intr;
 };
 
-static struct epclk_softc *epclk_sc = NULL;
-static u_int32_t tmark;
-
-
-/* This is a quick ARM way to multiply by 983040/1000000 */
-#define US_TO_TIMER4VAL(x) { \
-	u_int32_t hi, lo, scalar = 4222124650UL; \
-	__asm volatile ( \
-		"umull %0, %1, %2, %3;" \
-		: "=&r"(lo), "=&r"(hi) \
-		: "r"((x)), "r"(scalar) \
-	); \
-	(x) = hi; \
-}
-
-/* This is a quick ARM way to multiply by 1000000/983040 */
-#define TIMER4VAL_TO_US(x) { \
-	u_int32_t hi, lo, scalar = 2184533333UL; \
-	__asm volatile ( \
-		"umull %0, %1, %2, %3;" \
-		"mov %1, %1, lsl #1;" \
-		"mov %0, %0, lsr #31;" \
-		"orr %1, %1, %0;" \
-		: "=&r"(lo), "=&r"(hi) \
-		: "r"((x)), "r"(scalar) \
-	); \
-	(x) = hi; \
-}
+static struct timecounter epclk_timecounter = {
+	epclk_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	~0u,			/* counter_mask */
+	TIMER_FREQ,		/* frequency */
+	"epclk",		/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
 
+static struct epclk_softc *epclk_sc = NULL;
 
 CFATTACH_DECL(epclk, sizeof(struct epclk_softc),
     epclk_match, epclk_attach, NULL, NULL);
@@ -136,6 +123,7 @@ epclk_attach(struct device *parent, stru
 {
 	struct epclk_softc		*sc;
 	struct epsoc_attach_args	*sa;
+	bool first_run;
 
 	printf("\n");
 
@@ -145,8 +133,10 @@ epclk_attach(struct device *parent, stru
 	sc->sc_baseaddr = sa->sa_addr;
 	sc->sc_intr = sa->sa_intr;
 
-	if (epclk_sc == NULL)
+	if (epclk_sc == NULL) {
+		first_run = true;
 		epclk_sc = sc;
+	}
 
 	if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 
 		0, &sc->sc_ioh))
@@ -160,6 +150,9 @@ epclk_attach(struct device *parent, stru
 	/* clear and start the debug timer (Timer4) */
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer4Enable, 0);
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer4Enable, 0x100);
+
+	if (first_run)
+		tc_init(&epclk_timecounter);
 }
 
 /*
@@ -172,7 +165,6 @@ epclk_intr(void *arg)
 {
 	struct epclk_softc*	sc;
 
-	tmark = TIMER4VAL();
 	sc = epclk_sc;
 
 #if defined(HZ) && (HZ == 64)
@@ -239,88 +231,54 @@ cpu_initclocks(void)
 }
 
 /*
- * microtime:
+ * delay:
  *
- *	Fill in the specified timeval struct with the current time
- *	accurate to the microsecond.
+ *	Delay for at least N microseconds.
  */
 void
-microtime(register struct timeval *tvp)
+delay(unsigned int n)
 {
-	u_int			oldirqstate;
-	u_int			tmarknow, delta;
-	static struct timeval	lasttv;
+	unsigned int cur_tick, initial_tick;
+	int remaining;
 
 #ifdef DEBUG
 	if (epclk_sc == NULL) {
-		printf("microtime: called before initialize epclk\n");
-		tvp->tv_sec = 0;
-		tvp->tv_usec = 0;
+		printf("delay: called before start epclk\n");
 		return;
 	}
 #endif
 
-	oldirqstate = disable_interrupts(I32_bit);
-	tmarknow = TIMER4VAL();
-
-        /* Fill in the timeval struct. */
-	*tvp = time;
-	if (__predict_false(tmarknow < tmark)) { /* overflow */
-		delta = tmarknow + (UINT_MAX - tmark);
+	/*
+	 * Read the counter first, so that the rest of the setup overhead is
+	 * counted.
+	 */
+	initial_tick = TIMER4VAL();
+
+	if (n <= UINT_MAX / TIMER_FREQ) {
+		/*
+		 * For unsigned arithmetic, division can be replaced with
+		 * multiplication with the inverse and a shift.
+		 */
+		remaining = n * TIMER_FREQ / 1000000;
 	} else {
-		delta = tmarknow - tmark;
-	}
-
-	TIMER4VAL_TO_US(delta);
-
-	tvp->tv_usec += delta;
-
-        /* Make sure microseconds doesn't overflow. */
-	while (__predict_false(tvp->tv_usec >= 1000000)) {
-		tvp->tv_usec -= 1000000;
-		tvp->tv_sec++;
+		/* This is a very long delay.
+		 * Being slow here doesn't matter.
+		 */
+		remaining = (unsigned long long) n * TIMER_FREQ / 1000000;
 	}
 
-        /* Make sure the time has advanced. */
-	if (__predict_false(tvp->tv_sec == lasttv.tv_sec &&
-	    tvp->tv_usec <= lasttv.tv_usec)) {
-		tvp->tv_usec = lasttv.tv_usec + 1;
-		if (tvp->tv_usec >= 1000000) {
-			tvp->tv_usec -= 1000000;
-			tvp->tv_sec++;
-		}
+	while (remaining > 0) {
+		cur_tick = TIMER4VAL();
+		if (cur_tick > initial_tick)
+			remaining -= UINT_MAX - (cur_tick - initial_tick);
+		else
+			remaining -= initial_tick - cur_tick;
+		initial_tick = cur_tick;
 	}
-
-	lasttv = *tvp;
-
-	restore_interrupts(oldirqstate);
 }
 
-/*
- * delay:
- *
- *	Delay for at least N microseconds.
- */
-void
-delay(unsigned int len)
+static u_int
+epclk_get_timecount(struct timecounter *tc)
 {
-	u_int32_t	start, end, ticks;
-
-#ifdef DEBUG
-	if (epclk_sc == NULL) {
-		printf("delay: called before start epclk\n");
-		return;
-	}
-#endif
-
-	ticks = start = TIMER4VAL();
-	US_TO_TIMER4VAL(len);
-	end = start + len;
-	while (start <= ticks && ticks > end) {
-		/* wait for Timer4ValueLow wraparound */
-		ticks = TIMER4VAL();
-	}
-	while (ticks <= end) {
-		ticks = TIMER4VAL();
-	}
+	return TIMER4VAL();
 }
Index: arm/include/types.h
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/include/types.h,v
retrieving revision 1.14
diff -u -p -r1.14 types.h
--- arm/include/types.h	9 Mar 2007 05:40:08 -0000	1.14
+++ arm/include/types.h	7 Jan 2008 16:55:51 -0000
@@ -81,4 +81,6 @@ typedef	volatile int		__cpu_simple_lock_
 #define	__HAVE_RAS
 #endif
 
+#define	__HAVE_TIMECOUNTER
+
 #endif	/* _ARM_TYPES_H_ */
Index: arm/ixp12x0/ixp12x0_clk.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/ixp12x0/ixp12x0_clk.c,v
retrieving revision 1.11
diff -u -p -r1.11 ixp12x0_clk.c
--- arm/ixp12x0/ixp12x0_clk.c	6 Jan 2007 16:18:18 -0000	1.11
+++ arm/ixp12x0/ixp12x0_clk.c	8 Jan 2008 17:19:45 -0000
@@ -42,9 +42,11 @@ __KERNEL_RCSID(0, "$NetBSD: ixp12x0_clk.
 
 #include <sys/types.h>
 #include <sys/param.h>
+#include <sys/atomic.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 #include <sys/device.h>
 
 #include <machine/bus.h>
@@ -61,6 +63,8 @@ __KERNEL_RCSID(0, "$NetBSD: ixp12x0_clk.
 static int	ixpclk_match(struct device *, struct cfdata *, void *);
 static void	ixpclk_attach(struct device *, struct device *, void *);
 
+static u_int	ixpclk_get_timecount(struct timecounter *);
+
 int		gettick(void);
 void		rtcinit(void);
 
@@ -119,6 +123,19 @@ static u_int32_t ccf_to_coreclock[MAX_CC
 
 static struct ixpclk_softc *ixpclk_sc = NULL;
 
+static struct timecounter ixpclk_timecounter = {
+	ixpclk_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	0xffffffff,		/* counter_mask */
+	0,			/* frequency */
+	"ixpclk",		/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
+
+static volatile uint32_t ixpclk_base;
+
 #define TIMER_FREQUENCY         3686400         /* 3.6864MHz */
 #define TICKS_PER_MICROSECOND   (TIMER_FREQUENCY/1000000)
 
@@ -143,6 +160,7 @@ ixpclk_attach(struct device *parent, str
 	struct ixpclk_softc		*sc;
 	struct ixpsip_attach_args	*sa;
 	u_int32_t			ccf;
+	bool first_run = ixpclk_sc == NULL;
 
 	printf("\n");
 
@@ -181,6 +199,11 @@ ixpclk_attach(struct device *parent, str
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCLK_CONTROL,
 			  IXPCL_ENABLE | IXPCL_PERIODIC | IXPCL_STP_CORE);
 
+	if (first_run) {
+		ixpclk_timecounter.tc_frequency = sc->sc_coreclock_freq;
+		tc_init(&ixpclk_timecounter);
+	}
+
 	printf("%s: IXP12x0 Interval Timer (core clock %d.%03dMHz)\n",
 	       sc->sc_dev.dv_xname,
 	       sc->sc_coreclock_freq / 1000000,
@@ -199,6 +222,8 @@ ixpclk_intr(void *arg)
 	bus_space_write_4(ixpclk_sc->sc_iot, ixpclk_sc->sc_ioh,
 			  IXPCLK_CLEAR, 1);
 
+	atomic_add_32(&ixpclk_base, ixpclk_sc->sc_coreclock_freq);
+
 	hardclock((struct clockframe*) arg);
 	return (1);
 }
@@ -261,55 +286,19 @@ gettick(void)
 	return counter;
 }
 
-/*
- * microtime:
- *
- *	Fill in the specified timeval struct with the current time
- *	accurate to the microsecond.
- */
-void
-microtime(register struct timeval *tvp)
+static u_int
+ixpclk_get_timecount(struct timecounter *tc)
 {
-	u_int			oldirqstate;
-	u_int32_t		counts;
-	static struct timeval	lasttv;
+	u_int	savedints, base, counter;
 
-	if (ixpclk_sc == NULL) {
-#ifdef DEBUG
-		printf("microtime: called befor initialize ixpclk\n");
-#endif
-		tvp->tv_sec = 0;
-		tvp->tv_usec = 0;
-		return;
-	}
-
-	oldirqstate = disable_interrupts(I32_bit);
-
-	counts = ixpclk_sc->sc_clock_count - GET_TIMER_VALUE(ixpclk_sc);
-
-        /* Fill in the timeval struct. */
-	*tvp = time;
-	tvp->tv_usec += counts / ixpclk_sc->sc_count_per_usec;
-
-        /* Make sure microseconds doesn't overflow. */
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_usec -= 1000000;
-		tvp->tv_sec++;
-	}
-
-        /* Make sure the time has advanced. */
-	if (tvp->tv_sec == lasttv.tv_sec &&
-	    tvp->tv_usec <= lasttv.tv_usec) {
-		tvp->tv_usec = lasttv.tv_usec + 1;
-		if (tvp->tv_usec >= 1000000) {
-			tvp->tv_usec -= 1000000;
-			tvp->tv_sec++;
-		}
-	}
-
-	lasttv = *tvp;
+	savedints = disable_interrupts(I32_bit);
+	do {
+		base = ixpclk_base;
+		counter = GET_TIMER_VALUE(ixpclk_sc);
+	} while (base != ixpclk_base);
+	restore_interrupts(savedints);
 
-	restore_interrupts(oldirqstate);
+	return base - counter;
 }
 
 /*
Index: arm/ofw/ofwgencfg_clock.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/ofw/ofwgencfg_clock.c,v
retrieving revision 1.7
diff -u -p -r1.7 ofwgencfg_clock.c
--- arm/ofw/ofwgencfg_clock.c	8 Mar 2007 20:48:39 -0000	1.7
+++ arm/ofw/ofwgencfg_clock.c	8 Jan 2008 18:12:09 -0000
@@ -135,50 +135,6 @@ cpu_initclocks()
 	}
 }
 
-
-/*
- * void microtime(struct timeval *tvp)
- *
- * Fill in the specified timeval struct with the current time
- * accurate to the microsecond.
- */
-
-void
-microtime(tvp)
-	struct timeval *tvp;
-{
-	int s;
-	static struct timeval oldtv;
-
-	s = splhigh();
-
-	/* Fill in the timeval struct */
-
-	*tvp = time;    
-
-	/* Make sure the micro seconds don't overflow. */
-
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_usec -= 1000000;
-		++tvp->tv_sec;
-	}
-
-	/* Make sure the time has advanced. */
-
-	if (tvp->tv_sec == oldtv.tv_sec &&
-	    tvp->tv_usec <= oldtv.tv_usec) {
-		tvp->tv_usec = oldtv.tv_usec + 1;
-		if (tvp->tv_usec >= 1000000) {
-			tvp->tv_usec -= 1000000;
-			++tvp->tv_sec;
-		}
-	}
-	    
-
-	oldtv = *tvp;
-	(void)splx(s);		
-}
-
 /*
  * Estimated loop for n microseconds
  */
Index: arm/omap/omap_mputmr.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/omap/omap_mputmr.c,v
retrieving revision 1.2
diff -u -p -r1.2 omap_mputmr.c
--- arm/omap/omap_mputmr.c	6 Jan 2008 01:37:55 -0000	1.2
+++ arm/omap/omap_mputmr.c	12 Jan 2008 23:29:40 -0000
@@ -80,6 +80,7 @@ __KERNEL_RCSID(0, "$NetBSD: omap_mputmr.
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 #include <sys/device.h>
 
 #include <dev/clock_subr.h>
@@ -115,7 +116,6 @@ struct omapmputmr_softc {
 
 static uint32_t counts_per_usec, counts_per_hz;
 static uint32_t hardref;
-static struct timeval hardtime;
 static struct omapmputmr_softc *clock_sc = NULL;
 static struct omapmputmr_softc *stat_sc = NULL;
 static struct omapmputmr_softc *ref_sc = NULL;
@@ -237,11 +237,9 @@ clockintr(void *arg)
 	int ticks, i, oldirqstate;
 
 	oldirqstate = disable_interrupts(I32_bit);
-	hardtime = time;
 	newref = bus_space_read_4(ref_sc->sc_iot, ref_sc->sc_ioh,
 				  MPU_READ_TIMER);
 	ticks = hardref ? (hardref - newref) / counts_per_hz : 1;
-	hardtime.tv_usec += (hardref - newref) / counts_per_usec;
 	hardref = newref;
 	restore_interrupts(oldirqstate);
 
@@ -300,6 +298,31 @@ setstatclockrate(int schz)
 			    | MPU_ST));
 }
 
+static u_int
+mpu_get_timecount(struct timecounter *tc)
+{
+	uint32_t counter;
+	int oldirqstate;
+
+	oldirqstate = disable_interrupts(I32_bit);
+	counter = bus_space_read_4(ref_sc->sc_iot, ref_sc->sc_ioh,
+			       MPU_READ_TIMER);
+	restore_interrupts(oldirqstate);
+
+	return counter;
+}
+
+static struct timecounter mpu_timecounter = {
+	mpu_get_timecount,
+	NULL,
+	0xffffffff,
+	0,
+	"mpu",
+	100,
+	NULL,
+	NULL,
+};
+
 void
 cpu_initclocks(void)
 {
@@ -325,61 +348,8 @@ cpu_initclocks(void)
 			    clock_sc->sc_dev.dv_xname, clockintr, 0);
 	omap_intr_establish(stat_sc->sc_intr, IPL_HIGH,
 			    stat_sc->sc_dev.dv_xname, statintr, 0);
-}
-
-void
-microtime(struct timeval *tvp)
-{
-	u_int oldirqstate;
-	uint32_t ref, baseref;
-	static struct timeval lasttime;
-	static uint32_t lastref;
-
-	if (clock_sc == NULL) {
-		tvp->tv_sec = 0;
-		tvp->tv_usec = 0;
-		return;
-	}
 
-	oldirqstate = disable_interrupts(I32_bit);
-	ref = bus_space_read_4(ref_sc->sc_iot, ref_sc->sc_ioh,
-			       MPU_READ_TIMER);
-
-	*tvp = hardtime;
-	baseref = hardref;
-
-	/*
-	 * If time was just jumped forward and hardtime hasn't caught up
-	 * then just use time.
-	 */
-
-	if (time.tv_sec - hardtime.tv_sec > 1)
-		*tvp = time;
-
-	if (tvp->tv_sec < lasttime.tv_sec ||
-	    (tvp->tv_sec == lasttime.tv_sec &&
-	     tvp->tv_usec < lasttime.tv_usec)) {
-		*tvp = lasttime;
-		baseref = lastref;
-
-	} else {
-		lasttime = *tvp;
-		lastref = ref;
-	}
-
-	restore_interrupts(oldirqstate);
-
-	/* Prior to the first hardclock completion we don't have a
-	   microtimer reference. */
-
-	if (baseref)
-		tvp->tv_usec += (baseref - ref) / counts_per_usec;
-
-	/* Make sure microseconds doesn't overflow. */
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_usec -= 1000000;
-		tvp->tv_sec++;
-	}
+	tc_init(&mpu_timecounter);
 }
 
 void
Index: arm/s3c2xx0/s3c24x0_clk.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/s3c2xx0/s3c24x0_clk.c,v
retrieving revision 1.8
diff -u -p -r1.8 s3c24x0_clk.c
--- arm/s3c2xx0/s3c24x0_clk.c	6 Jan 2008 01:37:55 -0000	1.8
+++ arm/s3c2xx0/s3c24x0_clk.c	12 Jan 2008 23:18:02 -0000
@@ -35,7 +35,9 @@ __KERNEL_RCSID(0, "$NetBSD: s3c24x0_clk.
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/atomic.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 
 #include <machine/bus.h>
 #include <machine/intr.h>
@@ -61,27 +63,26 @@ static unsigned int timer4_mseccount;
 #define counter_to_usec(c,pclk)	\
 	(((c)*timer4_prescaler*1000)/(TIMER_FREQUENCY(pclk)/1000))
 
+static u_int	s3c24x0_get_timecount(struct timecounter *);
 
-/*
- * microtime:
- *
- *	Fill in the specified timeval struct with the current time
- *	accurate to the microsecond.
- */
-void
-microtime(struct timeval *tvp)
+static struct timecounter s3c24x0_timecounter = {
+	s3c24x0_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	0xffffffff,		/* counter_mask */
+	0,		/* frequency */
+	"s3c234x0",		/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
+
+static volatile uint32_t s3c24x0_base;
+
+static u_int
+s3c24x0_get_timecount(struct timecounter *tc)
 {
 	struct s3c24x0_softc *sc = (struct s3c24x0_softc *) s3c2xx0_softc;
-	int save, int_pend0, int_pend1, count, delta;
-	static struct timeval last;
-	int pclk = s3c2xx0_softc->sc_pclk;
-
-	if( timer4_reload_value == 0 ){
-		/* not initialized yet */
-		tvp->tv_sec = 0;
-		tvp->tv_usec = 0;
-		return;
-	}
+	int save, int_pend0, int_pend1, count;
 
 	save = disable_interrupts(I32_bit);
 
@@ -92,7 +93,7 @@ microtime(struct timeval *tvp)
 	count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh,
 	    TIMER_TCNTO(4));
 	
-	for (;;){
+	for (;;) {
 
 		int_pend1 = S3C24X0_INT_TIMER4 &
 		    bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_intctl_ioh,
@@ -109,63 +110,22 @@ microtime(struct timeval *tvp)
 		    TIMER_TCNTO(4));
 	}
 
-	if( __predict_false(count > timer4_reload_value) ){
+	if (__predict_false(count > timer4_reload_value)) {
 		/* 
 		 * Buggy Hardware Warning --- sometimes timer counter
 		 * reads bogus value like 0xffff.  I guess it happens when
 		 * the timer is reloaded.
 		 */
-		printf( "Bogus value from timer counter: %d\n", count );
+		printf("Bogus value from timer counter: %d\n", count);
 		goto again;
 	}
 
-	/* copy system time */
-	*tvp = time;
-
 	restore_interrupts(save);
 
-	delta = timer4_reload_value - count;
-
-	if( int_pend1 ){
-		/*
-		 * down counter underflow, but
-		 * clock interrupt have not serviced yet
-		 */
-		tvp->tv_usec += tick;
-	}
-
-	tvp->tv_usec += counter_to_usec(delta, pclk);
-
-	/* Make sure microseconds doesn't overflow. */
-	tvp->tv_sec += tvp->tv_usec / 1000000;
-	tvp->tv_usec = tvp->tv_usec % 1000000;
-
-	if (last.tv_sec &&
-	    (tvp->tv_sec < last.tv_sec ||
-		(tvp->tv_sec == last.tv_sec && 
-		    tvp->tv_usec < last.tv_usec) ) ){
-
-		/* XXX: This happens very often when the kernel runs
-		   under Multi-ICE */
-#if 0
-		printf("time reversal: %ld.%06ld(%d,%d) -> %ld.%06ld(%d,%d)\n",
-		    last.tv_sec, last.tv_usec,
-		    last_count, last_pend,
-		    tvp->tv_sec, tvp->tv_usec,
-		    count, int_pend1 );
-#endif
-			    
-		/* make sure the time has advanced. */
-		*tvp = last;
-		tvp->tv_usec++;
-		if( tvp->tv_usec >= 1000000 ){
-			tvp->tv_usec -= 1000000;
-			tvp->tv_sec++;
-		}
-	}
-
-	last = *tvp;
+	if (int_pend1)
+		count -= timer4_reload_value;
 
+	return s3c24x0_base - count;
 }
 
 static inline int
@@ -235,8 +195,15 @@ setstatclockrate(int newhz)
 {
 }
 
-#define hardintr	(int (*)(void *))hardclock
-#define statintr	(int (*)(void *))statclock
+static int
+hardintr(void *arg)
+{
+	atomic_add_32(&s3c24x0_base, timer4_reload_value);
+
+	hardclock((struct clockframe *)arg);
+
+	return 1;
+}
 
 void
 cpu_initclocks(void)
@@ -316,6 +283,9 @@ cpu_initclocks(void)
 	bus_space_write_4(iot, ioh, TIMER_TCON, reg |
 	    TCON_AUTORELOAD(3) | TCON_START(3) |
 	    TCON_AUTORELOAD(4) | TCON_START(4) );
+
+	s3c24x0_timecounter.tc_frequency = pclk;
+	tc_init(&s3c24x0_timecounter);
 }
 
 
Index: arm/s3c2xx0/s3c2800_clk.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/s3c2xx0/s3c2800_clk.c,v
retrieving revision 1.11
diff -u -p -r1.11 s3c2800_clk.c
--- arm/s3c2xx0/s3c2800_clk.c	6 Jan 2008 01:37:55 -0000	1.11
+++ arm/s3c2xx0/s3c2800_clk.c	12 Jan 2008 23:17:50 -0000
@@ -39,7 +39,9 @@ __KERNEL_RCSID(0, "$NetBSD: s3c2800_clk.
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/atomic.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 
 #include <machine/bus.h>
 #include <machine/intr.h>
@@ -65,26 +67,26 @@ static unsigned int timer0_mseccount;
 #define counter_to_usec(c,pclk)	\
 	(((c)*timer0_prescaler*1000)/(TIMER_FREQUENCY(pclk)/1000))
 
-/*
- * microtime:
- *
- *	Fill in the specified timeval struct with the current time
- *	accurate to the microsecond.
- */
-void
-microtime(struct timeval *tvp)
+static u_int	s3c2800_get_timecount(struct timecounter *);
+
+static struct timecounter s3c2800_timecounter = {
+	s3c2800_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	0xffffffff,		/* counter_mask */
+	0,		/* frequency */
+	"s3c23800",		/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
+
+static volatile uint32_t s3c2800_base;
+
+static u_int
+s3c2800_get_timecount(struct timecounter *tc)
 {
 	struct s3c2800_softc *sc = (struct s3c2800_softc *) s3c2xx0_softc;
-	int save, int_pend0, int_pend1, count, delta;
-	static struct timeval last;
-	int pclk = s3c2xx0_softc->sc_pclk;
-
-	if( timer0_reload_value == 0 ){
-		/* not initialized yet */
-		tvp->tv_sec = 0;
-		tvp->tv_usec = 0;
-		return;
-	}
+	int save, int_pend0, int_pend1, count;
 
 	save = disable_interrupts(I32_bit);
 
@@ -124,56 +126,12 @@ microtime(struct timeval *tvp)
 		goto again;
 	}
 
-	/* copy system time */
-	*tvp = time;
-
 	restore_interrupts(save);
 
-	delta = timer0_reload_value - count;
+	if (int_pend1)
+		count -= timer0_reload_value;
 
-	if( int_pend1 ){
-		/*
-		 * down counter underflow, but
-		 * clock interrupt have not serviced yet
-		 */
-#if 1
-		tvp->tv_usec += tick;
-#else
-		delta = 0;
-#endif
-	}
-
-	tvp->tv_usec += counter_to_usec(delta, pclk);
-
-	/* Make sure microseconds doesn't overflow. */
-	tvp->tv_sec += tvp->tv_usec / 1000000;
-	tvp->tv_usec = tvp->tv_usec % 1000000;
-
-	if (last.tv_sec &&
-	    (tvp->tv_sec < last.tv_sec ||
-		(tvp->tv_sec == last.tv_sec && 
-		    tvp->tv_usec < last.tv_usec) ) ){
-
-		/* XXX: This happens very often when the kernel runs
-		   under Multi-ICE */
-#if 0
-		printf("time reversal: %ld.%06ld(%d,%d) -> %ld.%06ld(%d,%d)\n",
-		    last.tv_sec, last.tv_usec,
-		    last_count, last_pend,
-		    tvp->tv_sec, tvp->tv_usec,
-		    count, int_pend1 );
-#endif
-			    
-		/* make sure the time has advanced. */
-		*tvp = last;
-		tvp->tv_usec++;
-		if( tvp->tv_usec >= 1000000 ){
-			tvp->tv_usec -= 1000000;
-			tvp->tv_sec++;
-		}
-	}
-
-	last = *tvp;
+	return s3c2800_base - count;
 }
 
 static inline int
@@ -243,9 +201,15 @@ setstatclockrate(int newhz)
 {
 }
 
+static int
+hardintr(void *arg)
+{
+	atomic_add_32(&s3c2800_base, timer4_reload_value);
 
-#define hardintr	(int (*)(void *))hardclock
-#define statintr	(int (*)(void *))statclock
+	hardclock((struct clockframe *)arg);
+
+	return 1;
+}
 
 void
 cpu_initclocks()
@@ -313,4 +277,7 @@ cpu_initclocks()
 		    S3C2800_TIMER_SIZE);
 
 	}
+
+	s3c2800_timecounter.tc_frequency = pclk;
+	tc_init(&s3c2800_timecounter);
 }
Index: arm/sa11x0/sa11x0_ost.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/sa11x0/sa11x0_ost.c,v
retrieving revision 1.20
diff -u -p -r1.20 sa11x0_ost.c
--- arm/sa11x0/sa11x0_ost.c	24 Sep 2006 15:40:14 -0000	1.20
+++ arm/sa11x0/sa11x0_ost.c	7 Jan 2008 16:50:48 -0000
@@ -60,9 +60,7 @@ __KERNEL_RCSID(0, "$NetBSD: sa11x0_ost.c
 static int	saost_match(struct device *, struct cfdata *, void *);
 static void	saost_attach(struct device *, struct device *, void *);
 
-#ifdef __HAVE_TIMECOUNTER
 static void	saost_tc_init(void);
-#endif /* __HAVE_TIMECOUNTER */
 
 static uint32_t	gettick(void);
 static int	clockintr(void *);
@@ -239,12 +237,9 @@ cpu_initclocks(void)
 	/* Zero the counter value */
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SAOST_CR, 0);
 
-#ifdef __HAVE_TIMECOUNTER
 	saost_tc_init();
-#endif /* __HAVE_TIMECOUNTER */
 }
 
-#ifdef __HAVE_TIMECOUNTER
 static u_int
 saost_tc_get_timecount(struct timecounter *tc)
 {
@@ -264,7 +259,6 @@ saost_tc_init(void)
 
 	tc_init(&saost_tc);
 }
-#endif /* __HAVE_TIMECOUNTER */
 
 static uint32_t
 gettick(void)
@@ -280,44 +274,6 @@ gettick(void)
 	return counter;
 }
 
-#ifndef __HAVE_TIMECOUNTER
-void
-microtime(struct timeval *tvp)
-{
-	struct saost_softc *sc = saost_sc;
-	int s, tm, deltatm;
-	static struct timeval lasttime;
-
-	if (sc == NULL) {
-		tvp->tv_sec = 0;
-		tvp->tv_usec = 0;
-		return;
-	}
-
-	s = splhigh();
-	tm = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SAOST_CR);
-
-	deltatm = sc->sc_clock_count - tm;
-
-	*tvp = time;
-	tvp->tv_usec++;		/* XXX */
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_sec++;
-		tvp->tv_usec -= 1000000;
-	}
-
-	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);
-}
-#endif /* !__HAVE_TIMECOUNTER */
-
 void
 delay(u_int usecs)
 {
Index: arm/xscale/becc_timer.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/xscale/becc_timer.c,v
retrieving revision 1.13
diff -u -p -r1.13 becc_timer.c
--- arm/xscale/becc_timer.c	6 Jan 2008 01:37:57 -0000	1.13
+++ arm/xscale/becc_timer.c	8 Jan 2008 21:01:10 -0000
@@ -45,7 +45,9 @@ __KERNEL_RCSID(0, "$NetBSD: becc_timer.c
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/atomic.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 
 #include <dev/clock_subr.h>
 
@@ -65,6 +67,21 @@ void	(*becc_hardclock_hook)(void);
 
 static void *clock_ih;
 
+static u_int	becc_get_timecount(struct timecounter *);
+
+static struct timecounter becc_timecounter = {
+	becc_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	0xffffffff,		/* counter_mask */
+	COUNTS_PER_SEC,		/* frequency */
+	"becc",			/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
+
+static volatile uint32_t becc_base;
+
 /*
  * Since the timer interrupts when the counter underflows, we need to
  * subtract 1 from counts_per_hz when loading the preload register.
@@ -115,15 +132,6 @@ cpu_initclocks(void)
 		hz = 100;
 	}
 #endif
-	tick = 1000000 / hz;	/* number of microseconds between interrupts */
-	tickfix = 1000000 - (hz * tick);
-	if (tickfix) {
-		int ftp;
-
-		ftp = min(ffs(tickfix), ffs(hz));
-		tickfix >>= (ftp - 1);
-		tickfixinterval = hz >> (ftp - 1);
-	}
 
 	/*
 	 * We only have one timer available; stathz and profhz are
@@ -168,6 +176,8 @@ cpu_initclocks(void)
 #endif
 
 	restore_interrupts(oldirqstate);
+
+	tc_init(&becc_timecounter);
 }
 
 /*
@@ -188,49 +198,18 @@ setstatclockrate(int new_hz)
 	 */
 }
 
-/*
- * microtime:
- *
- *	Fill in the specified timeval struct with the current time
- *	accurate to the microsecond.
- */
-void
-microtime(struct timeval *tvp)
+static u_int
+becc_get_timecount(struct timecounter *tc)
 {
-	static struct timeval lasttv;
+	uint32_t counter, base;
 	u_int oldirqstate;
-	uint32_t counts;
 
 	oldirqstate = disable_interrupts(I32_bit);
-
-	/*
-	 * XXX How do we compensate for the -1 behavior of the preload value?
-	 */
-	counts = counts_per_hz - BECC_CSR_READ(BECC_TCVRA);
-
-	/* Fill in the timeval struct. */
-	*tvp = time;
-	tvp->tv_usec += (counts / COUNTS_PER_USEC);
-
-	/* Make sure microseconds doesn't overflow. */
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_usec -= 1000000;
-		tvp->tv_sec++;
-	}
-
-	/* Make sure the time has advanced. */
-	if (tvp->tv_sec == lasttv.tv_sec &&
-	    tvp->tv_usec <= lasttv.tv_usec) {
-		tvp->tv_usec = lasttv.tv_usec + 1;
-		if (tvp->tv_usec >= 1000000) {
-			tvp->tv_usec -= 1000000;
-			tvp->tv_sec++;
-		}
-	}
-
-	lasttv = *tvp;
-
+	counter = BECC_CSR_READ(BECC_TCVRA);
+	base = becc_base;
 	restore_interrupts(oldirqstate);
+
+	return base - counter;
 }
 
 /*
@@ -283,6 +262,8 @@ clockhandler(void *arg)
 
 	hardclock(frame);
 
+	atomic_add_32(&becc_base, counts_per_hz);
+
 	if (becc_hardclock_hook != NULL)
 		(*becc_hardclock_hook)();
 
Index: arm/xscale/i80321_timer.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/xscale/i80321_timer.c,v
retrieving revision 1.17
diff -u -p -r1.17 i80321_timer.c
--- arm/xscale/i80321_timer.c	3 Dec 2007 15:33:20 -0000	1.17
+++ arm/xscale/i80321_timer.c	7 Jan 2008 16:51:28 -0000
@@ -68,9 +68,7 @@ void	(*i80321_hardclock_hook)(void);
 #endif
 #define	COUNTS_PER_USEC		(COUNTS_PER_SEC / 1000000)
 
-#ifdef __HAVE_TIMECOUNTER
 static void tmr1_tc_init(void);
-#endif
 
 static void *clock_ih;
 
@@ -125,8 +123,6 @@ trr0_write(uint32_t val)
 		: "r" (val));
 }
 
-#ifdef __HAVE_TIMECOUNTER
-
 static inline uint32_t
 tmr1_read(void)
 {
@@ -174,8 +170,6 @@ trr1_write(uint32_t val)
 		: "r" (val));
 }
 
-#endif /* __HAVE_TIMECOUNTER */
-
 static inline void
 tisr_write(uint32_t val)
 {
@@ -225,17 +219,6 @@ cpu_initclocks(void)
 		aprint_error("Cannot get %d Hz clock; using 100 Hz\n", hz);
 		hz = 100;
 	}
-#ifndef __HAVE_TIMECOUNTER
-	tick = 1000000 / hz;	/* number of microseconds between interrupts */
-	tickfix = 1000000 - (hz * tick);
-	if (tickfix) {
-		int ftp;
-
-		ftp = min(ffs(tickfix), ffs(hz));
-		tickfix >>= (ftp - 1);
-		tickfixinterval = hz >> (ftp - 1);
-	}
-#endif
 
 	/*
 	 * We only have one timer available; stathz and profhz are
@@ -282,9 +265,7 @@ cpu_initclocks(void)
 
 	restore_interrupts(oldirqstate);
 
-#ifdef	__HAVE_TIMECOUNTER
 	tmr1_tc_init();
-#endif
 }
 
 /*
@@ -305,53 +286,6 @@ setstatclockrate(int newhz)
 	 */
 }
 
-#ifndef __HAVE_TIMECOUNTER
-
-/*
- * microtime:
- *
- *	Fill in the specified timeval struct with the current time
- *	accurate to the microsecond.
- */
-void
-microtime(struct timeval *tvp)
-{
-	static struct timeval lasttv;
-	u_int oldirqstate;
-	uint32_t counts;
-
-	oldirqstate = disable_interrupts(I32_bit);
-
-	counts = counts_per_hz - tcr0_read();
-
-	/* Fill in the timeval struct. */
-	*tvp = time;
-	tvp->tv_usec += (counts / COUNTS_PER_USEC);
-
-	/* Make sure microseconds doesn't overflow. */
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_usec -= 1000000;
-		tvp->tv_sec++;
-	}
-
-	/* Make sure the time has advanced. */
-	if (tvp->tv_sec == lasttv.tv_sec &&
-	    tvp->tv_usec <= lasttv.tv_usec) {
-		tvp->tv_usec = lasttv.tv_usec + 1;
-		if (tvp->tv_usec >= 1000000) {
-			tvp->tv_usec -= 1000000;
-			tvp->tv_sec++;
-		}
-	}
-
-	lasttv = *tvp;
-
-	restore_interrupts(oldirqstate);
-}
-
-
-#else
-
 static inline uint32_t
 tmr1_tc_get(struct timecounter *tch)
 {
@@ -379,7 +313,6 @@ tmr1_tc_init(void)
 	trr1_write(~0);
 	tc_init(&tmr1_tc);
 }
-#endif
 
 /*
  * delay:
Index: arm/xscale/ixp425_timer.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/arm/xscale/ixp425_timer.c,v
retrieving revision 1.13
diff -u -p -r1.13 ixp425_timer.c
--- arm/xscale/ixp425_timer.c	6 Jan 2007 16:18:18 -0000	1.13
+++ arm/xscale/ixp425_timer.c	8 Jan 2008 20:50:29 -0000
@@ -43,7 +43,9 @@ __KERNEL_RCSID(0, "$NetBSD: ixp425_timer
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/atomic.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 #include <sys/device.h>
 
 #include <dev/clock_subr.h>
@@ -59,6 +61,7 @@ __KERNEL_RCSID(0, "$NetBSD: ixp425_timer
 
 static int	ixpclk_match(struct device *, struct cfdata *, void *);
 static void	ixpclk_attach(struct device *, struct device *, void *);
+static u_int	ixpclk_get_timecount(struct timecounter *);
 
 static uint32_t counts_per_hz;
 
@@ -83,6 +86,19 @@ struct ixpclk_softc {
 
 static struct ixpclk_softc *ixpclk_sc;
 
+static struct timecounter ixpclk_timecounter = {
+	ixpclk_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	0xffffffff,		/* counter_mask */
+	COUNTS_PER_SEC,		/* frequency */
+	"ixpclk",		/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
+
+static volatile uint32_t ixpclk_base;
+
 CFATTACH_DECL(ixpclk, sizeof(struct ixpclk_softc),
 		ixpclk_match, ixpclk_attach, NULL, NULL);
 
@@ -137,15 +153,6 @@ cpu_initclocks(void)
 		aprint_error("Cannot get %d Hz clock; using 100 Hz\n", hz);
 		hz = 100;
 	}
-	tick = 1000000 / hz;	/* number of microseconds between interrupts */
-	tickfix = 1000000 - (hz * tick);
-	if (tickfix) {
-		int ftp;
-
-		ftp = min(ffs(tickfix), ffs(hz));
-		tickfix >>= (ftp - 1);
-		tickfixinterval = hz >> (ftp - 1);
-	}
 
 	/*
 	 * We only have one timer available; stathz and profhz are
@@ -192,6 +199,8 @@ cpu_initclocks(void)
 			  (counts_per_hz & TIMERRELOAD_MASK) | OST_TIMER_EN);
 
 	restore_interrupts(oldirqstate);
+
+	tc_init(&ixpclk_timecounter);
 }
 
 /*
@@ -212,47 +221,17 @@ setstatclockrate(int newhz)
 	 */
 }
 
-/*
- * microtime:
- *
- *	Fill in the specified timeval struct with the current time
- *	accurate to the microsecond.
- */
-void
-microtime(struct timeval *tvp)
+static u_int
+ixpclk_get_timecount(struct timecounter *tc)
 {
-	struct ixpclk_softc* sc = ixpclk_sc;
-	static struct timeval lasttv;
-	u_int oldirqstate;
-	uint32_t counts;
-
-	oldirqstate = disable_interrupts(I32_bit);
-
-	counts = counts_per_hz - GET_TIMER_VALUE(sc);
-
-	/* Fill in the timeval struct. */
-	*tvp = time;
-	tvp->tv_usec += (counts / COUNTS_PER_USEC);
-
-	/* Make sure microseconds doesn't overflow. */
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_usec -= 1000000;
-		tvp->tv_sec++;
-	}
-
-	/* Make sure the time has advanced. */
-	if (tvp->tv_sec == lasttv.tv_sec &&
-	    tvp->tv_usec <= lasttv.tv_usec) {
-		tvp->tv_usec = lasttv.tv_usec + 1;
-		if (tvp->tv_usec >= 1000000) {
-			tvp->tv_usec -= 1000000;
-			tvp->tv_sec++;
-		}
-	}
+	u_int	savedints, base, counter;
 
-	lasttv = *tvp;
+	savedints = disable_interrupts(I32_bit);
+	base = ixpclk_base;
+	counter = GET_TIMER_VALUE(ixpclk_sc);
+	restore_interrupts(savedints);
 
-	restore_interrupts(oldirqstate);
+	return base - counter;
 }
 
 /*
@@ -304,6 +283,8 @@ ixpclk_intr(void *arg)
 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS,
 			  OST_TIM0_INT);
 
+	atomic_add_32(&ixpclk_base, counts_per_hz);
+
 	hardclock(frame);
 
 	return (1);
Index: evbarm/ifpga/ifpga_clock.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/evbarm/ifpga/ifpga_clock.c,v
retrieving revision 1.11
diff -u -p -r1.11 ifpga_clock.c
--- evbarm/ifpga/ifpga_clock.c	22 Dec 2007 01:21:41 -0000	1.11
+++ evbarm/ifpga/ifpga_clock.c	8 Jan 2008 21:23:37 -0000
@@ -45,7 +45,9 @@ __KERNEL_RCSID(0, "$NetBSD: ifpga_clock.
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/atomic.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 #include <sys/device.h>
 
 #include <arm/cpufunc.h>
@@ -81,6 +83,21 @@ static int statprev;		/* previous value 
 
 #define COUNTS_PER_SEC (IFPGA_TIMER1_FREQ / 16)
 
+static u_int	ifpga_get_timecount(struct timecounter *);
+
+static struct timecounter ifpga_timecounter = {
+	ifpga_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	0xffffffff,		/* counter_mask */
+	COUNTS_PER_SEC,		/* frequency */
+	"ifpga",		/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
+
+static volatile uint32_t ifpga_base;
+
 extern struct ifpga_softc *ifpga_sc;
 
 static int clock_started = 0;
@@ -115,6 +132,9 @@ clockhandler(void *fr)
 
 	bus_space_write_4(ifpga_sc->sc_iot, ifpga_sc->sc_tmr_ioh,
 	    TIMER_1_CLEAR, 0);
+
+	atomic_add_32(&ifpga_base, ifpga_sc->sc_clock_count);
+
 	hardclock(frame);
 	return 0;	/* Pass the interrupt on down the chain */
 }
@@ -288,60 +308,21 @@ cpu_initclocks()
 		panic("%s: Cannot install timer 2 interrupt handler",
 		    ifpga_sc->sc_dev.dv_xname);
 	load_timer(IFPGA_TIMER2_BASE, statint);
-}
 
+	tc_init(&ifpga_timecounter);
+}
 
-/*
- * void microtime(struct timeval *tvp)
- *
- * Fill in the specified timeval struct with the current time
- * accurate to the microsecond.
- */
-
-void
-microtime(struct timeval *tvp)
+static u_int
+ifpga_get_timecount(struct timecounter *tc)
 {
-	int s;
-	int tm;
-	int deltatm;
-	static struct timeval oldtv;
+	u_int base, counter;
 
-	if (ifpga_sc == NULL || ifpga_sc->sc_clock_count == 0)
-		return;
-
-	s = splhigh();
-
-	tm = getclock();
-
-	deltatm = ifpga_sc->sc_clock_count - tm;
-
-#ifdef DIAGNOSTIC
-	if (deltatm < 0)
-		panic("opps deltatm < 0 tm=%d deltatm=%d", tm, deltatm);
-#endif
-
-	/* Fill in the timeval struct */
-	*tvp = time;
-	tvp->tv_usec += ((deltatm << 8) / ifpga_sc->sc_clock_ticks_per_256us);
-
-	/* Make sure the micro seconds don't overflow. */
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_usec -= 1000000;
-		++tvp->tv_sec;
-	}
-
-	/* Make sure the time has advanced. */
-	if (tvp->tv_sec == oldtv.tv_sec &&
-	    tvp->tv_usec <= oldtv.tv_usec) {
-		tvp->tv_usec = oldtv.tv_usec + 1;
-		if (tvp->tv_usec >= 1000000) {
-			tvp->tv_usec -= 1000000;
-			++tvp->tv_sec;
-		}
-	}
+	do {
+		base = ifpga_base;
+		counter = getclock();
+	} while (base != ifpga_base);
 
-	oldtv = *tvp;
-	(void)splx(s);
+	return base - counter;
 }
 
 /*
Index: evbarm/iq80310/iq80310_timer.c
===================================================================
RCS file: /data/repo/netbsd/src/sys/arch/evbarm/iq80310/iq80310_timer.c,v
retrieving revision 1.20
diff -u -p -r1.20 iq80310_timer.c
--- evbarm/iq80310/iq80310_timer.c	19 Feb 2007 02:08:12 -0000	1.20
+++ evbarm/iq80310/iq80310_timer.c	8 Jan 2008 18:21:05 -0000
@@ -52,7 +52,9 @@ __KERNEL_RCSID(0, "$NetBSD: iq80310_time
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/atomic.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 
 #include <dev/clock_subr.h>
 
@@ -80,6 +82,21 @@ static void *clock_ih;
 
 static uint32_t counts_per_hz;
 
+static u_int	iq80310_get_timecount(struct timecounter *);
+
+static struct timecounter iq80310_timecounter = {
+	iq80310_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	0xffffffff,		/* counter_mask */
+	COUNTS_PER_SEC,		/* frequency */
+	"iq80310",		/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
+
+static volatile uint32_t iq80310_base;
+
 int	clockhandler(void *);
 
 static inline void
@@ -177,15 +194,6 @@ cpu_initclocks(void)
 		printf("Cannot get %d Hz clock; using 100 Hz\n", hz);
 		hz = 100;
 	}
-	tick = 1000000 / hz;	/* number of microseconds between interrupts */
-	tickfix = 1000000 - (hz * tick);
-	if (tickfix) {
-		int ftp;
-
-		ftp = min(ffs(tickfix), ffs(hz));
-		tickfix >>= (ftp - 1);
-		tickfixinterval = hz >> (ftp - 1);
-	}
 
 	/*
 	 * We only have one timer available; stathz and profhz are
@@ -221,6 +229,8 @@ cpu_initclocks(void)
 	timer_enable(TIMER_ENABLE_EN);
 
 	restore_interrupts(oldirqstate);
+
+	tc_init(&iq80310_timecounter);
 }
 
 /*
@@ -242,46 +252,17 @@ setstatclockrate(int newhz)
 	 */
 }
 
-/*
- * microtime:
- *
- *	Fill in the specified timeval struct with the current time
- *	accurate to the microsecond.
- */
-void
-microtime(struct timeval *tvp)
+static u_int
+iq80310_get_timecount(struct timecounter *tc)
 {
-	static struct timeval lasttv;
-	u_int oldirqstate;
-	uint32_t counts;
+	u_int oldirqstate, base, counter;
 
 	oldirqstate = disable_interrupts(I32_bit);
-
-	counts = timer_read();
-
-	/* Fill in the timeval struct. */
-	*tvp = time;
-	tvp->tv_usec += (counts / COUNTS_PER_USEC);
-
-	/* Make sure microseconds doesn't overflow. */
-	while (tvp->tv_usec >= 1000000) {
-		tvp->tv_usec -= 1000000;
-		tvp->tv_sec++;
-	}
-
-	/* Make sure the time has advanced. */
-	if (tvp->tv_sec == lasttv.tv_sec &&
-	    tvp->tv_usec <= lasttv.tv_usec) {
-		tvp->tv_usec = lasttv.tv_usec + 1;
-		if (tvp->tv_usec >= 1000000) {
-			tvp->tv_usec -= 1000000;
-			tvp->tv_sec++;
-		}
-	}
-
-	lasttv = *tvp;
-
+	base = iq80310_base;
+	counter = timer_read();
 	restore_interrupts(oldirqstate);
+
+	return base + counter;
 }
 
 /*
@@ -332,6 +313,8 @@ clockhandler(void *arg)
 	timer_disable(TIMER_ENABLE_INTEN);
 	timer_enable(TIMER_ENABLE_INTEN);
 
+	atomic_add_32(&iq80310_base, counts_per_hz);
+
 	hardclock(frame);
 
 	/*

--zYM0uCDKw75PZbzx--