Index: linux-2.6.7/include/linux/timex.h =================================================================== --- linux-2.6.7.orig/include/linux/timex.h 2004-07-29 12:08:14.000000000 -0700 +++ linux-2.6.7/include/linux/timex.h 2004-08-04 00:34:58.000000000 -0700 @@ -327,6 +327,10 @@ #define TIME_SOURCE_MMIO32 2 #define TIME_SOURCE_FUNCTION 3 +/* Countdown to do the adjustment of the interpolators. 1 minute */ +#define TIME_ADJUST_COUNTDOWN (HZ*60) +/* If we skip more than these number of nanoseconds per tick adjust interpolator clock */ +#define TIME_MAX_NS_SKIP_PER_TICK 10 /* For proper operations time_interpolator clocks must run slightly slower * than the standard clock since the interpolator may only correct by having * time jump forward during a tick. A slower clock is usually a side effect @@ -360,6 +364,9 @@ unsigned long last_cycle; /* Last timer value if TIME_SOURCE_JITTER is set */ unsigned long frequency; /* frequency in counts/second */ long drift; /* drift in parts-per-million (or -1) */ + unsigned long countdown; /* cycles left to adjustments */ + unsigned long count_resets; /* How many resets happened */ + unsigned long ns_skipped; /* Nanoseconds that were skipped */ struct time_interpolator *next; }; @@ -418,6 +425,9 @@ { time_interpolator->offset = 0; time_interpolator->last_counter = time_interpolator_get_counter(); + time_interpolator->countdown=TIME_ADJUST_COUNTDOWN; + time_interpolator->count_resets=0; + time_interpolator->ns_skipped=0; } #define GET_TI_NSECS(count,i) ((((count) - i->last_counter) * i->nsec_per_cyc) >> i->shift) @@ -443,9 +453,41 @@ if (delta_nsec < 0 || (unsigned long) delta_nsec < offset) time_interpolator->offset = offset - delta_nsec; - else + else { + time_interpolator->ns_skipped+= delta_nsec-offset; + time_interpolator->count_resets++; time_interpolator->offset = 0; /* Early tick. Resync */ + } time_interpolator->last_counter = counter; + if (time_interpolator->countdown) + time_interpolator->countdown--; + else { + /* Check for the necessity to adjust every minute + * Skip whatever happened in the first minute after bootup. We are only interested in the regular behavior of the + * interpolator. + * if (time_inteprolator->count_resets==0) time_interpolator->nsec_per_cyc--; + * if (other cond) time_interpolator->nsec_per_cyc++; + */ + if (jiffies >= 2*TIME_ADJUST_COUNTDOWN) { + if (time_interpolator->count_resets==0) + { + /* Uhh... no resets. We are running too fast */ + time_interpolator->nsec_per_cyc--; + printk(KERN_WARNING "time interpolator fast. nsec_per_cyc adjusted to %u\n",time_interpolator->nsec_per_cyc); + } else + if (time_interpolator->ns_skipped> TIME_MAX_NS_SKIP_PER_TICK*TIME_ADJUST_COUNTDOWN) + { + /* We are skipping more than 10usec per tick increase clock speed. */ + time_interpolator->nsec_per_cyc++; + printk(KERN_WARNING "time interpolator slow. %lu nsecs skipped in %lu skips. nsec_per_cyc adjusted to %u\n",time_interpolator->ns_skipped,time_interpolator->count_resets,time_interpolator->nsec_per_cyc); + + } else + printk(KERN_INFO "time_interpolator ok. %lu nsecs skipped in %lu skips.\n",time_interpolator->ns_skipped,time_interpolator->count_resets); + } + time_interpolator->count_resets=0; + time_interpolator->ns_skipped=0; + time_interpolator->countdown=TIME_ADJUST_COUNTDOWN; + } } #else /* !CONFIG_TIME_INTERPOLATION */ Index: linux-2.6.7/arch/ia64/sn/kernel/sn2/timer.c =================================================================== --- linux-2.6.7.orig/arch/ia64/sn/kernel/sn2/timer.c 2004-07-22 19:45:58.000000000 -0700 +++ linux-2.6.7/arch/ia64/sn/kernel/sn2/timer.c 2004-08-03 21:04:13.000000000 -0700 @@ -28,7 +28,7 @@ { sn2_interpolator.frequency = sn_rtc_cycles_per_second; sn2_interpolator.drift = -1; /* unknown */ - sn2_interpolator.shift = 0; /* RTC is 54 bits maximum shift is 10 */ + sn2_interpolator.shift = 10; /* RTC is 54 bits maximum shift is 10 */ sn2_interpolator.addr = RTC_COUNTER_ADDR; sn2_interpolator.source = TIME_SOURCE_MMIO64; register_time_interpolator(&sn2_interpolator); Index: linux-2.6.7/kernel/posix-timers.c =================================================================== --- linux-2.6.7.orig/kernel/posix-timers.c 2004-07-22 19:40:09.000000000 -0700 +++ linux-2.6.7/kernel/posix-timers.c 2004-08-03 21:09:26.000000000 -0700 @@ -218,7 +218,10 @@ .clock_get = do_posix_clock_monotonic_gettime, .clock_set = do_posix_clock_monotonic_settime }; - +#ifdef CONFIG_TIME_INTERPOLATION + /* Clocks are more accurate with time interpolators */ + clock_realtime.res=clock_monotonic.res=time_interpolator->nsec_per_cyc; +#endif register_posix_clock(CLOCK_REALTIME, &clock_realtime); register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);