diff options
Diffstat (limited to 'kernel/time/ntp.c')
| -rw-r--r-- | kernel/time/ntp.c | 59 |
1 files changed, 56 insertions, 3 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index b5e352597cbb..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> |
| @@ -175,12 +176,64 @@ u64 current_tick_length(void) | |||
| 175 | return tick_length; | 176 | return tick_length; |
| 176 | } | 177 | } |
| 177 | 178 | ||
| 179 | #ifdef CONFIG_GENERIC_CMOS_UPDATE | ||
| 178 | 180 | ||
| 179 | 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) | ||
| 180 | { | 228 | { |
| 181 | return; | 229 | if (no_sync_cmos_clock) |
| 230 | mod_timer(&sync_cmos_timer, jiffies + 1); | ||
| 182 | } | 231 | } |
| 183 | 232 | ||
| 233 | #else | ||
| 234 | static inline void notify_cmos_timer(void) { } | ||
| 235 | #endif | ||
| 236 | |||
| 184 | /* adjtimex mainly allows reading (and writing, if superuser) of | 237 | /* adjtimex mainly allows reading (and writing, if superuser) of |
| 185 | * kernel time-keeping variables. used by xntpd. | 238 | * kernel time-keeping variables. used by xntpd. |
| 186 | */ | 239 | */ |
| @@ -345,6 +398,6 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) | |||
| 345 | txc->stbcnt = 0; | 398 | txc->stbcnt = 0; |
| 346 | write_sequnlock_irq(&xtime_lock); | 399 | write_sequnlock_irq(&xtime_lock); |
| 347 | do_gettimeofday(&txc->time); | 400 | do_gettimeofday(&txc->time); |
| 348 | notify_arch_cmos_timer(); | 401 | notify_cmos_timer(); |
| 349 | return(result); | 402 | return(result); |
| 350 | } | 403 | } |
