Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3048

kernel-2.6.18-194.11.1.el5.src.rpm

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;