Port-arm archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Timecounter patch for testing



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
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);
 
        /*


Home | Main Index | Thread Index | Old Index