Messages in this thread Patch in this message | | | Date | Mon, 1 Nov 1999 11:20:54 +0100 | From | Pavel Machek <> | Subject | Re: Wrong bogomips after plugging in AC power |
| |
Hi!
> > Unfortunately, when my toshiba changes speed, it changes speed of > > cycle counter, too :-(. That sounds like show stopper. > > Thats a gift not a show stopper. Just check the rdtsc change between each > timer tick looks believeable. Timer ticks might get delayed but if you start > to get an excessive numbers of ticks per n cycles of the tsc you know your > CPU slowed down
Detecting this is easy (and actually works): [It does not recalculate bogomips just now. Should we really recalculate them or just scale them according to the tsc?]
But... That is wrong solution. We already ran for at least one tick with wrong bogomips. If by chance some flaky device is used for that one-tick period, we already lost the game... Pavel
--- clean/arch/i386/kernel/time.c Sun Oct 10 11:22:47 1999 +++ linux/arch/i386/kernel/time.c Sun Oct 31 23:17:28 1999 @@ -429,6 +466,27 @@ */ write_lock(&xtime_lock); + if (use_tsc) { + long off = do_gettimeoffset(); + static int faster = 0, slower = 0; + if (off > (1100000/HZ)) + faster++; + else + faster = 0; + + if (off < (900000/HZ)) + slower++; + else + slower = 0; + + if ((faster > 10) || (slower > 10)) { + printk( KERN_ERR "TSC is %s than it should be! ", (faster > 10) ? "faster" : "slower" ); + big_calibrate_tsc(); + faster = 0; + slower = 0; + } + } + if (use_tsc) { /* @@ -547,7 +605,7 @@ #define CALIBRATE_LATCH (5 * LATCH) #define CALIBRATE_TIME (5 * 1000020/HZ) -static unsigned long __init calibrate_tsc(void) +static unsigned long calibrate_tsc(void) { /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); @@ -612,11 +670,39 @@ return 0; } +void big_calibrate_tsc(void) +{ + if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) { + unsigned long tsc_quotient = calibrate_tsc(); + if (tsc_quotient) { + fast_gettimeoffset_quotient = tsc_quotient; + use_tsc = 1; +#ifndef do_gettimeoffset + do_gettimeoffset = do_fast_gettimeoffset; +#endif + do_get_fast_time = do_gettimeofday; + + /* report CPU clock rate in Hz. + * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = + * clock/second. Our precision is about 100 ppm. + */ + { unsigned long eax=0, edx=1000000; + __asm__("divl %2" + :"=a" (cpu_hz), "=d" (edx) + :"r" (tsc_quotient), + "0" (eax), "1" (edx)); + printk("Detected %ld Hz processor.\n", cpu_hz); + } + } + } +} + void __init time_init(void) { xtime.tv_sec = get_cmos_time(); xtime.tv_usec = 0; + /* * If we have APM enabled or the CPU clock speed is variable * (CPU stops clock on HLT or slows clock to save power) @@ -644,29 +730,7 @@ dodgy_tsc(); - if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) { - unsigned long tsc_quotient = calibrate_tsc(); - if (tsc_quotient) { - fast_gettimeoffset_quotient = tsc_quotient; - use_tsc = 1; -#ifndef do_gettimeoffset - do_gettimeoffset = do_fast_gettimeoffset; -#endif - do_get_fast_time = do_gettimeofday; - - /* report CPU clock rate in Hz. - * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = - * clock/second. Our precision is about 100 ppm. - */ - { unsigned long eax=0, edx=1000000; - __asm__("divl %2" - :"=a" (cpu_hz), "=d" (edx) - :"r" (tsc_quotient), - "0" (eax), "1" (edx)); - printk("Detected %ld Hz processor.\n", cpu_hz); - } - } - } + big_calibrate_tsc(); #ifdef CONFIG_VISWS printk("Starting Cobalt Timer system clock\n"); @@ -686,3 +750,4 @@ setup_irq(0, &irq0); #endif } +
-- I'm really pavel@ucw.cz. Look at http://195.113.31.123/~pavel. Pavel Hi! I'm a .signature virus! Copy me into your ~/.signature, please!
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |