Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/i386/isa Take care of National Geode (Cyrix MediaGX...
details: https://anonhg.NetBSD.org/src/rev/d8a77a7f1b15
branches: trunk
changeset: 481607:d8a77a7f1b15
user: minoura <minoura%NetBSD.org@localhost>
date: Wed Feb 02 15:26:27 2000 +0000
description:
Take care of National Geode (Cyrix MediaGX) built-in clock module bug.
Patch supplied by INOUE Yoshinari <pf5y-inue%asahi-net.or.jp@localhost>, kern/8654.
diffstat:
sys/arch/i386/isa/clock.c | 140 +++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 139 insertions(+), 1 deletions(-)
diffs (201 lines):
diff -r f7f96deca387 -r d8a77a7f1b15 sys/arch/i386/isa/clock.c
--- a/sys/arch/i386/isa/clock.c Wed Feb 02 15:12:10 2000 +0000
+++ b/sys/arch/i386/isa/clock.c Wed Feb 02 15:26:27 2000 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: clock.c,v 1.62 1999/11/06 01:14:01 enami Exp $ */
+/* $NetBSD: clock.c,v 1.63 2000/02/02 15:26:27 minoura Exp $ */
/*-
* Copyright (c) 1993, 1994 Charles M. Hannum.
@@ -85,6 +85,9 @@
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/* #define CLOCKDEBUG */
+/* #define CLOCK_PARANOIA */
+
/*
* Primitive clock interrupt routines.
*/
@@ -110,6 +113,13 @@
#if (NPCPPI > 0)
#include <dev/isa/pcppivar.h>
+#ifdef CLOCKDEBUG
+int clock_debug = 0;
+#define DPRINTF(arg) if (clock_debug) printf arg
+#else
+#define DPRINTF(arg)
+#endif
+
int sysbeepmatch __P((struct device *, struct cfdata *, void *));
void sysbeepattach __P((struct device *, struct device *, void *));
@@ -131,6 +141,9 @@
int bcdtobin __P((int));
int bintobcd __P((int));
+static void check_clock_bug __P((void));
+static inline int gettick_broken_latch __P((void));
+
__inline u_int mc146818_read __P((void *, u_int));
__inline void mc146818_write __P((void *, u_int, u_int));
@@ -156,6 +169,105 @@
}
static u_long rtclock_tval;
+static int clock_broken_latch = 0;
+
+#ifdef CLOCK_PARANOIA
+static int ticks[6];
+#endif
+
+/*
+ * i8254 latch check routine:
+ * National Geode (formerly Cyrix MediaGX) has a sirious bug in
+ * its built-in i8254-compatible clock module.
+ * Set the variable 'clock_broken_latch' to indicate it.
+ * XXX check only cpu_id
+ */
+static void
+check_clock_bug()
+{
+ extern int cpu_id;
+
+ switch (cpu_id) {
+ case 0x440: /* Cyrix MediaGX */
+ case 0x540: /* GXm */
+ clock_broken_latch = 1;
+ break;
+ default:
+ clock_broken_latch = 0;
+ break;
+ }
+}
+
+int
+gettick_broken_latch()
+{
+ u_long ef;
+ int v1, v2, v3;
+ int w1, w2, w3;
+
+ /* Don't want someone screwing with the counter
+ while we're here. */
+ ef = read_eflags();
+ disable_intr();
+
+ v1 = inb(TIMER_CNTR0);
+ v1 |= inb(TIMER_CNTR0) << 8;
+ v2 = inb(TIMER_CNTR0);
+ v2 |= inb(TIMER_CNTR0) << 8;
+ v3 = inb(TIMER_CNTR0);
+ v3 |= inb(TIMER_CNTR0) << 8;
+
+ write_eflags(ef);
+
+#ifdef CLOCK_PARANOIA
+ if (clock_debug) {
+ ticks[0] = ticks[3];
+ ticks[1] = ticks[4];
+ ticks[2] = ticks[5];
+ ticks[3] = v1;
+ ticks[4] = v2;
+ ticks[5] = v3;
+ }
+#endif
+
+ if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200)
+ return (v2);
+
+#define _swap_val(a, b) do { \
+ int c = a; \
+ a = b; \
+ b = c; \
+} while (0)
+
+ /*
+ * sort v1 v2 v3
+ */
+ if (v1 < v2)
+ _swap_val(v1, v2);
+ if (v2 < v3)
+ _swap_val(v2, v3);
+ if (v1 < v2)
+ _swap_val(v1, v2);
+
+ /*
+ * compute the middle value
+ */
+
+ if (v1 - v3 < 0x200)
+ return (v2);
+
+ w1 = v2 - v3;
+ w2 = v3 - v1 + rtclock_tval;
+ w3 = v1 - v2;
+ if (w1 >= w2) {
+ if (w1 >= w3)
+ return (v1);
+ } else {
+ if (w2 >= w3)
+ return (v2);
+ }
+ return (v3);
+}
/* minimal initialization, enough for delay() */
void
@@ -179,6 +291,8 @@
outb(IO_TIMER1, tval / 256);
rtclock_tval = tval;
+
+ check_clock_bug();
}
/*
@@ -297,6 +411,9 @@
u_long ef;
u_char lo, hi;
+ if (clock_broken_latch)
+ return (gettick_broken_latch());
+
/* Don't want someone screwing with the counter while we're here. */
ef = read_eflags();
disable_intr();
@@ -369,11 +486,32 @@
}
while (n > 0) {
+#ifdef CLOCK_PARANOIA
+ int delta;
+ tick = gettick();
+ if (tick > otick)
+ delta = rtclock_tval - (tick - otick);
+ else
+ delta = otick - tick;
+ if (delta < 0 || delta >= rtclock_tval / 2) {
+ DPRINTF(("delay: ignore ticks %.4x-%.4x",
+ otick, tick));
+ if (clock_broken_latch) {
+ DPRINTF((" (%.4x %.4x %.4x %.4x %.4x %.4x)\n",
+ ticks[0], ticks[1], ticks[2],
+ ticks[3], ticks[4], ticks[5]));
+ } else {
+ DPRINTF(("\n"));
+ }
+ } else
+ n -= delta;
+#else
tick = gettick();
if (tick > otick)
n -= rtclock_tval - (tick - otick);
else
n -= otick - tick;
+#endif
otick = tick;
}
}
Home |
Main Index |
Thread Index |
Old Index