Port-cats archive

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

footbridge support for timecounter



The following patch is my attempt at enabling timecounters for
footbridge based ARM32 systems.  As far as I can see, this is only cats
and netwinder.

Thus I've dispensed with all the checks for __HAVE_TIMECOUNTER and just
assumed it for both ports.

I've changed the semantics of the delay timer (previously used for
delay()) slightly -- it now is let run free, rather than being
periodic.  This works better for timecounters.

I have _not_ tested this patch, although it does compile.  If someone
could verify it, I would be grateful, as it converts not one but _two_
ports. :-)

Thanks.

-- 
Garrett D'Amore, Principal Software Engineer
Tadpole Computer / Computing Technologies Division,
General Dynamics C4 Systems
http://www.tadpolecomputer.com/
Phone: 951 325-2134  Fax: 951 325-2191

Index: sys/arch/netwinder/include/types.h
===================================================================
RCS file: /cvsroot/src/sys/arch/netwinder/include/types.h,v
retrieving revision 1.5
diff -d -p -u -r1.5 types.h
--- sys/arch/netwinder/include/types.h  3 Sep 2006 13:51:23 -0000       1.5
+++ sys/arch/netwinder/include/types.h  11 Sep 2006 05:33:21 -0000
@@ -7,5 +7,6 @@
 
 #define __HAVE_GENERIC_SOFT_INTERRUPTS
 #define __HAVE_DEVICE_REGISTER
+#define        __HAVE_TIMECOUNTER
 
 #endif
Index: sys/arch/cats/include/types.h
===================================================================
RCS file: /cvsroot/src/sys/arch/cats/include/types.h,v
retrieving revision 1.6
diff -d -p -u -r1.6 types.h
--- sys/arch/cats/include/types.h       3 Sep 2006 13:51:23 -0000       1.6
+++ sys/arch/cats/include/types.h       11 Sep 2006 05:33:21 -0000
@@ -6,5 +6,6 @@
 #include <arm/arm32/types.h>
 #define __HAVE_GENERIC_SOFT_INTERRUPTS
 #define __HAVE_DEVICE_REGISTER
+#define        __HAVE_TIMECOUNTER
 
 #endif
Index: sys/arch/arm/footbridge/footbridge_clock.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/footbridge/footbridge_clock.c,v
retrieving revision 1.21
diff -d -p -u -r1.21 footbridge_clock.c
--- sys/arch/arm/footbridge/footbridge_clock.c  17 Apr 2006 00:03:17 -0000      
1.21
+++ sys/arch/arm/footbridge/footbridge_clock.c  11 Sep 2006 05:33:21 -0000
@@ -44,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: footbridge_c
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/time.h>
+#include <sys/timetc.h>
 #include <sys/device.h>
 
 #include <machine/intr.h>
