Hello,
Cyrix MediaGX/NSC Geode is a NatSemi's i386 CPU.
It's old integrated southbrige companion chip cs5510/5520 has a PIT latch bug.
this breaks TSC syncronization, but I found work around about this.
After I posted lkml about this bug in Mar. 2002, I have tried to make this smart.
In past post, I say the dual calling of 'calibrate_tsc()' make things good.
but now I found the simple solution.
This PIT need the delay after 1st counter reset.
in timer_tsc.c,
outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
is changed to
outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
outb_p(CALIBRATE_LATCH >> 8, 0x42); /* add delay to start count */
this 'outb_p()' fixes this problem on startup.
The same kind of problem exist in do_gettimeofday().
if we disables TSC on PC using Geode/CS5520, latch value of PIT has no
accuracy then many many timejumps or timebacks happens. (every 2-10 sec)
with this patch, timejumps or timebacks don't occurs.
This patch also removes dodgy_tsc() workaround.
this patch tried on mini note-PC CASSIOPEIA FIVA http://www.casio.co.jp/mpc/103/
you can get spec from http://www.da-cha.org/fiva/fiva.html
I use with this workaround on 6 month and i think this work fine.
I tried 2.4.18, 2.4.19, 2.5.43.
------------------------------------------------------------
--- linux-2.5.43-orig/arch/i386/config.in 2002-10-17 13:04:36.000000000 +0900
+++ linux-2.5.43/arch/i386/config.in 2002-10-17 13:02:44.000000000 +0900
@@ -30,6 +30,7 @@
Winchip-C6 CONFIG_MWINCHIPC6 \
Winchip-2 CONFIG_MWINCHIP2 \
Winchip-2A/Winchip-3 CONFIG_MWINCHIP3D \
+ MediaGX/Geode CONFIG_GEODE \
CyrixIII/VIA-C3 CONFIG_MCYRIXIII" Pentium-Pro
#
# Define implied options from the CPU selection here
@@ -67,6 +68,13 @@
define_bool CONFIG_X86_PPRO_FENCE y
define_bool CONFIG_X86_F00F_BUG y
fi
+if [ "$CONFIG_GEODE" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_SHIFT 5
+ define_bool CONFIG_X86_USE_STRING_486 y
+ define_bool CONFIG_X86_ALIGNMENT_16 y
+ define_bool CONFIG_X86_TSC y
+ define_bool CONFIG_X86_PPRO_FENCE y
+fi
if [ "$CONFIG_M586TSC" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
define_bool CONFIG_X86_USE_STRING_486 y
diff -urB -x .config -x '*.[oasS]' -x '*.in' -x '*.rej' -x '*.orig' linux-2.5.43-orig/arch/i386/kernel/cpu/common.c linux-2.5.43/arch/i386/kernel/cpu/common.c
--- linux-2.5.43-orig/arch/i386/kernel/cpu/common.c 2002-10-12 13:21:05.000000000 +0900
+++ linux-2.5.43/arch/i386/kernel/cpu/common.c 2002-10-14 20:40:46.000000000 +0900
@@ -356,17 +356,6 @@
boot_cpu_data.x86_capability[2],
boot_cpu_data.x86_capability[3]);
}
-/*
- * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
- */
-
-void __init dodgy_tsc(void)
-{
- get_cpu_vendor(&boot_cpu_data);
- if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
- ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC ))
- cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data);
-}
void __init print_cpu_info(struct cpuinfo_x86 *c)
{
Only in linux-2.5.43/arch/i386/kernel/cpu: common.c~
diff -urB -x .config -x '*.[oasS]' -x '*.in' -x '*.rej' -x '*.orig' linux-2.5.43-orig/arch/i386/kernel/cpu/cyrix.c linux-2.5.43/arch/i386/kernel/cpu/cyrix.c
--- linux-2.5.43-orig/arch/i386/kernel/cpu/cyrix.c 2002-10-12 13:21:34.000000000 +0900
+++ linux-2.5.43/arch/i386/kernel/cpu/cyrix.c 2002-10-14 21:34:57.000000000 +0900
@@ -170,7 +233,7 @@
c->coma_bug = 1;
break;
- case 4: /* MediaGX/GXm */
+ case 4: /* MediaGX/GXm or Geode GXM/GXLV/GX1 */
#ifdef CONFIG_PCI
/* It isn't really a PCI quirk directly, but the cure is the
same. The MediaGX has deep magic SMM stuff that handles the
@@ -188,29 +247,26 @@
isa_dma_bridge_buggy = 2;
#endif
c->x86_cache_size=16; /* Yep 16K integrated cache thats it */
+
+ /*
+ * The 5510/5520 companion chips have a funky PIT.
+ */
+ if (pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
+ pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
+ pit_latch_buggy = 1;
/* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) {
- /* Enable Natsemi MMX extensions */
- setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
+ /* Enable cxMMX extensions (GX1 Datasheet 54) */
+ setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
get_model_name(c); /* get CPU marketing name */
- /*
- * The 5510/5520 companion chips have a funky PIT
- * that breaks the TSC synchronizing, so turn it off
- */
- if (pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
- pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
- clear_bit(X86_FEATURE_TSC, c->x86_capability);
return;
}
else { /* MediaGX */
Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
p = Cx86_cb+2;
c->x86_model = (dir1 & 0x20) ? 1 : 2;
-#ifndef CONFIG_CS5520
- clear_bit(X86_FEATURE_TSC, c->x86_capability);
-#endif
}
break;
diff -urB -x .config -x '*.[oasS]' -x '*.in' -x '*.rej' -x '*.orig' linux-2.5.43-orig/arch/i386/kernel/time.c linux-2.5.43/arch/i386/kernel/time.c
--- linux-2.5.43-orig/arch/i386/kernel/time.c 2002-10-17 13:04:36.000000000 +0900
+++ linux-2.5.43/arch/i386/kernel/time.c 2002-10-17 13:02:44.000000000 +0900
@@ -61,6 +61,7 @@
#include <asm/arch_hooks.h>
extern spinlock_t i8259A_lock;
+int pit_latch_buggy; /* extern */
#include "do_timer.h"
diff -urB -x .config -x '*.[oasS]' -x '*.in' -x '*.rej' -x '*.orig' linux-2.5.43-orig/arch/i386/kernel/timers/timer_tsc.c linux-2.5.43/arch/i386/kernel/timers/timer_tsc.c
--- linux-2.5.43-orig/arch/i386/kernel/timers/timer_tsc.c 2002-10-17 13:04:36.000000000 +0900
+++ linux-2.5.43/arch/i386/kernel/timers/timer_tsc.c 2002-10-17 13:02:45.000000000 +0900
@@ -60,6 +60,10 @@
static void mark_offset_tsc(void)
{
int count;
+#ifdef CONFIG_GEODE
+ int countmp;
+ static int count1=0, count2=LATCH;
+#endif
/*
* It is important that these two operations happen almost at
* the same time. We do the RDTSC stuff first, since it's
@@ -83,6 +87,22 @@
count |= inb(0x40) << 8;
spin_unlock(&i8253_lock);
+#ifdef CONFIG_GEODE
+ if (pit_latch_buggy) {
+ /* get center value of last 3 time lutch */
+ if (count2 >= count && count >= count1
+ || count1 >= count && count >= count2) {
+ count2 = count1; count1 = count;
+ } else if (count1 >= count2 && count2 >= count
+ || count >= count2 && count2 >= count1) {
+ countmp = count;count = count2;
+ count2 = count1;count1 = countmp;
+ } else {
+ count2 = count1; count1 = count; count = count1;
+ }
+ }
+#endif
+
count = ((LATCH-1) - count) * TICK_SIZE;
delay_at_last_interrupt = (count + LATCH/2) / LATCH;
}
@@ -114,7 +134,11 @@
*/
outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
- outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
+#ifndef CONFIG_GEODE
+ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
+#else
+ outb_p(CALIBRATE_LATCH >> 8, 0x42); /* add delay to start count */
+#endif
{
unsigned long startlow, starthigh;
@@ -238,8 +262,6 @@
* moaned if you have the only one in the world - you fix it!
*/
- dodgy_tsc();
-
if (cpu_has_tsc) {
unsigned long tsc_quotient = calibrate_tsc();
if (tsc_quotient) {
--
Hiroshi Miura --- http://www.da-cha.org/
NTTDATA Corp. Marketing & Business Strategy Planning Dept. --- [email protected]
Key fingerprint = 9117 9407 5684 FBF1 4063 15B4 401D D077 04AB 8617
-- My hacking life is happy as the day is long
> with this patch, timejumps or timebacks don't occurs.
> This patch also removes dodgy_tsc() workaround.
>
> this patch tried on mini note-PC CASSIOPEIA FIVA http://www.casio.co.jp/mpc/103/
> you can get spec from http://www.da-cha.org/fiva/fiva.html
Excellent. My wife has a 5520 based system and I can test it there too. Dave
if Windows always generates that delayed sequence (which btw the docs say
the delay is required...) it may explain the similar VIA weirdness
Alan
Alan Cox <[email protected]> writes:
> > with this patch, timejumps or timebacks don't occurs.
> > This patch also removes dodgy_tsc() workaround.
> >
> > this patch tried on mini note-PC CASSIOPEIA FIVA http://www.casio.co.jp/mpc/103/
> > you can get spec from http://www.da-cha.org/fiva/fiva.html
>
> Excellent. My wife has a 5520 based system and I can test it there too. Dave
> if Windows always generates that delayed sequence (which btw the docs say
> the delay is required...) it may explain the similar VIA weirdness
I have seen a similar problem with a Geode SC1200 based system which
basically is a GX1 and a CS5530 integrated on one chip. I'm starting
to wonder if the same bug has popped up again in the newer chip.
Unfortunately, I haven't got access to the troublesome system anymore
so I can't test the patch.
/Christer
--
"Just how much can I get away with and still go to heaven?"
Freelance consultant specializing in device driver programming for Linux
Christer Weinigel <[email protected]> http://www.weinigel.se
> I have seen a similar problem with a Geode SC1200 based system which
> basically is a GX1 and a CS5530 integrated on one chip. I'm starting
> to wonder if the same bug has popped up again in the newer chip.
The lack of delay between the two reads doesnt seem to be a chip bug but
a Linux bug.