Merge gregkh@master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[pandora-kernel.git] / arch / powerpc / kernel / time.c
index d209075..18e59e4 100644 (file)
@@ -32,7 +32,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -102,7 +101,7 @@ EXPORT_SYMBOL(tb_ticks_per_sec);    /* for cputime_t conversions */
 u64 tb_to_xs;
 unsigned tb_to_us;
 
-#define TICKLEN_SCALE  (SHIFT_SCALE - 10)
+#define TICKLEN_SCALE  TICK_LENGTH_SHIFT
 u64 last_tick_len;     /* units are ns / 2^TICKLEN_SCALE */
 u64 ticklen_to_xs;     /* 0.64 fraction */
 
@@ -418,7 +417,7 @@ static __inline__ void timer_check_rtc(void)
 /*
  * This version of gettimeofday has microsecond resolution.
  */
-static inline void __do_gettimeofday(struct timeval *tv, u64 tb_val)
+static inline void __do_gettimeofday(struct timeval *tv)
 {
        unsigned long sec, usec;
        u64 tb_ticks, xsec;
@@ -432,7 +431,12 @@ static inline void __do_gettimeofday(struct timeval *tv, u64 tb_val)
         * without a divide (and in fact, without a multiply)
         */
        temp_varp = do_gtod.varp;
-       tb_ticks = tb_val - temp_varp->tb_orig_stamp;
+
+       /* Sampling the time base must be done after loading
+        * do_gtod.varp in order to avoid racing with update_gtod.
+        */
+       data_barrier(temp_varp);
+       tb_ticks = get_tb() - temp_varp->tb_orig_stamp;
        temp_tb_to_xs = temp_varp->tb_to_xs;
        temp_stamp_xsec = temp_varp->stamp_xsec;
        xsec = temp_stamp_xsec + mulhdu(tb_ticks, temp_tb_to_xs);
@@ -465,7 +469,7 @@ void do_gettimeofday(struct timeval *tv)
                tv->tv_usec = usec;
                return;
        }
-       __do_gettimeofday(tv, get_tb());
+       __do_gettimeofday(tv);
 }
 
 EXPORT_SYMBOL(do_gettimeofday);
@@ -651,6 +655,7 @@ void timer_interrupt(struct pt_regs * regs)
        int next_dec;
        int cpu = smp_processor_id();
        unsigned long ticks;
+       u64 tb_next_jiffy;
 
 #ifdef CONFIG_PPC32
        if (atomic_read(&ppc_n_lost_interrupts) != 0)
@@ -692,11 +697,14 @@ void timer_interrupt(struct pt_regs * regs)
                        continue;
 
                write_seqlock(&xtime_lock);
-               tb_last_jiffy += tb_ticks_per_jiffy;
-               tb_last_stamp = per_cpu(last_jiffy, cpu);
-               do_timer(regs);
-               timer_recalc_offset(tb_last_jiffy);
-               timer_check_rtc();
+               tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
+               if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
+                       tb_last_jiffy = tb_next_jiffy;
+                       tb_last_stamp = per_cpu(last_jiffy, cpu);
+                       do_timer(regs);
+                       timer_recalc_offset(tb_last_jiffy);
+                       timer_check_rtc();
+               }
                write_sequnlock(&xtime_lock);
        }