@@ -57,9 +58,9 @@ __KERNEL_RCSID(0, "$NetBSD: footbridge_c
 extern struct footbridge_softc *clock_sc;
 extern u_int dc21285_fclk;
 
-int clockhandler __P((void *));
-int statclockhandler __P((void *));
-static int load_timer __P((int, int));
+int clockhandler(void *);
+int statclockhandler (void *);
+static int load_timer(int, int);
 
 /*
  * Statistics clock variance, in usec.  Variance must be a
@@ -74,9 +75,11 @@ int statmin;                 /* minimum stat clock cou
 int statcountperusec;          /* number of ticks per usec at current stathz */
 int statprev;                  /* last value of we set statclock to */
 
+void footbridge_tc_init(void);
+
 #if 0
-static int clockmatch  __P((struct device *parent, struct cfdata *cf, void 
*aux));
-static void clockattach        __P((struct device *parent, struct device 
*self, void *aux));
+static int clockmatch(struct device *parent, struct cfdata *cf, void *aux);
+static void clockattach(struct device *parent, struct device *self, void *aux);
 
 CFATTACH_DECL(footbridge_clock, sizeof(struct clock_softc),
     clockmatch, clockattach, NULL, NULL);
@@ -88,16 +91,13 @@ CFATTACH_DECL(footbridge_clock, sizeof(s
  */ 
  
 static int
-clockmatch(parent, cf, aux)
-       struct device *parent;
-       struct cfdata *cf;
-       void *aux;
+clockmatch(struct device *parent, struct cfdata *cf, void *aux)
 {
        union footbridge_attach_args *fba = aux;
 
        if (strcmp(fba->fba_ca.ca_name, "clk") == 0)
-               return(1);
-       return(0);
+               return 1;
+       return 0;
 }
 
 
@@ -107,10 +107,7 @@ clockmatch(parent, cf, aux)
  */
   
 static void
-clockattach(parent, self, aux)
-       struct device *parent;
-       struct device *self;
-       void *aux;
+clockattach(struct device *parent, struct device *self, void *aux)
 {
        struct clock_softc *sc = (struct clock_softc *)self;
        union footbridge_attach_args *fba = aux;
@@ -134,14 +131,13 @@ clockattach(parent, self, aux)
  */
 
 int
-clockhandler(aframe)
-       void *aframe;
+clockhandler(void *aframe)
 {
        struct clockframe *frame = aframe;
        bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
            TIMER_1_CLEAR, 0);
        hardclock(frame);
-       return(0);      /* Pass the interrupt on down the chain */
+       return 0;       /* Pass the interrupt on down the chain */
 }
 
 /*
@@ -152,8 +148,7 @@ clockhandler(aframe)
  */
  
 int
-statclockhandler(aframe)
-       void *aframe;
+statclockhandler(void *aframe)
 {
        struct clockframe *frame = aframe;
        int newint, r;
@@ -201,13 +196,11 @@ statclockhandler(aframe)
                 */
                statclock(frame);
 
-       return(0);      /* Pass the interrupt on down the chain */
+       return 0;       /* Pass the interrupt on down the chain */
 }
 
 static int
-load_timer(base, herz)
-       int base;
-       int herz;
+load_timer(int base, int herz)
 {
        unsigned int timer_count;
        int control;
@@ -229,7 +222,7 @@ load_timer(base, herz)
            base + TIMER_CONTROL, control);
        bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
            base + TIMER_CLEAR, 0);
-       return(timer_count);
+       return timer_count;
 }
 
 /*
@@ -239,8 +232,7 @@ load_timer(base, herz)
  */
 
 void
-setstatclockrate(herz)
-       int herz;
+setstatclockrate(int herz)
 {
        int statint;
        int countpersecond;
@@ -273,7 +265,7 @@ setstatclockrate(herz)
  */
  
 void
-cpu_initclocks()
+cpu_initclocks(void)
 {
        /* stathz and profhz should be set to something, we have the timer */
        if (stathz == 0)
@@ -311,62 +303,29 @@ cpu_initclocks()
                        panic("%s: Cannot install timer 2 interrupt handler",
                            clock_sc->sc_dev.dv_xname);
        }
-}
 
+       footbridge_tc_init();
+}
 
-/*
- * void microtime(struct timeval *tvp)
- *
- * Fill in the specified timeval struct with the current time
- * accurate to the microsecond.
- */
+static uint32_t
+fclk_get_count(struct timecounter *tc)
+{
+       return (TIMER_MAX_VAL -
+           bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+           TIMER_3_VALUE));
+}
 
 void
-microtime(tvp)
-       struct timeval *tvp;
+footbridge_tc_init(void)
 {
-       int s;
-       int tm;
-       int deltatm;
-       static struct timeval oldtv;
-
-       if (clock_sc == NULL || clock_sc->sc_clock_count == 0)
-               return;
-
-       s = splhigh();
-
-       tm = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
-           TIMER_1_VALUE);
-
-       deltatm = clock_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) / clock_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;
-               }
-       }
-
-       oldtv = *tvp;
-       (void)splx(s);          
+       struct timecounter fb_tc = {
+               .tc_get_timecount = fclk_get_count,
+               .tc_counter_mask = TIMER_MAX_VAL,
+               .tc_name = "dc21285_fclk",
+               .tc_quality = 100
+       };
+       fb_tc.tc_frequency = dc21285_fclk;
+       tc_init(&fb_tc);
 }
 
 /*
@@ -374,96 +333,75 @@ microtime(tvp)
  * rely on an estimated loop, however footbridge is attached very early on.
  */
 
