timekeeping: Introduce read_boot_clock
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 14 Aug 2009 13:47:32 +0000 (15:47 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Sat, 15 Aug 2009 08:55:47 +0000 (10:55 +0200)
Add the new function read_boot_clock to get the exact time the system
has been started. For architectures without support for exact boot
time a new weak function is added that returns 0.  Use the exact boot
time to initialize wall_to_monotonic, or xtime if the read_boot_clock
returned 0.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Ingo Molnar <mingo@elte.hu>
Acked-by: John Stultz <johnstul@us.ibm.com>
Cc: Daniel Walker <dwalker@fifo99.com>
LKML-Reference: <20090814134811.296703241@de.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/s390/kernel/time.c
include/linux/time.h
kernel/time/timekeeping.c

index a94ec48..6bff1a1 100644 (file)
@@ -187,6 +187,11 @@ void read_persistent_clock(struct timespec *ts)
        tod_to_timeval(get_clock() - TOD_UNIX_EPOCH, ts);
 }
 
+void read_boot_clock(struct timespec *ts)
+{
+       tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, ts);
+}
+
 static cycle_t read_tod_clock(struct clocksource *cs)
 {
        return get_clock();
@@ -243,9 +248,6 @@ void update_vsyscall_tz(void)
  */
 void __init time_init(void)
 {
-       struct timespec ts;
-       unsigned long flags;
-
        /* Reset time synchronization interfaces. */
        etr_reset();
        stp_reset();
@@ -261,15 +263,6 @@ void __init time_init(void)
        if (clocksource_register(&clocksource_tod) != 0)
                panic("Could not register TOD clock source");
 
-       /*
-        * Reset wall_to_monotonic to the initial timestamp created
-        * in head.S to get a precise value in /proc/uptime.
-        */
-       write_seqlock_irqsave(&xtime_lock, flags);
-       tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &ts);
-       set_normalized_timespec(&wall_to_monotonic, -ts.tv_sec, -ts.tv_nsec);
-       write_sequnlock_irqrestore(&xtime_lock, flags);
-
        /* Enable TOD clock interrupts on the boot cpu. */
        init_cpu_timer();
 
index 53a3216..f505988 100644 (file)
@@ -102,6 +102,7 @@ extern struct timespec wall_to_monotonic;
 extern seqlock_t xtime_lock;
 
 extern void read_persistent_clock(struct timespec *ts);
+extern void read_boot_clock(struct timespec *ts);
 extern int update_persistent_clock(struct timespec now);
 extern int no_sync_cmos_clock __read_mostly;
 void timekeeping_init(void);
index f1a21ce..15e06de 100644 (file)
@@ -501,6 +501,21 @@ void __attribute__((weak)) read_persistent_clock(struct timespec *ts)
        ts->tv_nsec = 0;
 }
 
+/**
+ * read_boot_clock -  Return time of the system start.
+ *
+ * Weak dummy function for arches that do not yet support it.
+ * Function to read the exact time the system has been started.
+ * Returns a timespec with tv_sec=0 and tv_nsec=0 if unsupported.
+ *
+ *  XXX - Do be sure to remove it once all arches implement it.
+ */
+void __attribute__((weak)) read_boot_clock(struct timespec *ts)
+{
+       ts->tv_sec = 0;
+       ts->tv_nsec = 0;
+}
+
 /*
  * timekeeping_init - Initializes the clocksource and common timekeeping values
  */
@@ -508,9 +523,10 @@ void __init timekeeping_init(void)
 {
        struct clocksource *clock;
        unsigned long flags;
-       struct timespec now;
+       struct timespec now, boot;
 
        read_persistent_clock(&now);
+       read_boot_clock(&boot);
 
        write_seqlock_irqsave(&xtime_lock, flags);
 
@@ -525,8 +541,12 @@ void __init timekeeping_init(void)
        xtime.tv_nsec = now.tv_nsec;
        raw_time.tv_sec = 0;
        raw_time.tv_nsec = 0;
+       if (boot.tv_sec == 0 && boot.tv_nsec == 0) {
+               boot.tv_sec = xtime.tv_sec;
+               boot.tv_nsec = xtime.tv_nsec;
+       }
        set_normalized_timespec(&wall_to_monotonic,
-               -xtime.tv_sec, -xtime.tv_nsec);
+                               -boot.tv_sec, -boot.tv_nsec);
        update_xtime_cache(0);
        total_sleep_time.tv_sec = 0;
        total_sleep_time.tv_nsec = 0;