Messages in this thread Patch in this message | | | From | Hiroshi Miura <> | Subject | workaround for Cyrix MediaGX/NSC Geode companion CS5510/5520 PIT latch bug k$vdp(%!_|7x7Ht)^ih5\%\l'hcl$`sqp;%`boxPHDJB<~Sr8(e:zPKmeZ)ZPml[0v\|[V00Jm G,%5V5X9Mw7j}(8+!o>&&wmQ]Xh=j | Date | Fri, 18 Oct 2002 02:03:44 +0900 (JST) |
| |
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. --- miurahr@nttdata.co.jp Key fingerprint = 9117 9407 5684 FBF1 4063 15B4 401D D077 04AB 8617 -- My hacking life is happy as the day is long
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |