]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kernel/time.c
Merge Paulus' tree
[karo-tx-linux.git] / arch / powerpc / kernel / time.c
index 3e722370113b793ed841de5b095a9fbbf0dc265f..6996a593dcb39b91422fa205f2af8057c2109165 100644 (file)
 #include <asm/firmware.h>
 #endif
 #ifdef CONFIG_PPC_ISERIES
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/iSeries/HvCallXm.h>
+#include <asm/iseries/it_lp_queue.h>
+#include <asm/iseries/hv_call_xm.h>
 #endif
 
-u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
-
-EXPORT_SYMBOL(jiffies_64);
-
 /* keep track of when we need to update the rtc */
 time_t last_rtc_update;
 extern int piranha_simulator;
@@ -126,6 +122,16 @@ unsigned long ppc_tb_freq;
 #define boot_cpuid     0
 #endif
 
+u64 tb_last_jiffy __cacheline_aligned_in_smp;
+unsigned long tb_last_stamp;
+
+/*
+ * Note that on ppc32 this only stores the bottom 32 bits of
+ * the timebase value, but that's enough to tell when a jiffy
+ * has passed.
+ */
+DEFINE_PER_CPU(unsigned long, last_jiffy);
+
 static __inline__ void timer_check_rtc(void)
 {
         /*
@@ -144,7 +150,7 @@ static __inline__ void timer_check_rtc(void)
          * We should have an rtc call that only sets the minutes and
          * seconds like on Intel to avoid problems with non UTC clocks.
          */
-        if (ntp_synced() &&
+        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 &&
            jiffies - wall_jiffies == 1) {
@@ -191,6 +197,26 @@ static inline void __do_gettimeofday(struct timeval *tv, u64 tb_val)
 
 void do_gettimeofday(struct timeval *tv)
 {
+       if (__USE_RTC()) {
+               /* do this the old way */
+               unsigned long flags, seq;
+               unsigned int sec, nsec, usec, lost;
+
+               do {
+                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
+                       sec = xtime.tv_sec;
+                       nsec = xtime.tv_nsec + tb_ticks_since(tb_last_stamp);
+                       lost = jiffies - wall_jiffies;
+               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+               usec = nsec / 1000 + lost * (1000000 / HZ);
+               while (usec >= 1000000) {
+                       usec -= 1000000;
+                       ++sec;
+               }
+               tv->tv_sec = sec;
+               tv->tv_usec = usec;
+               return;
+       }
        __do_gettimeofday(tv, get_tb());
 }
 
@@ -272,6 +298,8 @@ static __inline__ void timer_recalc_offset(u64 cur_tb)
        unsigned long offset;
        u64 new_stamp_xsec;
 
+       if (__USE_RTC())
+               return;
        offset = cur_tb - do_gtod.varp->tb_orig_stamp;
        if ((offset & 0x80000000u) == 0)
                return;
@@ -357,15 +385,6 @@ static void iSeries_tb_recal(void)
  * call will not be needed)
  */
 
-u64 tb_last_stamp __cacheline_aligned_in_smp;
-
-/*
- * Note that on ppc32 this only stores the bottom 32 bits of
- * the timebase value, but that's enough to tell when a jiffy
- * has passed.
- */
-DEFINE_PER_CPU(unsigned long, last_jiffy);
-
 /*
  * timer_interrupt - gets called when the decrementer overflows,
  * with interrupts disabled.
@@ -415,10 +434,11 @@ void timer_interrupt(struct pt_regs * regs)
                        continue;
 
                write_seqlock(&xtime_lock);
-               tb_last_stamp += tb_ticks_per_jiffy;
-               timer_recalc_offset(tb_last_stamp);
+               tb_last_jiffy += tb_ticks_per_jiffy;
+               tb_last_stamp = per_cpu(last_jiffy, cpu);
+               timer_recalc_offset(tb_last_jiffy);
                do_timer(regs);
-               timer_sync_xtime(tb_last_stamp);
+               timer_sync_xtime(tb_last_jiffy);
                timer_check_rtc();
                write_sequnlock(&xtime_lock);
                if (adjusting_time && (time_adjust == 0))
@@ -453,12 +473,12 @@ void wakeup_decrementer(void)
         * We don't expect this to be called on a machine with a 601,
         * so using get_tbl is fine.
         */
-       tb_last_stamp = get_tb();
+       tb_last_stamp = tb_last_jiffy = get_tb();
        for_each_cpu(i)
                per_cpu(last_jiffy, i) = tb_last_stamp;
 }
 
-#ifdef CONFIG_SMPxxx
+#ifdef CONFIG_SMP
 void __init smp_space_timers(unsigned int max_cpus)
 {
        int i;
@@ -483,6 +503,8 @@ void __init smp_space_timers(unsigned int max_cpus)
  */
 unsigned long long sched_clock(void)
 {
+       if (__USE_RTC())
+               return get_rtc();
        return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift;
 }
 
@@ -492,7 +514,7 @@ int do_settimeofday(struct timespec *tv)
        long wtm_nsec, new_nsec = tv->tv_nsec;
        unsigned long flags;
        long int tb_delta;
-       u64 new_xsec;
+       u64 new_xsec, tb_delta_xs;
 
        if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
                return -EINVAL;
@@ -515,8 +537,7 @@ int do_settimeofday(struct timespec *tv)
 #endif
        tb_delta = tb_ticks_since(tb_last_stamp);
        tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
-
-       new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta);
+       tb_delta_xs = mulhdu(tb_delta, do_gtod.varp->tb_to_xs);
 
        wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec);
        wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec);
