From: Paul Mackerras <paulus@samba.org>

Somewhere along the line we lost the code that updates some fields of the
systemcfg structure that are used for translating timebase values to time
of day.  I want to get rid of the systemcfg structure eventually, but
applications are using it (and in particular these fields) and I don't want
to break the ABI in a stable kernel series.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/ppc64/kernel/smp.c  |    1 +
 25-akpm/arch/ppc64/kernel/time.c |   31 +++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff -puN arch/ppc64/kernel/smp.c~ppc64-set-time-related-systemcfg-fields arch/ppc64/kernel/smp.c
--- 25/arch/ppc64/kernel/smp.c~ppc64-set-time-related-systemcfg-fields	2004-08-15 13:44:50.247119904 -0700
+++ 25-akpm/arch/ppc64/kernel/smp.c	2004-08-15 13:44:50.252119144 -0700
@@ -843,6 +843,7 @@ void __init smp_prepare_cpus(unsigned in
 	 * number of msecs off until someone does a settimeofday()
 	 */
 	do_gtod.tb_orig_stamp = tb_last_stamp;
+	systemcfg->tb_orig_stamp = tb_last_stamp;
 
 	look_for_more_cpus();
 #endif
diff -puN arch/ppc64/kernel/time.c~ppc64-set-time-related-systemcfg-fields arch/ppc64/kernel/time.c
--- 25/arch/ppc64/kernel/time.c~ppc64-set-time-related-systemcfg-fields	2004-08-15 13:44:50.249119600 -0700
+++ 25-akpm/arch/ppc64/kernel/time.c	2004-08-15 13:44:50.254118840 -0700
@@ -101,6 +101,8 @@ extern unsigned long wall_jiffies;
 extern unsigned long lpevent_count;
 extern int smp_tb_synchronized;
 
+extern struct timezone sys_tz;
+
 void ppc_adjtimex(void);
 
 static unsigned adjusting_time = 0;
@@ -233,6 +235,8 @@ static void iSeries_tb_recal(void)
 				do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
 				tb_to_xs = divres.result_low;
 				do_gtod.varp->tb_to_xs = tb_to_xs;
+				systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
+				systemcfg->tb_to_xs = tb_to_xs;
 			}
 			else {
 				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -408,6 +412,7 @@ int do_settimeofday(struct timespec *tv)
 	new_xsec += new_sec * XSEC_PER_SEC;
 	if ( new_xsec > delta_xsec ) {
 		do_gtod.varp->stamp_xsec = new_xsec - delta_xsec;
+		systemcfg->stamp_xsec = new_xsec - delta_xsec;
 	}
 	else {
 		/* This is only for the case where the user is setting the time
@@ -416,8 +421,13 @@ int do_settimeofday(struct timespec *tv)
 		 * the time to Jan 5, 1970 */
 		do_gtod.varp->stamp_xsec = new_xsec;
 		do_gtod.tb_orig_stamp = tb_last_stamp;
+		systemcfg->stamp_xsec = new_xsec;
+		systemcfg->tb_orig_stamp = tb_last_stamp;
 	}
 
+	systemcfg->tz_minuteswest = sys_tz.tz_minuteswest;
+	systemcfg->tz_dsttime = sys_tz.tz_dsttime;
+
 	write_sequnlock_irqrestore(&xtime_lock, flags);
 	clock_was_set();
 	return 0;
@@ -520,6 +530,11 @@ void __init time_init(void)
 	do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
 	do_gtod.varp->tb_to_xs = tb_to_xs;
 	do_gtod.tb_to_us = tb_to_us;
+	systemcfg->tb_orig_stamp = tb_last_stamp;
+	systemcfg->tb_update_count = 0;
+	systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
+	systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
+	systemcfg->tb_to_xs = tb_to_xs;
 
 	xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8);
 	next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval;
@@ -655,6 +670,22 @@ void ppc_adjtimex(void)
 	do_gtod.varp = temp_varp;
 	do_gtod.var_idx = temp_idx;
 
+	/*
+	 * tb_update_count is used to allow the problem state gettimeofday code
+	 * to assure itself that it sees a consistent view of the tb_to_xs and
+	 * stamp_xsec variables.  It reads the tb_update_count, then reads
+	 * tb_to_xs and stamp_xsec and then reads tb_update_count again.  If
+	 * the two values of tb_update_count match and are even then the
+	 * tb_to_xs and stamp_xsec values are consistent.  If not, then it
+	 * loops back and reads them again until this criteria is met.
+	 */
+	++(systemcfg->tb_update_count);
+	wmb();
+	systemcfg->tb_to_xs = new_tb_to_xs;
+	systemcfg->stamp_xsec = new_stamp_xsec;
+	wmb();
+	++(systemcfg->tb_update_count);
+
 	write_sequnlock_irqrestore( &xtime_lock, flags );
 
 }
_