]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/time/clocksource.c
Merge branch 'linus' into core/softlockup
[linux-2.6-omap-h63xx.git] / kernel / time / clocksource.c
index ca89e1593f0833840fbbcaf58ba5bb5b075362e2..c46c931a7fe70424b66ca798c13c7819fbb9efe4 100644 (file)
 #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
 #include <linux/tick.h>
 
+void timecounter_init(struct timecounter *tc,
+                     const struct cyclecounter *cc,
+                     u64 start_tstamp)
+{
+       tc->cc = cc;
+       tc->cycle_last = cc->read(cc);
+       tc->nsec = start_tstamp;
+}
+EXPORT_SYMBOL(timecounter_init);
+
+/**
+ * timecounter_read_delta - get nanoseconds since last call of this function
+ * @tc:         Pointer to time counter
+ *
+ * When the underlying cycle counter runs over, this will be handled
+ * correctly as long as it does not run over more than once between
+ * calls.
+ *
+ * The first call to this function for a new time counter initializes
+ * the time tracking and returns an undefined result.
+ */
+static u64 timecounter_read_delta(struct timecounter *tc)
+{
+       cycle_t cycle_now, cycle_delta;
+       u64 ns_offset;
+
+       /* read cycle counter: */
+       cycle_now = tc->cc->read(tc->cc);
+
+       /* calculate the delta since the last timecounter_read_delta(): */
+       cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask;
+
+       /* convert to nanoseconds: */
+       ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta);
+
+       /* update time stamp of timecounter_read_delta() call: */
+       tc->cycle_last = cycle_now;
+
+       return ns_offset;
+}
+
+u64 timecounter_read(struct timecounter *tc)
+{
+       u64 nsec;
+
+       /* increment time by nanoseconds since last call */
+       nsec = timecounter_read_delta(tc);
+       nsec += tc->nsec;
+       tc->nsec = nsec;
+
+       return nsec;
+}
+EXPORT_SYMBOL(timecounter_read);
+
+u64 timecounter_cyc2time(struct timecounter *tc,
+                        cycle_t cycle_tstamp)
+{
+       u64 cycle_delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask;
+       u64 nsec;
+
+       /*
+        * Instead of always treating cycle_tstamp as more recent
+        * than tc->cycle_last, detect when it is too far in the
+        * future and treat it as old time stamp instead.
+        */
+       if (cycle_delta > tc->cc->mask / 2) {
+               cycle_delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask;
+               nsec = tc->nsec - cyclecounter_cyc2ns(tc->cc, cycle_delta);
+       } else {
+               nsec = cyclecounter_cyc2ns(tc->cc, cycle_delta) + tc->nsec;
+       }
+
+       return nsec;
+}
+EXPORT_SYMBOL(timecounter_cyc2time);
+
 /* XXX - Would like a better way for initializing curr_clocksource */
 extern struct clocksource clocksource_jiffies;