summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>1999-05-18 21:24:16 +0000
committerdfr <dfr@FreeBSD.org>1999-05-18 21:24:16 +0000
commita72b1925b493f31c8edc968eafa58149bf734be6 (patch)
treeb86c9b1f17ab651fb49b1076138c2d13528f5ddc /sys
parentd446c6adb0181af0297e6e6c8fe8e92a770b0895 (diff)
downloadFreeBSD-src-a72b1925b493f31c8edc968eafa58149bf734be6.zip
FreeBSD-src-a72b1925b493f31c8edc968eafa58149bf734be6.tar.gz
Calibrate the processor cycle counter instead of believing what the
firmware says.
Diffstat (limited to 'sys')
-rw-r--r--sys/alpha/alpha/clock.c67
-rw-r--r--sys/alpha/alpha/clock_if.m7
-rw-r--r--sys/alpha/isa/mcclock_isa.c3
-rw-r--r--sys/dev/dec/mcclock.c28
-rw-r--r--sys/dev/dec/mcclockvar.h1
5 files changed, 99 insertions, 7 deletions
diff --git a/sys/alpha/alpha/clock.c b/sys/alpha/alpha/clock.c
index f2a8a53..0884881 100644
--- a/sys/alpha/alpha/clock.c
+++ b/sys/alpha/alpha/clock.c
@@ -1,4 +1,4 @@
-/* $Id: clock.c,v 1.7 1999/04/23 19:53:37 dt Exp $ */
+/* $Id: clock.c,v 1.8 1999/04/25 10:45:59 dt Exp $ */
/* $NetBSD: clock.c,v 1.20 1998/01/31 10:32:47 ross Exp $ */
/*
@@ -114,6 +114,7 @@ static u_int32_t max_cycles_per_tick;
static u_int32_t last_time;
static void handleclock(void* arg);
+static u_int32_t calibrate_clocks(u_int32_t firmware_freq);
void
clockattach(device_t dev)
@@ -125,6 +126,7 @@ clockattach(device_t dev)
if (clockdev)
panic("clockattach: multiple clocks");
clockdev = dev;
+ cycles_per_sec = calibrate_clocks(cycles_per_sec);
#ifdef EVCNT_COUNTERS
evcnt_attach(dev, "intr", &clock_intr_evcnt);
#endif
@@ -150,6 +152,8 @@ clockattach(device_t dev)
void
cpu_initclocks()
{
+ u_int32_t freq;
+
if (clockdev == NULL)
panic("cpu_initclocks: no clock attached");
@@ -175,11 +179,12 @@ cpu_initclocks()
* hardclock, which would then fall over because p->p_stats
* isn't set at that time.
*/
+ freq = cycles_per_sec;
last_time = alpha_rpcc();
- scaled_ticks_per_cycle = ((u_int64_t)hz << FIX_SHIFT) / cycles_per_sec;
- max_cycles_per_tick = 2*cycles_per_sec / hz;
+ scaled_ticks_per_cycle = ((u_int64_t)hz << FIX_SHIFT) / freq;
+ max_cycles_per_tick = 2*freq / hz;
- alpha_timecounter.tc_frequency = cycles_per_sec;
+ alpha_timecounter.tc_frequency = freq;
init_timecounter(&alpha_timecounter);
platform.clockintr = (void (*) __P((void *))) handleclock;
@@ -190,6 +195,60 @@ cpu_initclocks()
CLOCK_INIT(clockdev);
}
+static u_int32_t
+calibrate_clocks(u_int32_t firmware_freq)
+{
+ u_int32_t start_pcc, stop_pcc;
+ int sec, start_sec;
+
+ if (bootverbose)
+ printf("Calibrating clock(s) ... ");
+
+ /* Read the mc146818A seconds counter. */
+ if (CLOCK_GETSECS(clockdev, &sec))
+ goto fail;
+
+ /* Wait for the mC146818A seconds counter to change. */
+ start_sec = sec;
+ for (;;) {
+ if (CLOCK_GETSECS(clockdev, &sec))
+ goto fail;
+ if (sec != start_sec)
+ break;
+ }
+
+ /* Start keeping track of the PCC. */
+ start_pcc = alpha_rpcc();
+
+ /*
+ * Wait for the mc146818A seconds counter to change.
+ */
+ start_sec = sec;
+ for (;;) {
+ if (CLOCK_GETSECS(clockdev, &sec))
+ goto fail;
+ if (sec != start_sec)
+ break;
+ }
+
+ /*
+ * Read the PCC again to work out frequency.
+ */
+ stop_pcc = alpha_rpcc();
+
+ if (bootverbose) {
+ printf("PCC clock: %u Hz (firmware %u Hz)\n",
+ stop_pcc - start_pcc, firmware_freq);
+ }
+ return (stop_pcc - start_pcc);
+
+fail:
+ if (bootverbose)
+ printf("failed, using firmware default of %u Hz\n",
+ firmware_freq);
+ return (firmware_freq);
+}
+
static void
handleclock(void* arg)
{
diff --git a/sys/alpha/alpha/clock_if.m b/sys/alpha/alpha/clock_if.m
index 75cb78f..95a2e09 100644
--- a/sys/alpha/alpha/clock_if.m
+++ b/sys/alpha/alpha/clock_if.m
@@ -23,7 +23,7 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# $Id: clock_if.m,v 1.1 1998/06/14 13:52:33 dfr Exp $
+# $Id: clock_if.m,v 1.2 1998/11/08 18:35:51 nsouch Exp $
#
#include <machine/clockvar.h>
@@ -44,3 +44,8 @@ METHOD void set {
device_t dev;
struct clocktime *ct;
};
+
+METHOD int getsecs {
+ device_t dev;
+ int *secp;
+};
diff --git a/sys/alpha/isa/mcclock_isa.c b/sys/alpha/isa/mcclock_isa.c
index 3c6ca80..71b22a0 100644
--- a/sys/alpha/isa/mcclock_isa.c
+++ b/sys/alpha/isa/mcclock_isa.c
@@ -1,4 +1,4 @@
-/* $Id: mcclock_isa.c,v 1.3 1998/07/31 09:20:35 dfr Exp $ */
+/* $Id: mcclock_isa.c,v 1.4 1999/05/08 21:58:38 dfr Exp $ */
/* $NetBSD: mcclock_tlsb.c,v 1.8 1998/05/13 02:50:29 thorpej Exp $ */
/*
@@ -61,6 +61,7 @@ static device_method_t mcclock_isa_methods[] = {
DEVMETHOD(clock_init, mcclock_init),
DEVMETHOD(clock_get, mcclock_get),
DEVMETHOD(clock_set, mcclock_set),
+ DEVMETHOD(clock_getsecs, mcclock_getsecs),
{ 0, 0 }
};
diff --git a/sys/dev/dec/mcclock.c b/sys/dev/dec/mcclock.c
index 3aada8b..fc06f82 100644
--- a/sys/dev/dec/mcclock.c
+++ b/sys/dev/dec/mcclock.c
@@ -1,4 +1,4 @@
-/* $Id: mcclock.c,v 1.1 1998/06/10 10:56:23 dfr Exp $ */
+/* $Id: mcclock.c,v 1.2 1998/06/14 13:45:41 dfr Exp $ */
/* $NetBSD: mcclock.c,v 1.11 1998/04/19 07:50:25 jonathan Exp $ */
/*
@@ -111,3 +111,29 @@ mcclock_set(device_t dev, struct clocktime *ct)
MC146818_PUTTOD(dev, &regs);
splx(s);
}
+
+int
+mcclock_getsecs(device_t dev, int *secp)
+{
+ int timeout = 100000000;
+ int sec;
+ int s;
+
+ s = splclock();
+ for (;;) {
+ if (!(MCCLOCK_READ(dev, MC_REGA) & MC_REGA_UIP)) {
+ sec = MCCLOCK_READ(dev, MC_SEC);
+ break;
+ }
+ if (--timeout == 0)
+ goto fail;
+ }
+
+ splx(s);
+ *secp = sec;
+ return 0;
+
+ fail:
+ splx(s);
+ return ETIMEDOUT;
+}
diff --git a/sys/dev/dec/mcclockvar.h b/sys/dev/dec/mcclockvar.h
index 0c9f5df..a38f632 100644
--- a/sys/dev/dec/mcclockvar.h
+++ b/sys/dev/dec/mcclockvar.h
@@ -33,3 +33,4 @@ void mcclock_attach(device_t dev);
void mcclock_init(device_t);
void mcclock_get(device_t, time_t, struct clocktime *);
void mcclock_set(device_t, struct clocktime *);
+int mcclock_getsecs(device_t dev, int *secp);
OpenPOWER on IntegriCloud