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