Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 14 May 1998 01:42:46 -0400 (EDT)
From:      cjohnson@netgsi.com
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/6630: Fix for Cyrix I8254 bug
Message-ID:  <199805140542.BAA12770@neunacht.netgsi.com>

next in thread | raw e-mail | index | archive | help

>Number:         6630
>Category:       kern
>Synopsis:       Fix for Cyrix I8254 bug
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed May 13 22:40:01 PDT 1998
>Last-Modified:
>Originator:     Christopher T. Johnson
>Organization:
NetGSi, Inc
>Release:        FreeBSD 3.0-CURRENT i386
>Environment:
	Any Cyrix GX(m) cpu using the 5510 or 5520 support chipset.

>Description:
	The Cyrix 5510 and 5520 chipset has a serious flaw in the 
	I8254 programmable interupt timer.  When the I8254 PIT is
	sent a "LATCH" command, it is suppose to copy the current counter
	into a 16 bit latch counter as an atomic action.  Instead, either
	the latch fails to take place, or there is no latch register.

	When the standard clock calibration loops run, the i8254 is miss
	tracked giving bogus timings.  In addition, the TSC is callibrated
	against the i8254 using the same busted logic giving such wonderful
	readings as a Pentium MMX running at 180 Mhz being detected as
	a 9Mhz Pentium.  (poor english sorry)

	In addition to these simple things going astray, the callout() routines
	die because they are based on the calibrations of the TSC or I8254.

	The biggest problem is that the DELAY() routine dies.  This causes
	things like APM to panic as well as many other kernel drivers that
	need sub second timing.

>How-To-Repeat:

	find a Compaq Presario 1215 and boot FreeBSD.  Type date a few times
	and see what the time warp is like.

>Fix:
Index: LINT
===================================================================
RCS file: /usr/cvsroot/src/sys/i386/conf/LINT,v
retrieving revision 1.429
diff -u -r1.429 LINT
--- LINT	1998/04/29 17:09:41	1.429
+++ LINT	1998/05/14 05:09:57
@@ -136,6 +136,11 @@
 # of Cyrix 6x86 and 6x86MX CPUs.  If this option is not set and
 # FAILESAFE is defined, NO_LOCK bit of CCR1 is cleared.  (NOTE 3)
 #
+# CPU_CYRIX_NO_I8254_LATCH enables a patch to deal with the I8254
+# programable interupt timer failing to latch in a number of cyrix
+# chipsets.  This can be seen by run away Time of Day clocks and 
+# panics when trying to do sub second time keeping.
+#
 # CPU_DISABLE_5X86_LSSER disables load store serialize (i.e. enables
 # reorder).  This option should not be used if you use memory mapped
 # I/O device(s). 
@@ -196,6 +201,7 @@
 options		"CPU_SUSP_HLT"
 options		"CYRIX_CACHE_WORKS"
 options		"CYRIX_CACHE_REALLY_WORKS"
+options		"CPU_CYRIX_NO_I8254_LATCH"
 #options	"NO_F00F_HACK"
 
 #
Index: options.i386
===================================================================
RCS file: /usr/cvsroot/src/sys/i386/conf/options.i386,v
retrieving revision 1.77
diff -u -r1.77 options.i386
--- options.i386	1998/04/18 04:58:01	1.77
+++ options.i386	1998/05/14 05:12:18
@@ -68,6 +68,7 @@
 CPU_UPGRADE_HW_CACHE		opt_cpu.h
 CYRIX_CACHE_WORKS		opt_cpu.h
 CYRIX_CACHE_REALLY_WORKS	opt_cpu.h
+CPU_CYRIX_NO_I8254_LATCH	opt_clock.h
 
 # The CPU type affects the endian conversion functions all over the kernel.
 I386_CPU		opt_global.h
Index: clock.c
===================================================================
RCS file: /usr/cvsroot/src/sys/i386/isa/clock.c,v
retrieving revision 1.119
diff -u -r1.119 clock.c
--- clock.c	1998/04/05 01:04:48	1.119
+++ clock.c	1998/05/14 05:20:02
@@ -402,7 +402,9 @@
 {
 	u_long ef;
 	int high, low;
-
+#if CPU_CYRIX_NO_I8254_LATCH
+	int ret1, ret2;
+#endif
 	ef = read_eflags();
 	disable_intr();
 
@@ -411,10 +413,21 @@
 
 	low = inb(TIMER_CNTR0);
 	high = inb(TIMER_CNTR0);
+#if CPU_CYRIX_NO_I8254_LATCH
+	ret1 = (high << 8) | low;
 
+	outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+	low = inb(TIMER_CNTR0);
+	high= inb(TIMER_CNTR0);
+	ret2 = (high <<8) | low;
+#endif
 	CLOCK_UNLOCK();
 	write_eflags(ef);
+#if CPU_CYRIX_NO_I8254_LATCH
+	return (ret1 > ret2 ? ret1 : ret2);
+#else
 	return ((high << 8) | low);
+#fi
 }
 
 /*


>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199805140542.BAA12770>