-static int delay_clock_count = 0;
 static int delay_count_per_usec = 0;
 
 void
 calibrate_delay(void)
 {
-     delay_clock_count = load_timer(TIMER_3_BASE, 100);
-     delay_count_per_usec = delay_clock_count/10000;
-#ifdef VERBOSE_DELAY_CALIBRATION
-     printf("delay calibration: delay_cc = %d, delay_c/us=%d\n",
-                    delay_clock_count, delay_count_per_usec);
-     
-     printf("0..");
-     delay(1000000);
-     printf("1..");
-     delay(1000000);
-     printf("2..");
-     delay(1000000);
-     printf("3..");
-     delay(1000000);
-     printf("4..");
-      delay(1000000);
-     printf("5..");
-      delay(1000000);
-     printf("6..");
-      delay(1000000);
-     printf("7..");
-      delay(1000000);
-     printf("8..");
-      delay(1000000);
-     printf("9..");
-      delay(1000000);
-     printf("10\n");
-#endif
+       /*
+        * For all current footbridge hardware, the fclk runs at a
+        * rate that is sufficiently slow enough that we don't need to
+        * use a prescaler.  A prescaler would be needed if the fclk
+        * could wrap within 2 hardclock periods (2 * HZ).  With
+        * normal values of HZ (100 and higher), this is unlikely to
+        * ever happen.
+        *
+        * We let TIMER 3 just run free.
+        */
+       bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+           TIMER_3_BASE + TIMER_CONTROL, TIMER_ENABLE);
+       delay_count_per_usec = dc21285_fclk / 1000000;
+       if (dc21285_fclk % 1000000)
+               delay_count_per_usec += 1;
 }
 
-int delaycount = 25000;
-
 void
-delay(n)
-       u_int n;
+delay(unsigned n)
 {
-       volatile u_int i;
        uint32_t cur, last, delta, usecs;
 
-       if (n == 0) return;
+       if (n == 0)
+               return;
 
        /* 
         * not calibrated the timer yet, so try to live with this horrible
         * loop!
+        *
+        * Note: a much better solution might be to have the timers
+        * get get calibrated out of mach_init.  Of course, the
+        * clock_sc needs to be set up, so we can read/write the clock
+        * registers.
         */
-       if (delay_clock_count == 0)
+       if (!delay_count_per_usec)
        {
-           while (n-- > 0) {
-               for (i = delaycount; --i;);
-           }
-           return;     
+               int delaycount = 25000;
+               volatile int i;
+
+               while (n-- > 0) {
+                       for (i = delaycount; --i;);
+               }
+               return; 
        }
 
-       /* 
-        * read the current value (do not reset it as delay is reentrant)
-        */
        last = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+           TIMER_3_VALUE);
+       delta = usecs = 0;
+       
+       while (n > usecs) {
+               cur = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
                    TIMER_3_VALUE);
-        
-       delta = 0;
+               if (last < cur)
+                       /* timer has wrapped */
+                       delta += ((TIMER_MAX_VAL - cur) + last);
+               else
+                       delta += (last - cur);
 
-       usecs = n * delay_count_per_usec;
+               last = cur;
 
-       while (usecs > delta)
-       {
-           cur = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
-                   TIMER_3_VALUE);
-           if (last < cur)
-               /* timer has wrapped */
-               delta += ((delay_clock_count - cur) + last);
-           else
-               delta += (last - cur);
-           
-           if (cur == 0)
-           {
-               /*
-                * reset the timer, note that if something blocks us for more
-                * than 1/100s we may delay for too long, but I believe that
-                * is fairly unlikely.
-                */
-               bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
-                       TIMER_3_CLEAR, 0);
-           }
-           last = cur;
+               while (delta >= delay_count_per_usec) {
+                       delta -= delay_count_per_usec;
+                       usecs++;
+               }
        }
 }
 
Index: sys/arch/arm/footbridge/todclock.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/footbridge/todclock.c,v
retrieving revision 1.9
diff -d -p -u -r1.9 todclock.c
--- sys/arch/arm/footbridge/todclock.c  24 Dec 2005 20:06:52 -0000      1.9
+++ sys/arch/arm/footbridge/todclock.c  11 Sep 2006 05:33:21 -0000
@@ -198,7 +198,7 @@ resettodr()
        if (todclock_sc->sc_rtc_write == NULL)
                return;
 
-       sec = time.tv_sec;
+       sec = time_second;
        sec -= rtc_offset * 60;
        year = (sec / SECPER4YEARS) * 4;
        sec %= SECPER4YEARS;
@@ -269,8 +269,7 @@ inittodr(base)
         */
 
        /* Use the suggested time as a fall back */
-       time.tv_sec = base;
-       time.tv_usec = 0;
+       time_second = base;
 
        /* Can we read an RTC ? */
        if (todclock_sc != NULL && todclock_sc->sc_rtc_read) {
@@ -302,8 +301,7 @@ inittodr(base)
 
        n += rtc_offset * 60;
 
-       time.tv_sec = n;
-       time.tv_usec = 0;
+       time_second = n;
 
        /* timeset is used to ensure the time is valid before a resettodr() */
 


Home | Main Index | Thread Index | Old Index