summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2002-05-16 15:33:11 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2002-05-16 15:33:11 +0000
commit0067565f657d02c8a513c87a00d9fd2a43006a92 (patch)
tree0903cec7dc7a6c01ac610302a7c02a2cc199e45a /sys
parentd754e515aeddb505eb6d8e92aef1902f5759717a (diff)
fix for a timer latch bug on the cyrix mediagx and gxm cpus.
based on freebsd pr#6630, netbsd pr#8654, openbsd pr#1492 . does not affect other cpu models (cyrix or not). asked by markus@ and testing.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/i386/i386/machdep.c7
-rw-r--r--sys/arch/i386/isa/clock.c91
2 files changed, 80 insertions, 18 deletions
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 1c675f34d30..cdc59b4c026 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.204 2002/03/30 09:42:28 mickey Exp $ */
+/* $OpenBSD: machdep.c,v 1.205 2002/05/16 15:33:05 mickey Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -1041,7 +1041,6 @@ cyrix6x86_cpu_setup(cpu_device, model, step)
int model, step;
{
#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
- extern int cpu_feature;
switch (model) {
case -1: /* M1 w/o cpuid */
@@ -1061,10 +1060,6 @@ cyrix6x86_cpu_setup(cpu_device, model, step)
printf("%s: xchg bug workaround performed\n", cpu_device);
break; /* fallthrough? */
- case 4: /* GXm */
- /* Unset the TSC bit until calibrate_delay() gets fixed. */
- cpu_feature &= ~CPUID_TSC;
- break;
}
#endif
}
diff --git a/sys/arch/i386/isa/clock.c b/sys/arch/i386/isa/clock.c
index 489a9874593..e86cda7777c 100644
--- a/sys/arch/i386/isa/clock.c
+++ b/sys/arch/i386/isa/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.25 2002/03/14 01:26:33 millert Exp $ */
+/* $OpenBSD: clock.c,v 1.26 2002/05/16 15:33:10 mickey Exp $ */
/* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */
/*-
@@ -149,7 +149,7 @@ u_int mc146818_read(void *, u_int);
void mc146818_write(void *, u_int, u_int);
#if defined(I586_CPU) || defined(I686_CPU)
-int pentium_mhz;
+int pentium_mhz, clock_broken_latch;
#endif
#define SECMIN ((unsigned)60) /* seconds per minute */
@@ -227,6 +227,21 @@ initrtclock()
/* Correct rounding will buy us a better precision in timekeeping */
outb(IO_TIMER1, TIMER_DIV(hz) % 256);
outb(IO_TIMER1, TIMER_DIV(hz) / 256);
+
+#if defined(CPU_I586) || defined(CPU_I686)
+ {
+ extern int cpu_id;
+ switch (cpu_id) {
+ case 0x440: /* Cyrix MediaGX */
+ case 0x540: /* Cyrix GXm */
+ clock_broken_latch = 1;
+ break;
+ default:
+ clock_broken_latch = 0;
+ break;
+ }
+ }
+#endif
}
int
@@ -260,16 +275,68 @@ rtcintr(arg)
int
gettick()
{
- u_char lo, hi;
-
- /* Don't want someone screwing with the counter while we're here. */
- disable_intr();
- /* Select counter 0 and latch it. */
- outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
- lo = inb(TIMER_CNTR0);
- hi = inb(TIMER_CNTR0);
- enable_intr();
- return ((hi << 8) | lo);
+
+#if defined(I586_CPU) || defined(I686_CPU)
+ if (clock_broken_latch) {
+ int v1, v2, v3;
+ int w1, w2, w3;
+
+ 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;
+
+ enable_intr();
+
+ 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 + TIMER_DIV(hz);
+ w3 = v1 - v2;
+ if (w1 >= w2) {
+ if (w1 >= w3)
+ return (v1);
+ } else {
+ if (w2 >= w3)
+ return (v2);
+ }
+ return (v3);
+ } else
+#endif
+ {
+ u_char lo, hi;
+
+ disable_intr();
+ /* Select counter 0 and latch it. */
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+ lo = inb(TIMER_CNTR0);
+ hi = inb(TIMER_CNTR0);
+
+ enable_intr();
+ return ((hi << 8) | lo);
+ }
}
/*