]> err.no Git - linux-2.6/blobdiff - kernel/time/timekeeping.c
Merge branch 'dmapool' of git://git.kernel.org/pub/scm/linux/kernel/git/willy/misc
[linux-2.6] / kernel / time / timekeeping.c
index 88c81026e0039ae8cf16e3da6b1de223d3c96312..cd5dbc4579c9bd3058063450b08e732c31e14ddf 100644 (file)
@@ -24,9 +24,7 @@
  * This read-write spinlock protects us from races in SMP while
  * playing with xtime and avenrun.
  */
-__attribute__((weak)) __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
-
-EXPORT_SYMBOL(xtime_lock);
+__cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
 
 
 /*
@@ -48,8 +46,12 @@ struct timespec xtime __attribute__ ((aligned (16)));
 struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
 static unsigned long total_sleep_time;         /* seconds */
 
-EXPORT_SYMBOL(xtime);
-
+static struct timespec xtime_cache __attribute__ ((aligned (16)));
+void update_xtime_cache(u64 nsec)
+{
+       xtime_cache = xtime;
+       timespec_add_ns(&xtime_cache, nsec);
+}
 
 static struct clocksource *clock; /* pointer to current clocksource */
 
@@ -80,13 +82,12 @@ static inline s64 __get_nsec_offset(void)
 }
 
 /**
- * __get_realtime_clock_ts - Returns the time of day in a timespec
+ * getnstimeofday - Returns the time of day in a timespec
  * @ts:                pointer to the timespec to be set
  *
- * Returns the time of day in a timespec. Used by
- * do_gettimeofday() and get_realtime_clock_ts().
+ * Returns the time of day in a timespec.
  */
-static inline void __get_realtime_clock_ts(struct timespec *ts)
+void getnstimeofday(struct timespec *ts)
 {
        unsigned long seq;
        s64 nsecs;
@@ -102,30 +103,19 @@ static inline void __get_realtime_clock_ts(struct timespec *ts)
        timespec_add_ns(ts, nsecs);
 }
 
-/**
- * getnstimeofday - Returns the time of day in a timespec
- * @ts:                pointer to the timespec to be set
- *
- * Returns the time of day in a timespec.
- */
-void getnstimeofday(struct timespec *ts)
-{
-       __get_realtime_clock_ts(ts);
-}
-
 EXPORT_SYMBOL(getnstimeofday);
 
 /**
  * do_gettimeofday - Returns the time of day in a timeval
  * @tv:                pointer to the timeval to be set
  *
- * NOTE: Users should be converted to using get_realtime_clock_ts()
+ * NOTE: Users should be converted to using getnstimeofday()
  */
 void do_gettimeofday(struct timeval *tv)
 {
        struct timespec now;
 
-       __get_realtime_clock_ts(&now);
+       getnstimeofday(&now);
        tv->tv_sec = now.tv_sec;
        tv->tv_usec = now.tv_nsec/1000;
 }
@@ -155,6 +145,7 @@ int do_settimeofday(struct timespec *tv)
 
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+       update_xtime_cache(0);
 
        clock->error = 0;
        ntp_clear();
@@ -196,7 +187,8 @@ static void change_clocksource(void)
 
        clock->error = 0;
        clock->xtime_nsec = 0;
-       clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
+       clocksource_calculate_interval(clock,
+               (unsigned long)(current_tick_length()>>TICK_LENGTH_SHIFT));
 
        tick_clock_notify();
 
@@ -205,6 +197,7 @@ static void change_clocksource(void)
 }
 #else
 static inline void change_clocksource(void) { }
+static inline s64 __get_nsec_offset(void) { return 0; }
 #endif
 
 /**
@@ -252,15 +245,16 @@ void __init timekeeping_init(void)
        ntp_clear();
 
        clock = clocksource_get_next();
-       clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
+       clocksource_calculate_interval(clock,
+               (unsigned long)(current_tick_length()>>TICK_LENGTH_SHIFT));
        clock->cycle_last = clocksource_read(clock);
 
        xtime.tv_sec = sec;
        xtime.tv_nsec = 0;
        set_normalized_timespec(&wall_to_monotonic,
                -xtime.tv_sec, -xtime.tv_nsec);
+       update_xtime_cache(0);
        total_sleep_time = 0;
-
        write_sequnlock_irqrestore(&xtime_lock, flags);
 }
 
@@ -268,6 +262,8 @@ void __init timekeeping_init(void)
 static int timekeeping_suspended;
 /* time in seconds when suspend began */
 static unsigned long timekeeping_suspend_time;
+/* xtime offset when we went into suspend */
+static s64 timekeeping_suspend_nsecs;
 
 /**
  * timekeeping_resume - Resumes the generic timekeeping subsystem.
@@ -293,6 +289,9 @@ static int timekeeping_resume(struct sys_device *dev)
                wall_to_monotonic.tv_sec -= sleep_length;
                total_sleep_time += sleep_length;
        }
+       /* Make sure that we have the correct xtime reference */
+       timespec_add_ns(&xtime, timekeeping_suspend_nsecs);
+       update_xtime_cache(0);
        /* re-base the last cycle value */
        clock->cycle_last = clocksource_read(clock);
        clock->error = 0;
@@ -313,9 +312,12 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
 {
        unsigned long flags;
 
+       timekeeping_suspend_time = read_persistent_clock();
+
        write_seqlock_irqsave(&xtime_lock, flags);
+       /* Get the current xtime offset */
+       timekeeping_suspend_nsecs = __get_nsec_offset();
        timekeeping_suspended = 1;
-       timekeeping_suspend_time = read_persistent_clock();
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
        clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
@@ -325,9 +327,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
 
 /* sysfs resume/suspend bits for timekeeping */
 static struct sysdev_class timekeeping_sysclass = {
+       .name           = "timekeeping",
        .resume         = timekeeping_resume,
        .suspend        = timekeeping_suspend,
-       set_kset_name("timekeeping"),
 };
 
 static struct sys_device device_timer = {
@@ -478,6 +480,8 @@ void update_wall_time(void)
        xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
        clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;
 
+       update_xtime_cache(cyc2ns(clock, offset));
+
        /* check to see if there is a new clocksource to use */
        change_clocksource();
        update_vsyscall(&xtime, clock);
@@ -509,3 +513,25 @@ void monotonic_to_bootbased(struct timespec *ts)
 {
        ts->tv_sec += total_sleep_time;
 }
+
+unsigned long get_seconds(void)
+{
+       return xtime_cache.tv_sec;
+}
+EXPORT_SYMBOL(get_seconds);
+
+
+struct timespec current_kernel_time(void)
+{
+       struct timespec now;
+       unsigned long seq;
+
+       do {
+               seq = read_seqbegin(&xtime_lock);
+
+               now = xtime_cache;
+       } while (read_seqretry(&xtime_lock, seq));
+
+       return now;
+}
+EXPORT_SYMBOL(current_kernel_time);