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 | ||
