diff options
-rw-r--r-- | include/linux/timex.h | 12 | ||||
-rw-r--r-- | kernel/time/ntp.c | 91 |
2 files changed, 56 insertions, 47 deletions
diff --git a/include/linux/timex.h b/include/linux/timex.h index 8ea3e71ba7fa..3c49d173bf39 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h | |||
@@ -58,6 +58,8 @@ | |||
58 | 58 | ||
59 | #include <asm/param.h> | 59 | #include <asm/param.h> |
60 | 60 | ||
61 | #define NTP_API 4 /* NTP API version */ | ||
62 | |||
61 | /* | 63 | /* |
62 | * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen | 64 | * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen |
63 | * for a slightly underdamped convergence characteristic. SHIFT_KH | 65 | * for a slightly underdamped convergence characteristic. SHIFT_KH |
@@ -135,6 +137,8 @@ struct timex { | |||
135 | #define ADJ_ESTERROR 0x0008 /* estimated time error */ | 137 | #define ADJ_ESTERROR 0x0008 /* estimated time error */ |
136 | #define ADJ_STATUS 0x0010 /* clock status */ | 138 | #define ADJ_STATUS 0x0010 /* clock status */ |
137 | #define ADJ_TIMECONST 0x0020 /* pll time constant */ | 139 | #define ADJ_TIMECONST 0x0020 /* pll time constant */ |
140 | #define ADJ_MICRO 0x1000 /* select microsecond resolution */ | ||
141 | #define ADJ_NANO 0x2000 /* select nanosecond resolution */ | ||
138 | #define ADJ_TICK 0x4000 /* tick value */ | 142 | #define ADJ_TICK 0x4000 /* tick value */ |
139 | #define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */ | 143 | #define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */ |
140 | #define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */ | 144 | #define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */ |
@@ -146,8 +150,6 @@ struct timex { | |||
146 | #define MOD_ESTERROR ADJ_ESTERROR | 150 | #define MOD_ESTERROR ADJ_ESTERROR |
147 | #define MOD_STATUS ADJ_STATUS | 151 | #define MOD_STATUS ADJ_STATUS |
148 | #define MOD_TIMECONST ADJ_TIMECONST | 152 | #define MOD_TIMECONST ADJ_TIMECONST |
149 | #define MOD_CLKB ADJ_TICK | ||
150 | #define MOD_CLKA ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */ | ||
151 | 153 | ||
152 | 154 | ||
153 | /* | 155 | /* |
@@ -169,9 +171,13 @@ struct timex { | |||
169 | #define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */ | 171 | #define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */ |
170 | 172 | ||
171 | #define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */ | 173 | #define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */ |
174 | #define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */ | ||
175 | #define STA_MODE 0x4000 /* mode (0 = PLL, 1 = FLL) (ro) */ | ||
176 | #define STA_CLK 0x8000 /* clock source (0 = A, 1 = B) (ro) */ | ||
172 | 177 | ||
178 | /* read-only bits */ | ||
173 | #define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \ | 179 | #define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \ |
174 | STA_PPSERROR | STA_CLOCKERR) /* read-only bits */ | 180 | STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK) |
175 | 181 | ||
176 | /* | 182 | /* |
177 | * Clock states (time_state) | 183 | * Clock states (time_state) |
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 2586c30f0658..3fc81066d7f1 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -65,7 +65,9 @@ static void ntp_update_offset(long offset) | |||
65 | if (!(time_status & STA_PLL)) | 65 | if (!(time_status & STA_PLL)) |
66 | return; | 66 | return; |
67 | 67 | ||
68 | time_offset = offset * NSEC_PER_USEC; | 68 | time_offset = offset; |
69 | if (!(time_status & STA_NANO)) | ||
70 | time_offset *= NSEC_PER_USEC; | ||
69 | 71 | ||
70 | /* | 72 | /* |
71 | * Scale the phase adjustment and | 73 | * Scale the phase adjustment and |
@@ -86,8 +88,11 @@ static void ntp_update_offset(long offset) | |||
86 | freq_adj = time_offset * mtemp; | 88 | freq_adj = time_offset * mtemp; |
87 | freq_adj = shift_right(freq_adj, time_constant * 2 + | 89 | freq_adj = shift_right(freq_adj, time_constant * 2 + |
88 | (SHIFT_PLL + 2) * 2 - SHIFT_NSEC); | 90 | (SHIFT_PLL + 2) * 2 - SHIFT_NSEC); |
89 | if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) | 91 | time_status &= ~STA_MODE; |
92 | if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) { | ||
90 | freq_adj += div_s64(time_offset << (SHIFT_NSEC - SHIFT_FLL), mtemp); | 93 | freq_adj += div_s64(time_offset << (SHIFT_NSEC - SHIFT_FLL), mtemp); |
94 | time_status |= STA_MODE; | ||
95 | } | ||
91 | freq_adj += time_freq; | 96 | freq_adj += time_freq; |
92 | freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC); | 97 | freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC); |
93 | time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC); | 98 | time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC); |
@@ -272,6 +277,7 @@ static inline void notify_cmos_timer(void) { } | |||
272 | */ | 277 | */ |
273 | int do_adjtimex(struct timex *txc) | 278 | int do_adjtimex(struct timex *txc) |
274 | { | 279 | { |
280 | struct timespec ts; | ||
275 | long save_adjust; | 281 | long save_adjust; |
276 | int result; | 282 | int result; |
277 | 283 | ||
@@ -282,17 +288,11 @@ int do_adjtimex(struct timex *txc) | |||
282 | /* Now we validate the data before disabling interrupts */ | 288 | /* Now we validate the data before disabling interrupts */ |
283 | 289 | ||
284 | if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) { | 290 | if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) { |
285 | /* singleshot must not be used with any other mode bits */ | 291 | /* singleshot must not be used with any other mode bits */ |
286 | if (txc->modes != ADJ_OFFSET_SINGLESHOT && | 292 | if (txc->modes & ~ADJ_OFFSET_SS_READ) |
287 | txc->modes != ADJ_OFFSET_SS_READ) | ||
288 | return -EINVAL; | 293 | return -EINVAL; |
289 | } | 294 | } |
290 | 295 | ||
291 | if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET)) | ||
292 | /* adjustment Offset limited to +- .512 seconds */ | ||
293 | if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE ) | ||
294 | return -EINVAL; | ||
295 | |||
296 | /* if the quartz is off by more than 10% something is VERY wrong ! */ | 296 | /* if the quartz is off by more than 10% something is VERY wrong ! */ |
297 | if (txc->modes & ADJ_TICK) | 297 | if (txc->modes & ADJ_TICK) |
298 | if (txc->tick < 900000/USER_HZ || | 298 | if (txc->tick < 900000/USER_HZ || |
@@ -300,51 +300,46 @@ int do_adjtimex(struct timex *txc) | |||
300 | return -EINVAL; | 300 | return -EINVAL; |
301 | 301 | ||
302 | write_seqlock_irq(&xtime_lock); | 302 | write_seqlock_irq(&xtime_lock); |
303 | result = time_state; /* mostly `TIME_OK' */ | ||
304 | 303 | ||
305 | /* Save for later - semantics of adjtime is to return old value */ | 304 | /* Save for later - semantics of adjtime is to return old value */ |
306 | save_adjust = time_adjust; | 305 | save_adjust = time_adjust; |
307 | 306 | ||
308 | #if 0 /* STA_CLOCKERR is never set yet */ | ||
309 | time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */ | ||
310 | #endif | ||
311 | /* If there are input parameters, then process them */ | 307 | /* If there are input parameters, then process them */ |
312 | if (txc->modes) { | 308 | if (txc->modes) { |
313 | if (txc->modes & ADJ_STATUS) /* only set allowed bits */ | 309 | if (txc->modes & ADJ_STATUS) { |
314 | time_status = (txc->status & ~STA_RONLY) | | 310 | if ((time_status & STA_PLL) && |
315 | (time_status & STA_RONLY); | 311 | !(txc->status & STA_PLL)) { |
312 | time_state = TIME_OK; | ||
313 | time_status = STA_UNSYNC; | ||
314 | } | ||
315 | /* only set allowed bits */ | ||
316 | time_status &= STA_RONLY; | ||
317 | time_status |= txc->status & ~STA_RONLY; | ||
318 | } | ||
319 | |||
320 | if (txc->modes & ADJ_NANO) | ||
321 | time_status |= STA_NANO; | ||
322 | if (txc->modes & ADJ_MICRO) | ||
323 | time_status &= ~STA_NANO; | ||
316 | 324 | ||
317 | if (txc->modes & ADJ_FREQUENCY) { | 325 | if (txc->modes & ADJ_FREQUENCY) { |
318 | if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) { | 326 | time_freq = min(txc->freq, MAXFREQ); |
319 | result = -EINVAL; | 327 | time_freq = min(time_freq, -MAXFREQ); |
320 | goto leave; | 328 | time_freq = ((s64)time_freq * NSEC_PER_USEC) |
321 | } | ||
322 | time_freq = ((s64)txc->freq * NSEC_PER_USEC) | ||
323 | >> (SHIFT_USEC - SHIFT_NSEC); | 329 | >> (SHIFT_USEC - SHIFT_NSEC); |
324 | } | 330 | } |
325 | 331 | ||
326 | if (txc->modes & ADJ_MAXERROR) { | 332 | if (txc->modes & ADJ_MAXERROR) |
327 | if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) { | ||
328 | result = -EINVAL; | ||
329 | goto leave; | ||
330 | } | ||
331 | time_maxerror = txc->maxerror; | 333 | time_maxerror = txc->maxerror; |
332 | } | 334 | if (txc->modes & ADJ_ESTERROR) |
333 | |||
334 | if (txc->modes & ADJ_ESTERROR) { | ||
335 | if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) { | ||
336 | result = -EINVAL; | ||
337 | goto leave; | ||
338 | } | ||
339 | time_esterror = txc->esterror; | 335 | time_esterror = txc->esterror; |
340 | } | ||
341 | 336 | ||
342 | if (txc->modes & ADJ_TIMECONST) { | 337 | if (txc->modes & ADJ_TIMECONST) { |
343 | if (txc->constant < 0) { /* NTP v4 uses values > 6 */ | 338 | time_constant = txc->constant; |
344 | result = -EINVAL; | 339 | if (!(time_status & STA_NANO)) |
345 | goto leave; | 340 | time_constant += 4; |
346 | } | 341 | time_constant = min(time_constant, (long)MAXTC); |
347 | time_constant = min(txc->constant + 4, (long)MAXTC); | 342 | time_constant = max(time_constant, 0l); |
348 | } | 343 | } |
349 | 344 | ||
350 | if (txc->modes & ADJ_OFFSET) { | 345 | if (txc->modes & ADJ_OFFSET) { |
@@ -360,16 +355,20 @@ int do_adjtimex(struct timex *txc) | |||
360 | if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET)) | 355 | if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET)) |
361 | ntp_update_frequency(); | 356 | ntp_update_frequency(); |
362 | } | 357 | } |
363 | leave: | 358 | |
359 | result = time_state; /* mostly `TIME_OK' */ | ||
364 | if (time_status & (STA_UNSYNC|STA_CLOCKERR)) | 360 | if (time_status & (STA_UNSYNC|STA_CLOCKERR)) |
365 | result = TIME_ERROR; | 361 | result = TIME_ERROR; |
366 | 362 | ||
367 | if ((txc->modes == ADJ_OFFSET_SINGLESHOT) || | 363 | if ((txc->modes == ADJ_OFFSET_SINGLESHOT) || |
368 | (txc->modes == ADJ_OFFSET_SS_READ)) | 364 | (txc->modes == ADJ_OFFSET_SS_READ)) |
369 | txc->offset = save_adjust; | 365 | txc->offset = save_adjust; |
370 | else | 366 | else { |
371 | txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) * | 367 | txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) * |
372 | NTP_INTERVAL_FREQ / 1000; | 368 | NTP_INTERVAL_FREQ; |
369 | if (!(time_status & STA_NANO)) | ||
370 | txc->offset /= NSEC_PER_USEC; | ||
371 | } | ||
373 | txc->freq = (time_freq / NSEC_PER_USEC) << | 372 | txc->freq = (time_freq / NSEC_PER_USEC) << |
374 | (SHIFT_USEC - SHIFT_NSEC); | 373 | (SHIFT_USEC - SHIFT_NSEC); |
375 | txc->maxerror = time_maxerror; | 374 | txc->maxerror = time_maxerror; |
@@ -391,7 +390,11 @@ leave: | |||
391 | txc->stbcnt = 0; | 390 | txc->stbcnt = 0; |
392 | write_sequnlock_irq(&xtime_lock); | 391 | write_sequnlock_irq(&xtime_lock); |
393 | 392 | ||
394 | do_gettimeofday(&txc->time); | 393 | getnstimeofday(&ts); |
394 | txc->time.tv_sec = ts.tv_sec; | ||
395 | txc->time.tv_usec = ts.tv_nsec; | ||
396 | if (!(time_status & STA_NANO)) | ||
397 | txc->time.tv_usec /= NSEC_PER_USEC; | ||
395 | 398 | ||
396 | notify_cmos_timer(); | 399 | notify_cmos_timer(); |
397 | 400 | ||