Module Name:    src
Committed By:   jakllsch
Date:           Thu Jun  9 13:43:44 UTC 2011

Modified Files:
        src/sys/arch/arm/marvell: mvsoctmr.c

Log Message:
Rework mvsoctmr(4), improving timekeeping accuracy

Inconveniently the Marvell hardware only counts down.
We need to reverse this for timecounter(9), and we need
to do it in a very lightweight way.

 - use Timer0 for the clock interrupt
 - use Timer1 for timecounter(9) and delay(9)
 - drop statclock due to lack of timers (does anyone actually use this?)


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/marvell/mvsoctmr.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/marvell/mvsoctmr.c
diff -u src/sys/arch/arm/marvell/mvsoctmr.c:1.1 src/sys/arch/arm/marvell/mvsoctmr.c:1.2
--- src/sys/arch/arm/marvell/mvsoctmr.c:1.1	Sun Oct  3 05:49:24 2010
+++ src/sys/arch/arm/marvell/mvsoctmr.c	Thu Jun  9 13:43:44 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsoctmr.c,v 1.1 2010/10/03 05:49:24 kiyohara Exp $	*/
+/*	$NetBSD: mvsoctmr.c,v 1.2 2011/06/09 13:43:44 jakllsch Exp $	*/
 /*
  * Copyright (c) 2007, 2008 KIYOHARA Takashi
  * All rights reserved.
@@ -25,7 +25,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mvsoctmr.c,v 1.1 2010/10/03 05:49:24 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsoctmr.c,v 1.2 2011/06/09 13:43:44 jakllsch Exp $");
 
 #include <sys/param.h>
 #include <sys/atomic.h>
@@ -60,18 +60,12 @@
 static void mvsoctmr_attach(device_t, device_t, void *);
 
 static int clockhandler(void *);
-static int statclockhandler(void *);
 
 static u_int mvsoctmr_get_timecount(struct timecounter *);
 
 static void mvsoctmr_cntl(struct mvsoctmr_softc *, int, u_int, int, int);
 
-#ifndef STATHZ
-#define STATHZ	64
-#endif
-
 static struct mvsoctmr_softc *mvsoctmr_sc;
-static uint32_t clock_ticks, statclock_ticks;
 static struct timecounter mvsoctmr_timecounter = {
 	mvsoctmr_get_timecount,	/* get_timecount */
 	0,			/* no poll_pps */
@@ -82,7 +76,6 @@
 	NULL,			/* prev */
 	NULL,			/* next */
 };
-static volatile uint32_t mvsoctmr_base;
 
 CFATTACH_DECL_NEW(mvsoctmr, sizeof(struct mvsoctmr_softc),
     mvsoctmr_match, mvsoctmr_attach, NULL, NULL);
@@ -121,6 +114,9 @@
 	if (bus_space_subregion(mva->mva_iot, mva->mva_ioh,
 	    mva->mva_offset, mva->mva_size, &sc->sc_ioh))
 		panic("%s: Cannot map registers", device_xname(self));
