Subject: footbridge support for timecounter
To: None <port-cats@NetBSD.org, port-netwinder@NetBSD.org,>
From: Garrett D'Amore <garrett_damore@tadpole.com>
List: port-cats
Date: 09/10/2006 22:41:05
This is a multi-part message in MIME format.
--------------070400000505030402010803
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
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
--------------070400000505030402010803
Content-Type: text/x-patch;
name="footbridge.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="footbridge.diff"
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() */
--------------070400000505030402010803--