diff options
Diffstat (limited to 'kernel/time/ntp.c')
-rw-r--r-- | kernel/time/ntp.c | 69 |
1 files changed, 56 insertions, 13 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 438c6b723ee2..cd91237dbfe3 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
13 | #include <linux/timer.h> | ||
13 | #include <linux/timex.h> | 14 | #include <linux/timex.h> |
14 | #include <linux/jiffies.h> | 15 | #include <linux/jiffies.h> |
15 | #include <linux/hrtimer.h> | 16 | #include <linux/hrtimer.h> |
@@ -116,11 +117,6 @@ void second_overflow(void) | |||
116 | if (xtime.tv_sec % 86400 == 0) { | 117 | if (xtime.tv_sec % 86400 == 0) { |
117 | xtime.tv_sec--; | 118 | xtime.tv_sec--; |
118 | wall_to_monotonic.tv_sec++; | 119 | wall_to_monotonic.tv_sec++; |
119 | /* | ||
120 | * The timer interpolator will make time change | ||
121 | * gradually instead of an immediate jump by one second | ||
122 | */ | ||
123 | time_interpolator_update(-NSEC_PER_SEC); | ||
124 | time_state = TIME_OOP; | 120 | time_state = TIME_OOP; |
125 | printk(KERN_NOTICE "Clock: inserting leap second " | 121 | printk(KERN_NOTICE "Clock: inserting leap second " |
126 | "23:59:60 UTC\n"); | 122 | "23:59:60 UTC\n"); |
@@ -130,11 +126,6 @@ void second_overflow(void) | |||
130 | if ((xtime.tv_sec + 1) % 86400 == 0) { | 126 | if ((xtime.tv_sec + 1) % 86400 == 0) { |
131 | xtime.tv_sec++; | 127 | xtime.tv_sec++; |
132 | wall_to_monotonic.tv_sec--; | 128 | wall_to_monotonic.tv_sec--; |
133 | /* | ||
134 | * Use of time interpolator for a gradual change of | ||
135 | * time | ||
136 | */ | ||
137 | time_interpolator_update(NSEC_PER_SEC); | ||
138 | time_state = TIME_WAIT; | 129 | time_state = TIME_WAIT; |
139 | printk(KERN_NOTICE "Clock: deleting leap second " | 130 | printk(KERN_NOTICE "Clock: deleting leap second " |
140 | "23:59:59 UTC\n"); | 131 | "23:59:59 UTC\n"); |
@@ -185,12 +176,64 @@ u64 current_tick_length(void) | |||
185 | return tick_length; | 176 | return tick_length; |
186 | } | 177 | } |
187 | 178 | ||
179 | #ifdef CONFIG_GENERIC_CMOS_UPDATE | ||
188 | 180 | ||
189 | void __attribute__ ((weak)) notify_arch_cmos_timer(void) | 181 | /* Disable the cmos update - used by virtualization and embedded */ |
182 | int no_sync_cmos_clock __read_mostly; | ||
183 | |||
184 | static void sync_cmos_clock(unsigned long dummy); | ||
185 | |||
186 | static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); | ||
187 | |||
188 | static void sync_cmos_clock(unsigned long dummy) | ||
189 | { | ||
190 | struct timespec now, next; | ||
191 | int fail = 1; | ||
192 | |||
193 | /* | ||
194 | * If we have an externally synchronized Linux clock, then update | ||
195 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | ||
196 | * called as close as possible to 500 ms before the new second starts. | ||
197 | * This code is run on a timer. If the clock is set, that timer | ||
198 | * may not expire at the correct time. Thus, we adjust... | ||
199 | */ | ||
200 | if (!ntp_synced()) | ||
201 | /* | ||
202 | * Not synced, exit, do not restart a timer (if one is | ||
203 | * running, let it run out). | ||
204 | */ | ||
205 | return; | ||
206 | |||
207 | getnstimeofday(&now); | ||
208 | if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) | ||
209 | fail = update_persistent_clock(now); | ||
210 | |||
211 | next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec; | ||
212 | if (next.tv_nsec <= 0) | ||
213 | next.tv_nsec += NSEC_PER_SEC; | ||
214 | |||
215 | if (!fail) | ||
216 | next.tv_sec = 659; | ||
217 | else | ||
218 | next.tv_sec = 0; | ||
219 | |||
220 | if (next.tv_nsec >= NSEC_PER_SEC) { | ||
221 | next.tv_sec++; | ||
222 | next.tv_nsec -= NSEC_PER_SEC; | ||
223 | } | ||
224 | mod_timer(&sync_cmos_timer, jiffies + timespec_to_jiffies(&next)); | ||
225 | } | ||
226 | |||
227 | static void notify_cmos_timer(void) | ||
190 | { | 228 | { |
191 | return; | 229 | if (no_sync_cmos_clock) |
230 | mod_timer(&sync_cmos_timer, jiffies + 1); | ||
192 | } | 231 | } |
193 | 232 | ||
233 | #else | ||
234 | static inline void notify_cmos_timer(void) { } | ||
235 | #endif | ||
236 | |||
194 | /* adjtimex mainly allows reading (and writing, if superuser) of | 237 | /* adjtimex mainly allows reading (and writing, if superuser) of |
195 | * kernel time-keeping variables. used by xntpd. | 238 | * kernel time-keeping variables. used by xntpd. |
196 | */ | 239 | */ |
@@ -355,6 +398,6 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) | |||
355 | txc->stbcnt = 0; | 398 | txc->stbcnt = 0; |
356 | write_sequnlock_irq(&xtime_lock); | 399 | write_sequnlock_irq(&xtime_lock); |
357 | do_gettimeofday(&txc->time); | 400 | do_gettimeofday(&txc->time); |
358 | notify_arch_cmos_timer(); | 401 | notify_cmos_timer(); |
359 | return(result); | 402 | return(result); |
360 | } | 403 | } |