summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2007-04-29 17:35:28 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2007-04-29 17:35:28 +0000
commit1b286df3ed9277fd99eeec31bf110a7a98d330b6 (patch)
tree0139245290c7ed4d647c6eddfb27290f58690a89
parent9cd34d823384c1dac0abdfd009da6d8be68e43e5 (diff)
The cpu clock frequency we get from ARCBIOS may be off by something in the
order of 1%. So calibrate the CP0 timecounter frequency using the TOD clock if we have one. "looks like good stuff" deraadt@, also tested by jsg@
-rw-r--r--sys/arch/mips64/mips64/clock.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/sys/arch/mips64/mips64/clock.c b/sys/arch/mips64/mips64/clock.c
index 0bf8a2d63a0..bb41e9f92c1 100644
--- a/sys/arch/mips64/mips64/clock.c
+++ b/sys/arch/mips64/mips64/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.17 2006/06/19 15:13:35 deraadt Exp $ */
+/* $OpenBSD: clock.c,v 1.18 2007/04/29 17:35:27 kettenis Exp $ */
/*
* Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -252,6 +252,9 @@ void
cpu_initclocks()
{
struct clock_softc *sc = (struct clock_softc *)clock_cd.cd_devs[0];
+ struct tod_time ct;
+ u_int first_cp0, second_cp0, cycles_per_sec;
+ int first_sec;
hz = sc->sc_clock.clk_hz;
stathz = sc->sc_clock.clk_stathz;
@@ -263,6 +266,29 @@ cpu_initclocks()
if (sc->sc_clock.clk_init != NULL)
(*sc->sc_clock.clk_init)(sc);
+ /*
+ * Calibrate the cycle counter frequency.
+ */
+ if (sc->sc_clock.clk_get != NULL) {
+ (*sc->sc_clock.clk_get)(sc, 0, &ct);
+ first_sec = ct.sec;
+
+ /* Let the clock tick one second. */
+ do {
+ first_cp0 = cp0_get_count();
+ (*sc->sc_clock.clk_get)(sc, 0, &ct);
+ } while (ct.sec == first_sec);
+ first_sec = ct.sec;
+ /* Let the clock tick one more second. */
+ do {
+ second_cp0 = cp0_get_count();
+ (*sc->sc_clock.clk_get)(sc, 0, &ct);
+ } while (ct.sec == first_sec);
+
+ cycles_per_sec = second_cp0 - first_cp0;
+ sys_config.cpu[0].clock = cycles_per_sec * 2;
+ }
+
tick = 1000000 / hz; /* number of micro-seconds between interrupts */
tickadj = 240000 / (60 * hz); /* can adjust 240ms in 60s */