+
+	mvsoctmr_timecounter.tc_name = device_xname(self);
+	mvsoctmr_cntl(sc, MVSOCTMR_TIMER1, 0xffffffff, 1, 1);
 }
 
 /*
@@ -133,48 +129,20 @@
 {
 	struct clockframe *frame = arg;
 
-	atomic_add_32(&mvsoctmr_base, clock_ticks);
-
 	hardclock(frame);
 
 	return 1;
 }
 
 /*
- * statclockhandler:
- *
- *	Handle the statclock interrupt.
- */
-static int
-statclockhandler(void *arg)
-{
-	struct clockframe *frame = arg;
-
-	statclock(frame);
-
-	return 1;
-}
-
-
-/*
  * setstatclockrate:
  *
  *	Set the rate of the statistics clock.
- *
- *	We assume that hz is either stathz or profhz, and that neither
- *	will change after being set by cpu_initclocks().  We could
- *	recalculate the intervals here, but that would be a pain.
  */
 /* ARGSUSED */
 void
 setstatclockrate(int newhz)
 {
-	struct mvsoctmr_softc *sc = mvsoctmr_sc;
-	const int en = 1, autoen = 1;
-
-	statclock_ticks = mvTclk / newhz;
-
-	mvsoctmr_cntl(sc, MVSOCTMR_TIMER1, statclock_ticks, en, autoen);
 }
 
 /*
@@ -188,32 +156,26 @@
 	struct mvsoctmr_softc *sc;
 	void *clock_ih;
 	const int en = 1, autoen = 1;
+	uint32_t timer0_tval;
 
 	sc = mvsoctmr_sc;
 	if (sc == NULL)
 		panic("cpu_initclocks: mvsoctmr not found");
 
-	stathz = profhz = STATHZ;
+	mvsoctmr_timecounter.tc_priv = sc;
 	mvsoctmr_timecounter.tc_frequency = mvTclk;
-	clock_ticks = mvTclk / hz;
 
-	mvsoctmr_cntl(sc, MVSOCTMR_TIMER0, clock_ticks, en, autoen);
+	timer0_tval = (mvTclk * 2) / (u_long) hz;
+	timer0_tval = (timer0_tval / 2) + (timer0_tval & 1);
+
+	mvsoctmr_cntl(sc, MVSOCTMR_TIMER0, timer0_tval, en, autoen);
+	mvsoctmr_cntl(sc, MVSOCTMR_TIMER1, 0xffffffff, en, autoen);
 
 	clock_ih = mvsoc_bridge_intr_establish(MVSOC_MLMB_MLMBI_CPUTIMER0INTREQ,
 	    IPL_CLOCK, clockhandler, NULL);
 	if (clock_ih == NULL)
 		panic("cpu_initclocks: unable to register timer interrupt");
 
-	if (stathz) {
-		setstatclockrate(stathz);
-		clock_ih = mvsoc_bridge_intr_establish(
-		    MVSOC_MLMB_MLMBI_CPUTIMER1INTREQ, IPL_HIGH,
-		    statclockhandler, NULL);
-		if (clock_ih == NULL)
-			panic("cpu_initclocks:"
-			    " unable to register statclock timer interrupt");
-	}
-
 	tc_init(&mvsoctmr_timecounter);
 }
 
@@ -237,7 +199,7 @@
 	 * counted.
 	 */
 	initial_tick = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
-	    MVSOCTMR_TIMER(MVSOCTMR_TIMER0));
+	    MVSOCTMR_TIMER(MVSOCTMR_TIMER1));
 
 	if (n <= UINT_MAX / mvTclk) {
 		/*
@@ -255,9 +217,9 @@
 
 	while (remaining > 0) {
 		cur_tick = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
-		    MVSOCTMR_TIMER(MVSOCTMR_TIMER0));
+		    MVSOCTMR_TIMER(MVSOCTMR_TIMER1));
 		if (cur_tick > initial_tick)
-			remaining -= clock_ticks - cur_tick + initial_tick;
+			remaining -= 0xffffffff - cur_tick + initial_tick;
 		else
 			remaining -= (initial_tick - cur_tick);
 		initial_tick = cur_tick;
@@ -267,20 +229,12 @@
 static u_int
 mvsoctmr_get_timecount(struct timecounter *tc)
 {
-	struct mvsoctmr_softc *sc = mvsoctmr_sc;
-	uint32_t counter, base;
-	u_int intrstat;
-
-	intrstat = disable_interrupts(I32_bit);
-	base = mvsoctmr_base;
-	counter = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
-	    MVSOCTMR_TIMER(MVSOCTMR_TIMER0));
-	restore_interrupts(intrstat);
+	struct mvsoctmr_softc *sc = tc->tc_priv;
 
-	return base - counter;
+	return 0xffffffff - bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+	    MVSOCTMR_TIMER(MVSOCTMR_TIMER1));
 }
 
-
 static void
 mvsoctmr_cntl(struct mvsoctmr_softc *sc, int num, u_int ticks, int en,
 	      int autoen)

Reply via email to