From aa3be5f32db137bc4404f32a24b36fb47d48d260 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Fri, 21 Sep 2007 13:26:02 +1000 Subject: [POWERPC] Implement {read,update}_persistent_clock With these functions implemented we cooperate better with the generic timekeeping code. This obsoletes the need for the timer sysdev as a bonus. Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/time.c | 85 ++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 59 deletions(-) (limited to 'arch/powerpc/kernel') diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index d95e68c0a6b..b94e4dffba1 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -73,16 +73,11 @@ #include #endif -/* keep track of when we need to update the rtc */ -time_t last_rtc_update; #ifdef CONFIG_PPC_ISERIES static unsigned long __initdata iSeries_recal_titan; static signed long __initdata iSeries_recal_tb; #endif -/* The decrementer counts down by 128 every 128ns on a 601. */ -#define DECREMENTER_COUNT_601 (1000000000 / HZ) - #define XSEC_PER_SEC (1024*1024) #ifdef CONFIG_PPC64 @@ -348,39 +343,6 @@ void udelay(unsigned long usecs) } EXPORT_SYMBOL(udelay); -static __inline__ void timer_check_rtc(void) -{ - /* - * update the rtc when needed, this should be performed on the - * right fraction of a second. Half or full second ? - * Full second works on mk48t59 clocks, others need testing. - * Note that this update is basically only used through - * the adjtimex system calls. Setting the HW clock in - * any other way is a /dev/rtc and userland business. - * This is still wrong by -0.5/+1.5 jiffies because of the - * timer interrupt resolution and possible delay, but here we - * hit a quantization limit which can only be solved by higher - * resolution timers and decoupling time management from timer - * interrupts. This is also wrong on the clocks - * which require being written at the half second boundary. - * We should have an rtc call that only sets the minutes and - * seconds like on Intel to avoid problems with non UTC clocks. - */ - if (ppc_md.set_rtc_time && ntp_synced() && - xtime.tv_sec - last_rtc_update >= 659 && - abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ) { - struct rtc_time tm; - to_tm(xtime.tv_sec + 1 + timezone_offset, &tm); - tm.tm_year -= 1900; - tm.tm_mon -= 1; - if (ppc_md.set_rtc_time(&tm) == 0) - last_rtc_update = xtime.tv_sec + 1; - else - /* Try again one minute later */ - last_rtc_update += 60; - } -} - /* * This version of gettimeofday has microsecond resolution. */ @@ -689,7 +651,6 @@ void timer_interrupt(struct pt_regs * regs) tb_last_jiffy = tb_next_jiffy; do_timer(1); timer_recalc_offset(tb_last_jiffy); - timer_check_rtc(); } write_sequnlock(&xtime_lock); } @@ -801,11 +762,6 @@ int do_settimeofday(struct timespec *tv) set_normalized_timespec(&xtime, new_sec, new_nsec); set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - /* In case of a large backwards jump in time with NTP, we want the - * clock to be updated as soon as the PLL is again in lock. - */ - last_rtc_update = new_sec - 658; - ntp_clear(); new_xsec = xtime.tv_nsec; @@ -881,12 +837,35 @@ void __init generic_calibrate_decr(void) #endif } -unsigned long get_boot_time(void) +int update_persistent_clock(struct timespec now) +{ + struct rtc_time tm; + + if (!ppc_md.set_rtc_time) + return 0; + + to_tm(now.tv_sec + 1 + timezone_offset, &tm); + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + return ppc_md.set_rtc_time(&tm); +} + +unsigned long read_persistent_clock(void) { struct rtc_time tm; + static int first = 1; + + /* XXX this is a litle fragile but will work okay in the short term */ + if (first) { + first = 0; + if (ppc_md.time_init) + timezone_offset = ppc_md.time_init(); - if (ppc_md.get_boot_time) - return ppc_md.get_boot_time(); + /* get_boot_time() isn't guaranteed to be safe to call late */ + if (ppc_md.get_boot_time) + return ppc_md.get_boot_time() -timezone_offset; + } if (!ppc_md.get_rtc_time) return 0; ppc_md.get_rtc_time(&tm); @@ -898,14 +877,10 @@ unsigned long get_boot_time(void) void __init time_init(void) { unsigned long flags; - unsigned long tm = 0; struct div_result res; u64 scale, x; unsigned shift; - if (ppc_md.time_init != NULL) - timezone_offset = ppc_md.time_init(); - if (__USE_RTC()) { /* 601 processor: dec counts down by 128 every 128ns */ ppc_tb_freq = 1000000000; @@ -980,19 +955,14 @@ void __init time_init(void) /* Save the current timebase to pretty up CONFIG_PRINTK_TIME */ boot_tb = get_tb_or_rtc(); - tm = get_boot_time(); - write_seqlock_irqsave(&xtime_lock, flags); /* If platform provided a timezone (pmac), we correct the time */ if (timezone_offset) { sys_tz.tz_minuteswest = -timezone_offset / 60; sys_tz.tz_dsttime = 0; - tm -= timezone_offset; } - xtime.tv_sec = tm; - xtime.tv_nsec = 0; do_gtod.varp = &do_gtod.vars[0]; do_gtod.var_idx = 0; do_gtod.varp->tb_orig_stamp = tb_last_jiffy; @@ -1010,9 +980,6 @@ void __init time_init(void) time_freq = 0; - last_rtc_update = xtime.tv_sec; - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); write_sequnlock_irqrestore(&xtime_lock, flags); /* Not exact, but the timer interrupt takes care of this */ -- cgit v1.2.3