From: Paul Mackerras 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 Signed-off-by: Andrew Morton --- 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 ); } _