aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/ntp.c
diff options
context:
space:
mode:
authorRoman Zippel <zippel@linux-m68k.org>2006-10-01 02:28:28 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-01 03:39:27 -0400
commitf19923937321244e7dc334767eb4b67e0e3d5c74 (patch)
treebe82956c645bab0cb13e73677116417d4c5ce311 /kernel/time/ntp.c
parent04b617e71e363e640e88be1e43f53fa6a3afef9f (diff)
[PATCH] ntp: convert to the NTP4 reference model
This converts the kernel ntp model into a model which matches the nanokernel reference implementations. The previous patches already increased the resolution and precision of the computations, so that this conversion becomes quite simple. <linux@horizon.com> explains: The original NTP kernel interface was defined in units of microseconds. That's what Linux implements. As computers have gotten faster and can now split microseconds easily, a new kernel interface using nanosecond units was defined ("the nanokernel", confusing as that name is to OS hackers), and there's an STA_NANO bit in the adjtimex() status field to tell the application which units it's using. The current ntpd supports both, but Linux loses some possible timing resolution because of quantization effects, and the ntpd hackers would really like to be able to drop the backwards compatibility code. Ulrich Windl has been maintaining a patch set to do the conversion for years, but it's hard to keep in sync. Signed-off-by: Roman Zippel <zippel@linux-m68k.org> Cc: john stultz <johnstul@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/time/ntp.c')
-rw-r--r--kernel/time/ntp.c51
1 files changed, 19 insertions, 32 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 9137b54613e0..1ab5e9d7fa50 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -145,18 +145,11 @@ void second_overflow(void)
145 } 145 }
146 146
147 /* 147 /*
148 * Compute the phase adjustment for the next second. In PLL mode, the 148 * Compute the phase adjustment for the next second. The offset is
149 * offset is reduced by a fixed factor times the time constant. In FLL 149 * reduced by a fixed factor times the time constant.
150 * mode the offset is used directly. In either mode, the maximum phase
151 * adjustment for each second is clamped so as to spread the adjustment
152 * over not more than the number of seconds between updates.
153 */ 150 */
154 tick_length = tick_length_base; 151 tick_length = tick_length_base;
155 time_adj = time_offset; 152 time_adj = shift_right(time_offset, SHIFT_PLL + time_constant);
156 if (!(time_status & STA_FLL))
157 time_adj = shift_right(time_adj, SHIFT_KG + time_constant);
158 time_adj = min(time_adj, -((MAXPHASE / HZ) << SHIFT_UPDATE) / MINSEC);
159 time_adj = max(time_adj, ((MAXPHASE / HZ) << SHIFT_UPDATE) / MINSEC);
160 time_offset -= time_adj; 153 time_offset -= time_adj;
161 tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE); 154 tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE);
162 155
@@ -200,7 +193,7 @@ void __attribute__ ((weak)) notify_arch_cmos_timer(void)
200int do_adjtimex(struct timex *txc) 193int do_adjtimex(struct timex *txc)
201{ 194{
202 long ltemp, mtemp, save_adjust; 195 long ltemp, mtemp, save_adjust;
203 s64 freq_adj; 196 s64 freq_adj, temp64;
204 int result; 197 int result;
205 198
206 /* In order to modify anything, you gotta be super-user! */ 199 /* In order to modify anything, you gotta be super-user! */
@@ -270,7 +263,7 @@ int do_adjtimex(struct timex *txc)
270 result = -EINVAL; 263 result = -EINVAL;
271 goto leave; 264 goto leave;
272 } 265 }
273 time_constant = txc->constant; 266 time_constant = min(txc->constant + 4, (long)MAXTC);
274 } 267 }
275 268
276 if (txc->modes & ADJ_OFFSET) { /* values checked earlier */ 269 if (txc->modes & ADJ_OFFSET) { /* values checked earlier */
@@ -298,26 +291,20 @@ int do_adjtimex(struct timex *txc)
298 time_reftime = xtime.tv_sec; 291 time_reftime = xtime.tv_sec;
299 mtemp = xtime.tv_sec - time_reftime; 292 mtemp = xtime.tv_sec - time_reftime;
300 time_reftime = xtime.tv_sec; 293 time_reftime = xtime.tv_sec;
301 freq_adj = 0; 294
302 if (time_status & STA_FLL) { 295 freq_adj = (s64)time_offset * mtemp;
303 if (mtemp >= MINSEC) { 296 freq_adj = shift_right(freq_adj, time_constant * 2 +
304 freq_adj = (s64)time_offset << (SHIFT_NSEC - SHIFT_KH); 297 (SHIFT_PLL + 2) * 2 - SHIFT_NSEC);
305 if (time_offset < 0) { 298 if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
306 freq_adj = -freq_adj; 299 temp64 = (s64)time_offset << (SHIFT_NSEC - SHIFT_FLL);
307 do_div(freq_adj, mtemp); 300 if (time_offset < 0) {
308 freq_adj = -freq_adj; 301 temp64 = -temp64;
309 } else 302 do_div(temp64, mtemp);
310 do_div(freq_adj, mtemp); 303 freq_adj -= temp64;
311 } else /* calibration interval too short (p. 12) */ 304 } else {
312 result = TIME_ERROR; 305 do_div(temp64, mtemp);
313 } else { /* PLL mode */ 306 freq_adj += temp64;
314 if (mtemp < MAXSEC) { 307 }
315 freq_adj = (s64)ltemp * mtemp;
316 freq_adj = shift_right(freq_adj,(time_constant +
317 time_constant +
318 SHIFT_KF - SHIFT_NSEC));
319 } else /* calibration interval too long (p. 12) */
320 result = TIME_ERROR;
321 } 308 }
322 freq_adj += time_freq; 309 freq_adj += time_freq;
323 freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC); 310 freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC);