Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Thu, 17 Oct 2002 12:57:58 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Thu, 17 Oct 2002 12:57:58 -0400 Received: from ylug.mozilla.gr.jp ([203.141.142.92]:16902 "HELO maison.kyo-ko.org") by vger.kernel.org with SMTP id ; Thu, 17 Oct 2002 12:57:53 -0400 X-Mailer: cmail 2.61.1+20011011 on GNU Emacs 20.7.2 / Mule 4.1 =?ISO-2022-JP?B?KBskQjAqGyhCKQ==?= From: Hiroshi Miura To: davej@suse.de, hpa@zytor.com Cc: alan@redhat.com, linux-kernel@vger.kernel.org X-Face: "7/]{D;9O-#dR'kB\tvpz_:#o|*UdC.KK/_"IN*i5VTU&EBhS6w68xQDPh]i4N%1byZ~v~X Subject: workaround for Cyrix MediaGX/NSC Geode companion CS5510/5520 PIT latch bug k$vdp(%V@gY!_|7x7Ht)^ih5\%\l'hcl$`sqp;%`boxPHDJB<~Sr8(e:zPKmeZ)ZPml[0v\|[V00Jm G,%5V5X9Mw7j}(8+!o>&&wmQ]Xh=j User-Agent: SEMI/1.14.3 (=?ISO-2022-JP?B?GyRCNW0lTkMrGyhC?=) FLIM/1.14.3 (=?ISO-2022-JP?B?GyRCQCZLNThmTk1BMBsoQg==?=) APEL/10.3 Emacs/20.7 (i386-debian-linux-gnu) MULE/4.1 (=?ISO-2022-JP?B?GyRCMCobKEI=?=) MIME-Version: 1.0 (generated by SEMI 1.14.3 - =?ISO-2022-JP?B?IhskQjVtGyhC?= =?ISO-2022-JP?B?GyRCJU5DKxsoQiI=?=) Content-Type: text/plain; charset=US-ASCII Message-Id: <20021017170344.0C87C11782A@triton2> Date: Fri, 18 Oct 2002 02:03:44 +0900 (JST) Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8132 Lines: 221 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 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/