ChangeSet 1.2231.1.43, 2005/03/28 19:28:42-08:00, george@mvista.com

        [PATCH] x86: CMOS time update optimisation
        
        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.
        
        We want the calls to sync_cmos_clock() to be made in a consistent 
environment.
        This was not true when calling it directly from the NTP call code.  The
        change means that sync_cmos_clock() is ALWAYS called from run_timers(), 
i.e.
        as a timer call back function.
        
        Also, call the timer code only through the timer interface (set a short 
timer
        to do it from the ntp call).
        
        Signed-off-by: George Anzinger <george@mvista.com>
        Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
        Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>



 arch/i386/kernel/time.c |   75 +++++++++++++++++++++++++++++++++---------------
 kernel/time.c           |    9 +++++
 2 files changed, 62 insertions(+), 22 deletions(-)


diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c   2005-03-28 21:15:46 -08:00
+++ b/arch/i386/kernel/time.c   2005-03-28 21:15:46 -08:00
@@ -204,19 +204,19 @@
 {
        int retval;
 
+       WARN_ON(irqs_disabled());
+
        /* gets recalled with irq locally disabled */
-       spin_lock(&rtc_lock);
+       spin_lock_irq(&rtc_lock);
        if (efi_enabled)
                retval = efi_set_rtc_mmss(nowtime);
        else
                retval = mach_set_rtc_mmss(nowtime);
-       spin_unlock(&rtc_lock);
+       spin_unlock_irq(&rtc_lock);
 
        return retval;
 }
 
-/* last time the cmos clock got updated */
-static long last_rtc_update;
 
 int timer_ack;
 
@@ -268,24 +268,6 @@
 
        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
@@ -341,6 +323,55 @@
        spin_unlock(&rtc_lock);
 
        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;
+       }
+       mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
+}
+
+void notify_arch_cmos_timer(void)
+{
+       mod_timer(&sync_cmos_timer, jiffies + 1);
 }
 
 static long clock_cmos_diff, sleep_start;
diff -Nru a/kernel/time.c b/kernel/time.c
--- a/kernel/time.c     2005-03-28 21:15:46 -08:00
+++ b/kernel/time.c     2005-03-28 21:15:46 -08:00
@@ -215,6 +215,14 @@
 /* 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 @@
        txc->stbcnt        = pps_stbcnt;
        write_sequnlock_irq(&xtime_lock);
        do_gettimeofday(&txc->time);
+       notify_arch_cmos_timer();
        return(result);
 }
 
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to