From: Don Zickus <dzickus@redhat.com> Date: Thu, 17 Sep 2009 00:01:31 -0400 Subject: Revert: [x86_64] fix gettimeoday TSC overflow issue - 1 Message-id: 4AB1B49B.2040000@redhat.com O-Subject: Re: [RHEL5 PATCH]: Fix gettimeoday() TSC overflow issue [v3] Bugzilla: 467942 Prarit Bhargava wrote: > A quick repost for dzickus. > > I had to update this patch for -148.el5 because of significant conflicts > in that kernel. The patches that my patch conflicted with have since > been removed and now [v2] will no longer apply properly. > > Refresh for -163.el5. > > Quick ACKs are appreciated -- I think those of you cc'd have already > acked [v2]. Just an FYI, this patch is being reverted due to test failures. Cheers, Don -- All rights reversed. diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index c3b3ea0..b1f1e22 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -78,7 +78,6 @@ static int notsc __initdata = 0; #define NSEC_PER_REAL_TICK (NSEC_PER_SEC / REAL_HZ) #define NS_SCALE 10 /* 2^10, carefully chosen */ -#define NS_SCALE_22 22 /* 2^22, carefully chosen for TSC */ #define US_SCALE 32 /* 2^32, arbitralrily chosen */ unsigned int cpu_khz; /* TSC clocks / usec, not used here */ @@ -121,7 +120,7 @@ static inline long do_gettimeoffset_tsc(void) t = get_cycles_sync(); if (t < vxtime.last_tsc) t = vxtime.last_tsc; /* hack */ - x = ((t - vxtime.last_tsc) * vxtime.tsc_quot) >> NS_SCALE_22; + x = ((t - vxtime.last_tsc) * vxtime.tsc_quot) >> NS_SCALE; return x; } @@ -401,11 +400,6 @@ static void do_timer_account_lost_ticks(struct pt_regs *regs) { unsigned long tsc; int delay = 0, offset = 0, lost = 0, i; - long tsc_offset = 0; - - /* for re-calculate offset */ - long last_tsc_quot = vxtime.tsc_quot; - unsigned long last_tsc = vxtime.last_tsc; if (vxtime.hpet_address) offset = hpet_readl(HPET_COUNTER); @@ -449,24 +443,27 @@ static void do_timer_account_lost_ticks(struct pt_regs *regs) lost = pmtimer_mark_offset(); #endif } else { - tsc_offset = (((tsc - vxtime.last_tsc) * - vxtime.tsc_quot) >> NS_SCALE_22) - - NSEC_PER_REAL_TICK; + offset = (((tsc - vxtime.last_tsc) * + vxtime.tsc_quot) >> NS_SCALE) - NSEC_PER_REAL_TICK; - if (tsc_offset < 0) - tsc_offset = 0; + if (offset < 0) + offset = 0; lost = 0; - while (tsc_offset > NSEC_PER_REAL_TICK) { + while (offset > NSEC_PER_REAL_TICK) { lost++; - tsc_offset -= NSEC_PER_REAL_TICK; + offset -= NSEC_PER_REAL_TICK; } /* FIXME: 1000 or 1000000? */ monotonic_base += (tsc - vxtime.last_tsc) * 1000000 / cpu_khz; - vxtime.last_tsc = tsc - vxtime.quot * delay / - (vxtime.tsc_quot >> (NS_SCALE_22 - NS_SCALE)); + vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot; + + if ((((tsc - vxtime.last_tsc) * + vxtime.tsc_quot) >> NS_SCALE) < offset) + vxtime.last_tsc = tsc - + (((long) offset << NS_SCALE) / vxtime.tsc_quot) - 1; } /* SCALE: We expect tick_divider - 1 lost, ie 0 for normal behaviour */ if (lost > (int)tick_divider - 1) { @@ -477,16 +474,6 @@ static void do_timer_account_lost_ticks(struct pt_regs *regs) /* Do the timer stuff */ for (i = 0; i < tick_divider; i++) do_timer_jiffy(regs); - - /* re-calculate vxtime.last_tsc */ - if (vxtime.mode != VXTIME_HPET && vxtime.mode != VXTIME_PMTMR) { - if (tsc > (last_tsc + tsc_khz)) { - vxtime.last_tsc = vxtime.last_tsc - - (tsc - last_tsc - - ((u64)tsc_khz * (u64)(lost + 1))) * - last_tsc_quot / vxtime.tsc_quot; - } - } } /* @@ -590,12 +577,12 @@ static unsigned int cyc2ns_scale __read_mostly; static inline void set_cyc2ns_scale(unsigned long cpu_khz) { - cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE_22) / cpu_khz; + cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / cpu_khz; } static inline unsigned long long cycles_2_ns(unsigned long long cyc) { - return (cyc * cyc2ns_scale) >> NS_SCALE_22; + return (cyc * cyc2ns_scale) >> NS_SCALE; } unsigned long long sched_clock(void) @@ -813,8 +800,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new); if (!(freq->flags & CPUFREQ_CONST_LOOPS)) - vxtime.tsc_quot = (NSEC_PER_MSEC << NS_SCALE_22) / - tsc_khz; + vxtime.tsc_quot = (NSEC_PER_MSEC << NS_SCALE) / cpu_khz; } set_cyc2ns_scale(tsc_khz_ref); @@ -1148,7 +1134,7 @@ void __init time_init(void) vxtime.mode = VXTIME_TSC; vxtime.quot = (NSEC_PER_SEC << NS_SCALE) / vxtime_hz; - vxtime.tsc_quot = (NSEC_PER_MSEC << NS_SCALE_22) / tsc_khz; + vxtime.tsc_quot = (NSEC_PER_MSEC << NS_SCALE) / cpu_khz; vxtime.last_tsc = get_cycles_sync(); setup_irq(0, &irq0); @@ -1244,7 +1230,7 @@ void time_init_gtod(void) printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); vxtime.quot = (NSEC_PER_SEC << NS_SCALE) / vxtime_hz; - vxtime.tsc_quot = (NSEC_PER_MSEC << NS_SCALE_22) / tsc_khz; + vxtime.tsc_quot = (NSEC_PER_MSEC << NS_SCALE) / tsc_khz; vxtime.last_tsc = get_cycles_sync(); set_cyc2ns_scale(tsc_khz); diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index bb42909..69719d6 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -53,8 +53,6 @@ int __vgetcpu_mode __section_vgetcpu_mode; ((v - fix_to_virt(VSYSCALL_FIRST_PAGE)) + __pa_symbol(&__vsyscall_0)); }) #define NS_SCALE 10 /* 2^10, carefully chosen */ -#define NS_SCALE_22 22 /* 2^22, carefully chosen for TSC*/ - static __always_inline void timeval_normalize(struct timeval * tv) { @@ -84,7 +82,7 @@ static __always_inline void do_vgettimeofday(struct timeval * tv) if (t < __vxtime.last_tsc) t = __vxtime.last_tsc; nsec += ((t - __vxtime.last_tsc) * - __vxtime.tsc_quot) >> NS_SCALE_22; + __vxtime.tsc_quot) >> NS_SCALE; } else { nsec += ((readl((void *)fix_to_virt(VSYSCALL_HPET) + 0xf0) - diff --git a/kernel/timer.c b/kernel/timer.c index e7a3e51..0e831b5 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1294,22 +1294,6 @@ static void update_wall_time(void) xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift; clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift; -#ifdef CONFIG_X86_64 -#define NS_SCALE_22 22 /* 2^22, carefully chosen */ - { -#ifdef CONFIG_XEN - unsigned int tsc_khz = cpu_khz; -#else - extern unsigned int tsc_khz; -#endif - /* re-calculate vxtime.tsc_quot */ - vxtime.tsc_quot = (NSEC_PER_MSEC << NS_SCALE_22) / tsc_khz * - (((s64)clock->xtime_interval + - (s64)clock->xtime_nsec) >> - clock->shift) / NSEC_PER_MSEC; - } -#endif - /* check to see if there is a new clocksource to use */ if (change_clocksource()) { clock->error = 0;