@@ -531,10 +552,13 @@ int do_settimeofday(struct timespec *tv)
 
        ntp_clear();
 
-       new_xsec = (u64)new_nsec * XSEC_PER_SEC;
-       do_div(new_xsec, NSEC_PER_SEC);
-       new_xsec += (u64)new_sec * XSEC_PER_SEC;
-       update_gtod(tb_last_stamp, new_xsec, do_gtod.varp->tb_to_xs);
+       new_xsec = 0;
+       if (new_nsec != 0) {
+               new_xsec = (u64)new_nsec * XSEC_PER_SEC;
+               do_div(new_xsec, NSEC_PER_SEC);
+       }
+       new_xsec += (u64)new_sec * XSEC_PER_SEC - tb_delta_xs;
+       update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
 
 #ifdef CONFIG_PPC64
        systemcfg->tz_minuteswest = sys_tz.tz_minuteswest;
@@ -584,6 +608,17 @@ void __init generic_calibrate_decr(void)
                        ppc_proc_freq = *fp;
                }
        }
+#ifdef CONFIG_BOOKE
+       /* Set the time base to zero */
+       mtspr(SPRN_TBWL, 0);
+       mtspr(SPRN_TBWU, 0);
+
+       /* Clear any pending timer interrupts */
+       mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+       /* Enable decrementer interrupt */
+       mtspr(SPRN_TCR, TCR_DIE);
+#endif
        if (!node_found)
                printk(KERN_ERR "WARNING: Estimating processor frequency "
                                "(not found)\n");
@@ -616,12 +651,20 @@ void __init time_init(void)
         if (ppc_md.time_init != NULL)
                 timezone_offset = ppc_md.time_init();
 
-       ppc_md.calibrate_decr();
-
-       printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
-              ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
-       printk(KERN_INFO "time_init: processor frequency   = %lu.%.6lu MHz\n",
-              ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
+       if (__USE_RTC()) {
+               /* 601 processor: dec counts down by 128 every 128ns */
+               ppc_tb_freq = 1000000000;
+               tb_last_stamp = get_rtcl();
+               tb_last_jiffy = tb_last_stamp;
+       } else {
+               /* Normal PowerPC with timebase register */
+               ppc_md.calibrate_decr();
+               printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+                      ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
+               printk(KERN_INFO "time_init: processor frequency   = %lu.%.6lu MHz\n",
+                      ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
+               tb_last_stamp = tb_last_jiffy = get_tb();
+       }
 
        tb_ticks_per_jiffy = ppc_tb_freq / HZ;
        tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
@@ -661,17 +704,16 @@ void __init time_init(void)
        write_seqlock_irqsave(&xtime_lock, flags);
        xtime.tv_sec = tm;
        xtime.tv_nsec = 0;
-       tb_last_stamp = get_tb();
        do_gtod.varp = &do_gtod.vars[0];
        do_gtod.var_idx = 0;
-       do_gtod.varp->tb_orig_stamp = tb_last_stamp;
+       do_gtod.varp->tb_orig_stamp = tb_last_jiffy;
        __get_cpu_var(last_jiffy) = tb_last_stamp;
        do_gtod.varp->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;
        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;
 #ifdef CONFIG_PPC64
-       systemcfg->tb_orig_stamp = tb_last_stamp;
+       systemcfg->tb_orig_stamp = tb_last_jiffy;
        systemcfg->tb_update_count = 0;
        systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
        systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
@@ -948,16 +990,6 @@ void div128_by_32(u64 dividend_high, u64 dividend_low,
        w = a / divisor;
        ra = ((u64)(a - (w * divisor)) << 32) + b;
 
-#ifdef CONFIG_PPC64
-       x = ra / divisor;
-       rb = ((ra - (x * divisor)) << 32) + c;
-
-       y = rb / divisor;
-       rc = ((rb - (y * divisor)) << 32) + d;
-
-       z = rc / divisor;
-#else
-       /* for 32-bit, use do_div from div64.h */
        rb = ((u64) do_div(ra, divisor) << 32) + c;
        x = ra;
 
@@ -966,10 +998,8 @@ void div128_by_32(u64 dividend_high, u64 dividend_low,
 
        do_div(rc, divisor);
        z = rc;
-#endif
 
        dr->result_high = ((u64)w << 32) + x;
        dr->result_low  = ((u64)y << 32) + z;
 
 }
-