diff options
author | Roman Zippel <zippel@linux-m68k.org> | 2008-05-01 07:34:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-01 11:03:58 -0400 |
commit | eea83d896e318bda54be2d2770d2c5d6668d11db (patch) | |
tree | 581f455e02ed3d03e543642b5d54b83dc75d47c7 /kernel/time | |
parent | ee9851b218b8bafa22942b5404505ff3d2d34324 (diff) |
ntp: NTP4 user space bits update
This adds a few more things from the ntp nanokernel related to user space.
It's now possible to select the resolution used of some values via STA_NANO
and the kernel reports in which mode it works (pll/fll).
If some values for adjtimex() are outside the acceptable range, they are now
simply normalized instead of letting the syscall fail. I removed
MOD_CLKA/MOD_CLKB as the mapping didn't really makes any sense, the kernel
doesn't support setting the clock.
Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/ntp.c | 91 |
1 files changed, 47 insertions, 44 deletions
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 | ||