aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrarit Bhargava <prarit@redhat.com>2013-02-08 17:59:53 -0500
committerJohn Stultz <john.stultz@linaro.org>2013-02-08 18:07:05 -0500
commit84e345e4e209cbe796c88fa2ad1732d7121ec100 (patch)
treef73f35d0e72a6c6f3e4b3ef430608aca3a5e8d54
parent6f16eebe1ff82176339a0439c98ebec9768b0ee2 (diff)
time, Fix setting of hardware clock in NTP code
At init time, if the system time is "warped" forward in warp_clock() it will differ from the hardware clock by sys_tz.tz_minuteswest. This time difference is not taken into account when ntp updates the hardware clock, and this causes the system time to jump forward by this offset every reboot. The kernel must take this offset into account when writing the system time to the hardware clock in the ntp code. This patch adds persistent_clock_is_local which indicates that an offset has been applied in warp_clock() and accounts for the "warp" before writing the hardware clock. x86 does not have this problem as rtc writes are software limited to a +/-15 minute window relative to the current rtc time. Other arches, such as powerpc, however do a full synchronization of the system time to the rtc and will see this problem. [v2]: generated against tip/timers/core Signed-off-by: Prarit Bhargava <prarit@redhat.com> Cc: John Stultz <john.stultz@linaro.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: John Stultz <john.stultz@linaro.org>
-rw-r--r--include/linux/time.h1
-rw-r--r--kernel/time.c8
-rw-r--r--kernel/time/ntp.c8
3 files changed, 15 insertions, 2 deletions
diff --git a/include/linux/time.h b/include/linux/time.h
index 476e1d7b2c37..a3ab6a814a9c 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -128,6 +128,7 @@ static inline bool has_persistent_clock(void)
128 128
129extern void read_persistent_clock(struct timespec *ts); 129extern void read_persistent_clock(struct timespec *ts);
130extern void read_boot_clock(struct timespec *ts); 130extern void read_boot_clock(struct timespec *ts);
131extern int persistent_clock_is_local;
131extern int update_persistent_clock(struct timespec now); 132extern int update_persistent_clock(struct timespec now);
132void timekeeping_init(void); 133void timekeeping_init(void);
133extern int timekeeping_suspended; 134extern int timekeeping_suspended;
diff --git a/kernel/time.c b/kernel/time.c
index d226c6a3fd28..c2a27dd93142 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -115,6 +115,12 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
115} 115}
116 116
117/* 117/*
118 * Indicates if there is an offset between the system clock and the hardware
119 * clock/persistent clock/rtc.
120 */
121int persistent_clock_is_local;
122
123/*
118 * Adjust the time obtained from the CMOS to be UTC time instead of 124 * Adjust the time obtained from the CMOS to be UTC time instead of
119 * local time. 125 * local time.
120 * 126 *
@@ -135,6 +141,8 @@ static inline void warp_clock(void)
135 struct timespec adjust; 141 struct timespec adjust;
136 142
137 adjust = current_kernel_time(); 143 adjust = current_kernel_time();
144 if (sys_tz.tz_minuteswest != 0)
145 persistent_clock_is_local = 1;
138 adjust.tv_sec += sys_tz.tz_minuteswest * 60; 146 adjust.tv_sec += sys_tz.tz_minuteswest * 60;
139 do_settimeofday(&adjust); 147 do_settimeofday(&adjust);
140} 148}
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 313b161504b7..b10a42bb0165 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -511,13 +511,17 @@ static void sync_cmos_clock(struct work_struct *work)
511 511
512 getnstimeofday(&now); 512 getnstimeofday(&now);
513 if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) { 513 if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) {
514 struct timespec adjust = now;
515
514 fail = -ENODEV; 516 fail = -ENODEV;
517 if (persistent_clock_is_local)
518 adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
515#ifdef CONFIG_GENERIC_CMOS_UPDATE 519#ifdef CONFIG_GENERIC_CMOS_UPDATE
516 fail = update_persistent_clock(now); 520 fail = update_persistent_clock(adjust);
517#endif 521#endif
518#ifdef CONFIG_RTC_SYSTOHC 522#ifdef CONFIG_RTC_SYSTOHC
519 if (fail == -ENODEV) 523 if (fail == -ENODEV)
520 fail = rtc_set_ntp_time(now); 524 fail = rtc_set_ntp_time(adjust);
521#endif 525#endif
522 } 526 }
523 527