From: George Anzinger This patch changes the update of the cmos clock to be timer driven rather than poll driven by the timer interrupt function. If the clock is not being synced to an outside source the timer is removed and thus system overhead is nill in that case. The update frequency is still ~11 minutes and missing the update window still causes a retry in 60 seconds. Signed-off-by: George Anzinger Signed-off-by: Andrew Morton --- 25-akpm/arch/i386/kernel/time.c | 67 ++++++++++++++++++++++++++++------------ 25-akpm/kernel/time.c | 9 +++++ 2 files changed, 56 insertions(+), 20 deletions(-) diff -puN arch/i386/kernel/time.c~x86-cmos-time-update-optimisation arch/i386/kernel/time.c --- 25/arch/i386/kernel/time.c~x86-cmos-time-update-optimisation Thu Mar 10 16:06:18 2005 +++ 25-akpm/arch/i386/kernel/time.c Thu Mar 10 16:06:18 2005 @@ -215,8 +215,6 @@ static int set_rtc_mmss(unsigned long no return retval; } -/* last time the cmos clock got updated */ -static long last_rtc_update; int timer_ack; @@ -268,24 +266,6 @@ static inline void do_timer_interrupt(in do_timer_interrupt_hook(regs); - /* - * If we have an externally synchronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - */ - if ((time_status & STA_UNSYNC) == 0 && - xtime.tv_sec > last_rtc_update + 660 && - (xtime.tv_nsec / 1000) - >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 && - (xtime.tv_nsec / 1000) - <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) { - last_rtc_update = xtime.tv_sec; - if (efi_enabled) { - if (efi_set_rtc_mmss(xtime.tv_sec)) - last_rtc_update -= 600; - } else if (set_rtc_mmss(xtime.tv_sec)) - last_rtc_update -= 600; - } if (MCA_bus) { /* The PS/2 uses level-triggered interrupts. You can't @@ -342,7 +322,54 @@ unsigned long get_cmos_time(void) return retval; } +static void sync_cmos_clock(unsigned long dummy); + +static struct timer_list sync_cmos_timer = + TIMER_INITIALIZER(sync_cmos_clock, 0, 0); + +static void sync_cmos_clock(unsigned long dummy) +{ + struct timeval now, next; + int fail = 1; + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + * This code is run on a timer. If the clock is set, that timer + * may not expire at the correct time. Thus, we adjust... + */ + if ((time_status & STA_UNSYNC) != 0) + /* + * Not synced, exit, do not restart a timer (if one is + * running, let it run out). + */ + return; + do_gettimeofday(&now); + if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 && + now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) { + fail = set_rtc_mmss(now.tv_sec); + } + next.tv_usec = USEC_AFTER - now.tv_usec; + if (next.tv_usec <= 0) + next.tv_usec += USEC_PER_SEC; + if (!fail) { + next.tv_sec = 659; + } else { + next.tv_sec = 0; + } + if (next.tv_usec >= USEC_PER_SEC) { + next.tv_sec++; + next.tv_usec -= USEC_PER_SEC; + } + sync_cmos_timer.expires = jiffies + timeval_to_jiffies(&next); + add_timer(&sync_cmos_timer); + +} +void notify_arch_cmos_timer(void) +{ + sync_cmos_clock(0); +} static long clock_cmos_diff, sleep_start; static int timer_suspend(struct sys_device *dev, u32 state) diff -puN kernel/time.c~x86-cmos-time-update-optimisation kernel/time.c --- 25/kernel/time.c~x86-cmos-time-update-optimisation Thu Mar 10 16:06:18 2005 +++ 25-akpm/kernel/time.c Thu Mar 10 16:06:18 2005 @@ -215,6 +215,14 @@ long pps_stbcnt; /* stability limit exc /* hook for a loadable hardpps kernel module */ void (*hardpps_ptr)(struct timeval *); +/* we call this to notify the arch when the clock is being + * controlled. If no such arch routine, do nothing. + */ +void __attribute__ ((weak)) notify_arch_cmos_timer(void) +{ + return; +} + /* adjtimex mainly allows reading (and writing, if superuser) of * kernel time-keeping variables. used by xntpd. */ @@ -398,6 +406,7 @@ leave: if ((time_status & (STA_UNSYNC|ST txc->stbcnt = pps_stbcnt; write_sequnlock_irq(&xtime_lock); do_gettimeofday(&txc->time); + notify_arch_cmos_timer(); return(result); } _