diff options
-rw-r--r-- | kernel/time/ntp.c | 173 |
1 files changed, 91 insertions, 82 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index dbd6f8905614..2586c30f0658 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -35,7 +35,7 @@ static u64 tick_length, tick_length_base; | |||
35 | /* TIME_ERROR prevents overwriting the CMOS clock */ | 35 | /* TIME_ERROR prevents overwriting the CMOS clock */ |
36 | static int time_state = TIME_OK; /* clock synchronization status */ | 36 | static int time_state = TIME_OK; /* clock synchronization status */ |
37 | int time_status = STA_UNSYNC; /* clock status bits */ | 37 | int time_status = STA_UNSYNC; /* clock status bits */ |
38 | static s64 time_offset; /* time adjustment (ns) */ | 38 | static s64 time_offset; /* time adjustment (ns) */ |
39 | static long time_constant = 2; /* pll time constant */ | 39 | static long time_constant = 2; /* pll time constant */ |
40 | long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ | 40 | long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */ |
41 | long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ | 41 | long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */ |
@@ -57,6 +57,44 @@ static void ntp_update_frequency(void) | |||
57 | tick_length_base = div_u64(tick_length_base, NTP_INTERVAL_FREQ); | 57 | tick_length_base = div_u64(tick_length_base, NTP_INTERVAL_FREQ); |
58 | } | 58 | } |
59 | 59 | ||
60 | static void ntp_update_offset(long offset) | ||
61 | { | ||
62 | long mtemp; | ||
63 | s64 freq_adj; | ||
64 | |||
65 | if (!(time_status & STA_PLL)) | ||
66 | return; | ||
67 | |||
68 | time_offset = offset * NSEC_PER_USEC; | ||
69 | |||
70 | /* | ||
71 | * Scale the phase adjustment and | ||
72 | * clamp to the operating range. | ||
73 | */ | ||
74 | time_offset = min(time_offset, (s64)MAXPHASE * NSEC_PER_USEC); | ||
75 | time_offset = max(time_offset, (s64)-MAXPHASE * NSEC_PER_USEC); | ||
76 | |||
77 | /* | ||
78 | * Select how the frequency is to be controlled | ||
79 | * and in which mode (PLL or FLL). | ||
80 | */ | ||
81 | if (time_status & STA_FREQHOLD || time_reftime == 0) | ||
82 | time_reftime = xtime.tv_sec; | ||
83 | mtemp = xtime.tv_sec - time_reftime; | ||
84 | time_reftime = xtime.tv_sec; | ||
85 | |||
86 | freq_adj = time_offset * mtemp; | ||
87 | freq_adj = shift_right(freq_adj, time_constant * 2 + | ||
88 | (SHIFT_PLL + 2) * 2 - SHIFT_NSEC); | ||
89 | if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) | ||
90 | freq_adj += div_s64(time_offset << (SHIFT_NSEC - SHIFT_FLL), mtemp); | ||
91 | freq_adj += time_freq; | ||
92 | freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC); | ||
93 | time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC); | ||
94 | time_offset = div_s64(time_offset, NTP_INTERVAL_FREQ); | ||
95 | time_offset <<= SHIFT_UPDATE; | ||
96 | } | ||
97 | |||
60 | /** | 98 | /** |
61 | * ntp_clear - Clears the NTP state variables | 99 | * ntp_clear - Clears the NTP state variables |
62 | * | 100 | * |
@@ -131,7 +169,7 @@ void second_overflow(void) | |||
131 | break; | 169 | break; |
132 | case TIME_WAIT: | 170 | case TIME_WAIT: |
133 | if (!(time_status & (STA_INS | STA_DEL))) | 171 | if (!(time_status & (STA_INS | STA_DEL))) |
134 | time_state = TIME_OK; | 172 | time_state = TIME_OK; |
135 | } | 173 | } |
136 | 174 | ||
137 | /* | 175 | /* |
@@ -234,8 +272,7 @@ static inline void notify_cmos_timer(void) { } | |||
234 | */ | 272 | */ |
235 | int do_adjtimex(struct timex *txc) | 273 | int do_adjtimex(struct timex *txc) |
236 | { | 274 | { |
237 | long mtemp, save_adjust; | 275 | long save_adjust; |
238 | s64 freq_adj; | ||
239 | int result; | 276 | int result; |
240 | 277 | ||
241 | /* In order to modify anything, you gotta be super-user! */ | 278 | /* In order to modify anything, you gotta be super-user! */ |
@@ -272,94 +309,63 @@ int do_adjtimex(struct timex *txc) | |||
272 | time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */ | 309 | time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */ |
273 | #endif | 310 | #endif |
274 | /* If there are input parameters, then process them */ | 311 | /* If there are input parameters, then process them */ |
275 | if (txc->modes) | 312 | if (txc->modes) { |
276 | { | 313 | if (txc->modes & ADJ_STATUS) /* only set allowed bits */ |
277 | if (txc->modes & ADJ_STATUS) /* only set allowed bits */ | 314 | time_status = (txc->status & ~STA_RONLY) | |
278 | time_status = (txc->status & ~STA_RONLY) | | 315 | (time_status & STA_RONLY); |
279 | (time_status & STA_RONLY); | 316 | |
280 | 317 | if (txc->modes & ADJ_FREQUENCY) { | |
281 | if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */ | 318 | if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) { |
282 | if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) { | 319 | result = -EINVAL; |
283 | result = -EINVAL; | 320 | goto leave; |
284 | goto leave; | 321 | } |
322 | time_freq = ((s64)txc->freq * NSEC_PER_USEC) | ||
323 | >> (SHIFT_USEC - SHIFT_NSEC); | ||
285 | } | 324 | } |
286 | time_freq = ((s64)txc->freq * NSEC_PER_USEC) | 325 | |
287 | >> (SHIFT_USEC - SHIFT_NSEC); | 326 | if (txc->modes & ADJ_MAXERROR) { |
288 | } | 327 | if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) { |
289 | 328 | result = -EINVAL; | |
290 | if (txc->modes & ADJ_MAXERROR) { | 329 | goto leave; |
291 | if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) { | 330 | } |
292 | result = -EINVAL; | 331 | time_maxerror = txc->maxerror; |
293 | goto leave; | ||
294 | } | 332 | } |
295 | time_maxerror = txc->maxerror; | ||
296 | } | ||
297 | 333 | ||
298 | if (txc->modes & ADJ_ESTERROR) { | 334 | if (txc->modes & ADJ_ESTERROR) { |
299 | if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) { | 335 | if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) { |
300 | result = -EINVAL; | 336 | result = -EINVAL; |
301 | goto leave; | 337 | goto leave; |
338 | } | ||
339 | time_esterror = txc->esterror; | ||
302 | } | 340 | } |
303 | time_esterror = txc->esterror; | ||
304 | } | ||
305 | 341 | ||
306 | if (txc->modes & ADJ_TIMECONST) { /* p. 24 */ | 342 | if (txc->modes & ADJ_TIMECONST) { |
307 | if (txc->constant < 0) { /* NTP v4 uses values > 6 */ | 343 | if (txc->constant < 0) { /* NTP v4 uses values > 6 */ |
308 | result = -EINVAL; | 344 | result = -EINVAL; |
309 | goto leave; | 345 | goto leave; |
346 | } | ||
347 | time_constant = min(txc->constant + 4, (long)MAXTC); | ||
310 | } | 348 | } |
311 | time_constant = min(txc->constant + 4, (long)MAXTC); | ||
312 | } | ||
313 | 349 | ||
314 | if (txc->modes & ADJ_OFFSET) { /* values checked earlier */ | 350 | if (txc->modes & ADJ_OFFSET) { |
315 | if (txc->modes == ADJ_OFFSET_SINGLESHOT) { | 351 | if (txc->modes == ADJ_OFFSET_SINGLESHOT) |
316 | /* adjtime() is independent from ntp_adjtime() */ | 352 | /* adjtime() is independent from ntp_adjtime() */ |
317 | time_adjust = txc->offset; | 353 | time_adjust = txc->offset; |
354 | else | ||
355 | ntp_update_offset(txc->offset); | ||
318 | } | 356 | } |
319 | else if (time_status & STA_PLL) { | 357 | if (txc->modes & ADJ_TICK) |
320 | time_offset = txc->offset * NSEC_PER_USEC; | 358 | tick_usec = txc->tick; |
321 | 359 | ||
322 | /* | 360 | if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET)) |
323 | * Scale the phase adjustment and | 361 | ntp_update_frequency(); |
324 | * clamp to the operating range. | 362 | } |
325 | */ | 363 | leave: |
326 | time_offset = min(time_offset, (s64)MAXPHASE * NSEC_PER_USEC); | 364 | if (time_status & (STA_UNSYNC|STA_CLOCKERR)) |
327 | time_offset = max(time_offset, (s64)-MAXPHASE * NSEC_PER_USEC); | ||
328 | |||
329 | /* | ||
330 | * Select whether the frequency is to be controlled | ||
331 | * and in which mode (PLL or FLL). Clamp to the operating | ||
332 | * range. Ugly multiply/divide should be replaced someday. | ||
333 | */ | ||
334 | |||
335 | if (time_status & STA_FREQHOLD || time_reftime == 0) | ||
336 | time_reftime = xtime.tv_sec; | ||
337 | mtemp = xtime.tv_sec - time_reftime; | ||
338 | time_reftime = xtime.tv_sec; | ||
339 | |||
340 | freq_adj = time_offset * mtemp; | ||
341 | freq_adj = shift_right(freq_adj, time_constant * 2 + | ||
342 | (SHIFT_PLL + 2) * 2 - SHIFT_NSEC); | ||
343 | if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) | ||
344 | freq_adj += div_s64(time_offset << (SHIFT_NSEC - SHIFT_FLL), mtemp); | ||
345 | freq_adj += time_freq; | ||
346 | freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC); | ||
347 | time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC); | ||
348 | time_offset = div_s64(time_offset, NTP_INTERVAL_FREQ); | ||
349 | time_offset <<= SHIFT_UPDATE; | ||
350 | } /* STA_PLL */ | ||
351 | } /* txc->modes & ADJ_OFFSET */ | ||
352 | if (txc->modes & ADJ_TICK) | ||
353 | tick_usec = txc->tick; | ||
354 | |||
355 | if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET)) | ||
356 | ntp_update_frequency(); | ||
357 | } /* txc->modes */ | ||
358 | leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) | ||
359 | result = TIME_ERROR; | 365 | result = TIME_ERROR; |
360 | 366 | ||
361 | if ((txc->modes == ADJ_OFFSET_SINGLESHOT) || | 367 | if ((txc->modes == ADJ_OFFSET_SINGLESHOT) || |
362 | (txc->modes == ADJ_OFFSET_SS_READ)) | 368 | (txc->modes == ADJ_OFFSET_SS_READ)) |
363 | txc->offset = save_adjust; | 369 | txc->offset = save_adjust; |
364 | else | 370 | else |
365 | txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) * | 371 | txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) * |
@@ -384,9 +390,12 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) | |||
384 | txc->errcnt = 0; | 390 | txc->errcnt = 0; |
385 | txc->stbcnt = 0; | 391 | txc->stbcnt = 0; |
386 | write_sequnlock_irq(&xtime_lock); | 392 | write_sequnlock_irq(&xtime_lock); |
393 | |||
387 | do_gettimeofday(&txc->time); | 394 | do_gettimeofday(&txc->time); |
395 | |||
388 | notify_cmos_timer(); | 396 | notify_cmos_timer(); |
389 | return(result); | 397 | |
398 | return result; | ||
390 | } | 399 | } |
391 | 400 | ||
392 | static int __init ntp_tick_adj_setup(char *str) | 401 | static int __init ntp_tick_adj_setup(char *str) |