Blame view

kernel/time/ntp.c 23 KB
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
1
  /*
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
2
3
4
5
6
7
   * NTP state machine interfaces and logic.
   *
   * This code was mainly moved from kernel/timer.c and kernel/time.c
   * Please see those files for relevant copyright info and historical
   * changelogs.
   */
aa0ac3651   Alexey Dobriyan   Remove capability...
8
  #include <linux/capability.h>
7dffa3c67   Roman Zippel   ntp: handle leap ...
9
  #include <linux/clocksource.h>
eb3f938fd   Maciej W. Rozycki   ntp: let update_p...
10
  #include <linux/workqueue.h>
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
11
12
13
14
15
16
  #include <linux/hrtimer.h>
  #include <linux/jiffies.h>
  #include <linux/math64.h>
  #include <linux/timex.h>
  #include <linux/time.h>
  #include <linux/mm.h>
025b40abe   Alexander Gordeev   ntp: add hardpps ...
17
  #include <linux/module.h>
023f333a9   Jason Gunthorpe   NTP: Add a CONFIG...
18
  #include <linux/rtc.h>
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
19

e2830b5c1   Torben Hohn   time: Make do_tim...
20
  #include "tick-internal.h"
aa6f9c595   John Stultz   ntp: Move do_adjt...
21
  #include "ntp_internal.h"
e2830b5c1   Torben Hohn   time: Make do_tim...
22

b0ee75561   Roman Zippel   [PATCH] ntp: add ...
23
  /*
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
24
   * NTP timekeeping variables:
a076b2146   John Stultz   ntp: Remove ntp_l...
25
26
   *
   * Note: All of the NTP state is protected by the timekeeping locks.
b0ee75561   Roman Zippel   [PATCH] ntp: add ...
27
   */
b0ee75561   Roman Zippel   [PATCH] ntp: add ...
28

bd3312681   John Stultz   ntp: Add ntp_lock...
29

53bbfa9e9   Ingo Molnar   time: ntp: clean ...
30
31
  /* USER_HZ period (usecs): */
  unsigned long			tick_usec = TICK_USEC;
02ab20ae3   John Stultz   time/jiffies: Ren...
32
  /* SHIFTED_HZ period (nsecs): */
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
33
  unsigned long			tick_nsec;
7dffa3c67   Roman Zippel   ntp: handle leap ...
34

ea7cf49a7   John Stultz   ntp: Access tick_...
35
  static u64			tick_length;
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
36
  static u64			tick_length_base;
bbd126769   Ingo Molnar   time: ntp: simpli...
37
  #define MAX_TICKADJ		500LL		/* usecs */
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
38
  #define MAX_TICKADJ_SCALED \
bbd126769   Ingo Molnar   time: ntp: simpli...
39
  	(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
40
41
42
43
  
  /*
   * phase-lock loop variables
   */
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
44
45
46
47
48
49
50
51
52
  
  /*
   * clock synchronization status
   *
   * (TIME_ERROR prevents overwriting the CMOS clock)
   */
  static int			time_state = TIME_OK;
  
  /* clock status bits:							*/
8357929e6   John Stultz   ntp: Cleanup timex.h
53
  static int			time_status = STA_UNSYNC;
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
54

53bbfa9e9   Ingo Molnar   time: ntp: clean ...
55
56
57
58
59
60
61
  /* time adjustment (nsecs):						*/
  static s64			time_offset;
  
  /* pll time constant:							*/
  static long			time_constant = 2;
  
  /* maximum error (usecs):						*/
1f5b8f8a2   John Stultz   ntp: Make time_es...
62
  static long			time_maxerror = NTP_PHASE_LIMIT;
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
63
64
  
  /* estimated error (usecs):						*/
1f5b8f8a2   John Stultz   ntp: Make time_es...
65
  static long			time_esterror = NTP_PHASE_LIMIT;
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
66
67
68
69
70
71
  
  /* frequency offset (scaled nsecs/secs):				*/
  static s64			time_freq;
  
  /* time at last adjustment (secs):					*/
  static long			time_reftime;
e1292ba16   John Stultz   ntp: Make time_ad...
72
  static long			time_adjust;
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
73

069569e02   Ingo Molnar   time: ntp: simpli...
74
75
  /* constant (boot-param configurable) NTP tick adjustment (upscaled)	*/
  static s64			ntp_tick_adj;
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
76

025b40abe   Alexander Gordeev   ntp: add hardpps ...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  #ifdef CONFIG_NTP_PPS
  
  /*
   * The following variables are used when a pulse-per-second (PPS) signal
   * is available. They establish the engineering parameters of the clock
   * discipline loop when controlled by the PPS signal.
   */
  #define PPS_VALID	10	/* PPS signal watchdog max (s) */
  #define PPS_POPCORN	4	/* popcorn spike threshold (shift) */
  #define PPS_INTMIN	2	/* min freq interval (s) (shift) */
  #define PPS_INTMAX	8	/* max freq interval (s) (shift) */
  #define PPS_INTCOUNT	4	/* number of consecutive good intervals to
  				   increase pps_shift or consecutive bad
  				   intervals to decrease it */
  #define PPS_MAXWANDER	100000	/* max PPS freq wander (ns/s) */
  
  static int pps_valid;		/* signal watchdog counter */
  static long pps_tf[3];		/* phase median filter */
  static long pps_jitter;		/* current jitter (ns) */
  static struct timespec pps_fbase; /* beginning of the last freq interval */
  static int pps_shift;		/* current interval duration (s) (shift) */
  static int pps_intcnt;		/* interval counter */
  static s64 pps_freq;		/* frequency offset (scaled ns/s) */
  static long pps_stabil;		/* current stability (scaled ns/s) */
  
  /*
   * PPS signal quality monitors
   */
  static long pps_calcnt;		/* calibration intervals */
  static long pps_jitcnt;		/* jitter limit exceeded */
  static long pps_stbcnt;		/* stability limit exceeded */
  static long pps_errcnt;		/* calibration errors */
  
  
  /* PPS kernel consumer compensates the whole phase error immediately.
   * Otherwise, reduce the offset by a fixed factor times the time constant.
   */
  static inline s64 ntp_offset_chunk(s64 offset)
  {
  	if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)
  		return offset;
  	else
  		return shift_right(offset, SHIFT_PLL + time_constant);
  }
  
  static inline void pps_reset_freq_interval(void)
  {
  	/* the PPS calibration interval may end
  	   surprisingly early */
  	pps_shift = PPS_INTMIN;
  	pps_intcnt = 0;
  }
  
  /**
   * pps_clear - Clears the PPS state variables
025b40abe   Alexander Gordeev   ntp: add hardpps ...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
   */
  static inline void pps_clear(void)
  {
  	pps_reset_freq_interval();
  	pps_tf[0] = 0;
  	pps_tf[1] = 0;
  	pps_tf[2] = 0;
  	pps_fbase.tv_sec = pps_fbase.tv_nsec = 0;
  	pps_freq = 0;
  }
  
  /* Decrease pps_valid to indicate that another second has passed since
   * the last PPS signal. When it reaches 0, indicate that PPS signal is
   * missing.
025b40abe   Alexander Gordeev   ntp: add hardpps ...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
   */
  static inline void pps_dec_valid(void)
  {
  	if (pps_valid > 0)
  		pps_valid--;
  	else {
  		time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
  				 STA_PPSWANDER | STA_PPSERROR);
  		pps_clear();
  	}
  }
  
  static inline void pps_set_freq(s64 freq)
  {
  	pps_freq = freq;
  }
  
  static inline int is_error_status(int status)
  {
  	return (time_status & (STA_UNSYNC|STA_CLOCKERR))
  		/* PPS signal lost when either PPS time or
  		 * PPS frequency synchronization requested
  		 */
  		|| ((time_status & (STA_PPSFREQ|STA_PPSTIME))
  			&& !(time_status & STA_PPSSIGNAL))
  		/* PPS jitter exceeded when
  		 * PPS time synchronization requested */
  		|| ((time_status & (STA_PPSTIME|STA_PPSJITTER))
  			== (STA_PPSTIME|STA_PPSJITTER))
  		/* PPS wander exceeded or calibration error when
  		 * PPS frequency synchronization requested
  		 */
  		|| ((time_status & STA_PPSFREQ)
  			&& (time_status & (STA_PPSWANDER|STA_PPSERROR)));
  }
  
  static inline void pps_fill_timex(struct timex *txc)
  {
  	txc->ppsfreq	   = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) *
  					 PPM_SCALE_INV, NTP_SCALE_SHIFT);
  	txc->jitter	   = pps_jitter;
  	if (!(time_status & STA_NANO))
  		txc->jitter /= NSEC_PER_USEC;
  	txc->shift	   = pps_shift;
  	txc->stabil	   = pps_stabil;
  	txc->jitcnt	   = pps_jitcnt;
  	txc->calcnt	   = pps_calcnt;
  	txc->errcnt	   = pps_errcnt;
  	txc->stbcnt	   = pps_stbcnt;
  }
  
  #else /* !CONFIG_NTP_PPS */
  
  static inline s64 ntp_offset_chunk(s64 offset)
  {
  	return shift_right(offset, SHIFT_PLL + time_constant);
  }
  
  static inline void pps_reset_freq_interval(void) {}
  static inline void pps_clear(void) {}
  static inline void pps_dec_valid(void) {}
  static inline void pps_set_freq(s64 freq) {}
  
  static inline int is_error_status(int status)
  {
  	return status & (STA_UNSYNC|STA_CLOCKERR);
  }
  
  static inline void pps_fill_timex(struct timex *txc)
  {
  	/* PPS is not implemented, so these are zero */
  	txc->ppsfreq	   = 0;
  	txc->jitter	   = 0;
  	txc->shift	   = 0;
  	txc->stabil	   = 0;
  	txc->jitcnt	   = 0;
  	txc->calcnt	   = 0;
  	txc->errcnt	   = 0;
  	txc->stbcnt	   = 0;
  }
  
  #endif /* CONFIG_NTP_PPS */
8357929e6   John Stultz   ntp: Cleanup timex.h
228
229
230
231
232
233
234
235
236
  
  /**
   * ntp_synced - Returns 1 if the NTP status is not UNSYNC
   *
   */
  static inline int ntp_synced(void)
  {
  	return !(time_status & STA_UNSYNC);
  }
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
237
238
239
  /*
   * NTP methods:
   */
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
240

9ce616aae   Ingo Molnar   time: ntp: clean ...
241
242
243
244
  /*
   * Update (tick_length, tick_length_base, tick_nsec), based
   * on (tick_usec, ntp_tick_adj, time_freq):
   */
70bc42f90   Adrian Bunk   [PATCH] kernel/ti...
245
246
  static void ntp_update_frequency(void)
  {
9ce616aae   Ingo Molnar   time: ntp: clean ...
247
  	u64 second_length;
bc26c31d4   Ingo Molnar   time: ntp: refact...
248
  	u64 new_base;
9ce616aae   Ingo Molnar   time: ntp: clean ...
249
250
251
  
  	second_length		 = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)
  						<< NTP_SCALE_SHIFT;
069569e02   Ingo Molnar   time: ntp: simpli...
252
  	second_length		+= ntp_tick_adj;
9ce616aae   Ingo Molnar   time: ntp: clean ...
253
  	second_length		+= time_freq;
70bc42f90   Adrian Bunk   [PATCH] kernel/ti...
254

9ce616aae   Ingo Molnar   time: ntp: clean ...
255
  	tick_nsec		 = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
bc26c31d4   Ingo Molnar   time: ntp: refact...
256
  	new_base		 = div_u64(second_length, NTP_INTERVAL_FREQ);
fdcedf7b7   John Stultz   time: apply NTP f...
257
258
259
  
  	/*
  	 * Don't wait for the next second_overflow, apply
bc26c31d4   Ingo Molnar   time: ntp: refact...
260
  	 * the change to the tick length immediately:
fdcedf7b7   John Stultz   time: apply NTP f...
261
  	 */
bc26c31d4   Ingo Molnar   time: ntp: refact...
262
263
  	tick_length		+= new_base - tick_length_base;
  	tick_length_base	 = new_base;
70bc42f90   Adrian Bunk   [PATCH] kernel/ti...
264
  }
478b7aab1   Ingo Molnar   time: ntp: simpli...
265
  static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
f939890b6   Ingo Molnar   time: ntp: refact...
266
267
268
269
  {
  	time_status &= ~STA_MODE;
  
  	if (secs < MINSEC)
478b7aab1   Ingo Molnar   time: ntp: simpli...
270
  		return 0;
f939890b6   Ingo Molnar   time: ntp: refact...
271
272
  
  	if (!(time_status & STA_FLL) && (secs <= MAXSEC))
478b7aab1   Ingo Molnar   time: ntp: simpli...
273
  		return 0;
f939890b6   Ingo Molnar   time: ntp: refact...
274

f939890b6   Ingo Molnar   time: ntp: refact...
275
  	time_status |= STA_MODE;
a078c6d0e   Sasha Levin   ntp: Fix integer ...
276
  	return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);
f939890b6   Ingo Molnar   time: ntp: refact...
277
  }
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
278
279
  static void ntp_update_offset(long offset)
  {
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
280
  	s64 freq_adj;
f939890b6   Ingo Molnar   time: ntp: refact...
281
282
  	s64 offset64;
  	long secs;
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
283
284
285
  
  	if (!(time_status & STA_PLL))
  		return;
eea83d896   Roman Zippel   ntp: NTP4 user sp...
286
  	if (!(time_status & STA_NANO))
9f14f669d   Roman Zippel   ntp: increase tim...
287
  		offset *= NSEC_PER_USEC;
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
288
289
290
291
292
  
  	/*
  	 * Scale the phase adjustment and
  	 * clamp to the operating range.
  	 */
9f14f669d   Roman Zippel   ntp: increase tim...
293
294
  	offset = min(offset, MAXPHASE);
  	offset = max(offset, -MAXPHASE);
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
295
296
297
298
299
  
  	/*
  	 * Select how the frequency is to be controlled
  	 * and in which mode (PLL or FLL).
  	 */
7e1b58477   John Stultz   ntp: Cleanup xtim...
300
  	secs = get_seconds() - time_reftime;
10dd31a7a   Ingo Molnar   time: ntp: fix bu...
301
  	if (unlikely(time_status & STA_FREQHOLD))
c7986acba   Ingo Molnar   time: ntp: micro-...
302
  		secs = 0;
7e1b58477   John Stultz   ntp: Cleanup xtim...
303
  	time_reftime = get_seconds();
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
304

f939890b6   Ingo Molnar   time: ntp: refact...
305
  	offset64    = offset;
8af3c153b   Miroslav Lichvar   ntp: Clamp PLL up...
306
  	freq_adj    = ntp_update_offset_fll(offset64, secs);
f939890b6   Ingo Molnar   time: ntp: refact...
307

8af3c153b   Miroslav Lichvar   ntp: Clamp PLL up...
308
309
310
311
312
313
314
315
316
317
  	/*
  	 * Clamp update interval to reduce PLL gain with low
  	 * sampling rate (e.g. intermittent network connection)
  	 * to avoid instability.
  	 */
  	if (unlikely(secs > 1 << (SHIFT_PLL + 1 + time_constant)))
  		secs = 1 << (SHIFT_PLL + 1 + time_constant);
  
  	freq_adj    += (offset64 * secs) <<
  			(NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant));
f939890b6   Ingo Molnar   time: ntp: refact...
318
319
320
321
322
323
  
  	freq_adj    = min(freq_adj + time_freq, MAXFREQ_SCALED);
  
  	time_freq   = max(freq_adj, -MAXFREQ_SCALED);
  
  	time_offset = div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
324
  }
b0ee75561   Roman Zippel   [PATCH] ntp: add ...
325
326
  /**
   * ntp_clear - Clears the NTP state variables
b0ee75561   Roman Zippel   [PATCH] ntp: add ...
327
328
329
   */
  void ntp_clear(void)
  {
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
330
331
332
333
  	time_adjust	= 0;		/* stop active adjtime() */
  	time_status	|= STA_UNSYNC;
  	time_maxerror	= NTP_PHASE_LIMIT;
  	time_esterror	= NTP_PHASE_LIMIT;
b0ee75561   Roman Zippel   [PATCH] ntp: add ...
334
335
  
  	ntp_update_frequency();
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
336
337
  	tick_length	= tick_length_base;
  	time_offset	= 0;
025b40abe   Alexander Gordeev   ntp: add hardpps ...
338
339
340
  
  	/* Clear PPS state variables */
  	pps_clear();
b0ee75561   Roman Zippel   [PATCH] ntp: add ...
341
  }
ea7cf49a7   John Stultz   ntp: Access tick_...
342
343
344
  
  u64 ntp_tick_length(void)
  {
a076b2146   John Stultz   ntp: Remove ntp_l...
345
  	return tick_length;
ea7cf49a7   John Stultz   ntp: Access tick_...
346
  }
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
347
  /*
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
348
349
350
351
352
353
354
355
   * this routine handles the overflow of the microsecond field
   *
   * The tricky bits of code to handle the accurate clock support
   * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
   * They were originally developed for SUN and DEC kernels.
   * All the kudos should go to Dave for this stuff.
   *
   * Also handles leap second processing, and returns leap offset
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
356
   */
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
357
  int second_overflow(unsigned long secs)
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
358
  {
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
359
  	s64 delta;
bd3312681   John Stultz   ntp: Add ntp_lock...
360
  	int leap = 0;
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
361
362
363
364
365
366
  
  	/*
  	 * Leap second processing. If in leap-insert state at the end of the
  	 * day, the system clock is set back one second; if in leap-delete
  	 * state, the system clock is set ahead one second.
  	 */
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
367
368
  	switch (time_state) {
  	case TIME_OK:
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
369
370
371
372
  		if (time_status & STA_INS)
  			time_state = TIME_INS;
  		else if (time_status & STA_DEL)
  			time_state = TIME_DEL;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
373
374
  		break;
  	case TIME_INS:
6b1859dba   John Stultz   ntp: Fix STA_INS/...
375
376
377
  		if (!(time_status & STA_INS))
  			time_state = TIME_OK;
  		else if (secs % 86400 == 0) {
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
378
379
380
381
382
383
  			leap = -1;
  			time_state = TIME_OOP;
  			printk(KERN_NOTICE
  				"Clock: inserting leap second 23:59:60 UTC
  ");
  		}
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
384
385
  		break;
  	case TIME_DEL:
6b1859dba   John Stultz   ntp: Fix STA_INS/...
386
387
388
  		if (!(time_status & STA_DEL))
  			time_state = TIME_OK;
  		else if ((secs + 1) % 86400 == 0) {
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
389
  			leap = 1;
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
390
391
392
393
394
  			time_state = TIME_WAIT;
  			printk(KERN_NOTICE
  				"Clock: deleting leap second 23:59:59 UTC
  ");
  		}
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
395
396
397
  		break;
  	case TIME_OOP:
  		time_state = TIME_WAIT;
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
398
  		break;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
399
400
  	case TIME_WAIT:
  		if (!(time_status & (STA_INS | STA_DEL)))
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
401
  			time_state = TIME_OK;
7dffa3c67   Roman Zippel   ntp: handle leap ...
402
403
  		break;
  	}
bd3312681   John Stultz   ntp: Add ntp_lock...
404

7dffa3c67   Roman Zippel   ntp: handle leap ...
405
406
407
408
409
410
  
  	/* Bump the maxerror field */
  	time_maxerror += MAXFREQ / NSEC_PER_USEC;
  	if (time_maxerror > NTP_PHASE_LIMIT) {
  		time_maxerror = NTP_PHASE_LIMIT;
  		time_status |= STA_UNSYNC;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
411
  	}
025b40abe   Alexander Gordeev   ntp: add hardpps ...
412
  	/* Compute the phase adjustment for the next second */
39854fe8c   Ingo Molnar   time: ntp: clean ...
413
  	tick_length	 = tick_length_base;
025b40abe   Alexander Gordeev   ntp: add hardpps ...
414
  	delta		 = ntp_offset_chunk(time_offset);
39854fe8c   Ingo Molnar   time: ntp: clean ...
415
416
  	time_offset	-= delta;
  	tick_length	+= delta;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
417

025b40abe   Alexander Gordeev   ntp: add hardpps ...
418
419
  	/* Check PPS signal */
  	pps_dec_valid();
3c972c244   Ingo Molnar   time: ntp: simpli...
420
  	if (!time_adjust)
bd3312681   John Stultz   ntp: Add ntp_lock...
421
  		goto out;
3c972c244   Ingo Molnar   time: ntp: simpli...
422
423
424
425
  
  	if (time_adjust > MAX_TICKADJ) {
  		time_adjust -= MAX_TICKADJ;
  		tick_length += MAX_TICKADJ_SCALED;
bd3312681   John Stultz   ntp: Add ntp_lock...
426
  		goto out;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
427
  	}
3c972c244   Ingo Molnar   time: ntp: simpli...
428
429
430
431
  
  	if (time_adjust < -MAX_TICKADJ) {
  		time_adjust += MAX_TICKADJ;
  		tick_length -= MAX_TICKADJ_SCALED;
bd3312681   John Stultz   ntp: Add ntp_lock...
432
  		goto out;
3c972c244   Ingo Molnar   time: ntp: simpli...
433
434
435
436
437
  	}
  
  	tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
  							 << NTP_SCALE_SHIFT;
  	time_adjust = 0;
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
438

bd3312681   John Stultz   ntp: Add ntp_lock...
439
  out:
6b43ae8a6   John Stultz   ntp: Fix leap-sec...
440
  	return leap;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
441
  }
023f333a9   Jason Gunthorpe   NTP: Add a CONFIG...
442
  #if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
eb3f938fd   Maciej W. Rozycki   ntp: let update_p...
443
  static void sync_cmos_clock(struct work_struct *work);
82644459c   Thomas Gleixner   NTP: move the cmo...
444

eb3f938fd   Maciej W. Rozycki   ntp: let update_p...
445
  static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
82644459c   Thomas Gleixner   NTP: move the cmo...
446

eb3f938fd   Maciej W. Rozycki   ntp: let update_p...
447
  static void sync_cmos_clock(struct work_struct *work)
82644459c   Thomas Gleixner   NTP: move the cmo...
448
449
450
451
452
453
454
455
456
457
  {
  	struct timespec now, next;
  	int fail = 1;
  
  	/*
  	 * If we have an externally synchronized Linux clock, then update
  	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
  	 * called as close as possible to 500 ms before the new second starts.
  	 * This code is run on a timer.  If the clock is set, that timer
  	 * may not expire at the correct time.  Thus, we adjust...
a97ad0c4b   Miroslav Lichvar   ntp: Make periodi...
458
  	 * We want the clock to be within a couple of ticks from the target.
82644459c   Thomas Gleixner   NTP: move the cmo...
459
  	 */
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
460
  	if (!ntp_synced()) {
82644459c   Thomas Gleixner   NTP: move the cmo...
461
462
463
464
465
  		/*
  		 * Not synced, exit, do not restart a timer (if one is
  		 * running, let it run out).
  		 */
  		return;
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
466
  	}
82644459c   Thomas Gleixner   NTP: move the cmo...
467
468
  
  	getnstimeofday(&now);
a97ad0c4b   Miroslav Lichvar   ntp: Make periodi...
469
  	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec * 5) {
84e345e4e   Prarit Bhargava   time, Fix setting...
470
  		struct timespec adjust = now;
023f333a9   Jason Gunthorpe   NTP: Add a CONFIG...
471
  		fail = -ENODEV;
84e345e4e   Prarit Bhargava   time, Fix setting...
472
473
  		if (persistent_clock_is_local)
  			adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
023f333a9   Jason Gunthorpe   NTP: Add a CONFIG...
474
  #ifdef CONFIG_GENERIC_CMOS_UPDATE
84e345e4e   Prarit Bhargava   time, Fix setting...
475
  		fail = update_persistent_clock(adjust);
023f333a9   Jason Gunthorpe   NTP: Add a CONFIG...
476
477
478
  #endif
  #ifdef CONFIG_RTC_SYSTOHC
  		if (fail == -ENODEV)
84e345e4e   Prarit Bhargava   time, Fix setting...
479
  			fail = rtc_set_ntp_time(adjust);
023f333a9   Jason Gunthorpe   NTP: Add a CONFIG...
480
481
  #endif
  	}
82644459c   Thomas Gleixner   NTP: move the cmo...
482

4ff4b9e19   Maciej W. Rozycki   ntp: fix calculat...
483
  	next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2);
82644459c   Thomas Gleixner   NTP: move the cmo...
484
485
  	if (next.tv_nsec <= 0)
  		next.tv_nsec += NSEC_PER_SEC;
023f333a9   Jason Gunthorpe   NTP: Add a CONFIG...
486
  	if (!fail || fail == -ENODEV)
82644459c   Thomas Gleixner   NTP: move the cmo...
487
488
489
490
491
492
493
494
  		next.tv_sec = 659;
  	else
  		next.tv_sec = 0;
  
  	if (next.tv_nsec >= NSEC_PER_SEC) {
  		next.tv_sec++;
  		next.tv_nsec -= NSEC_PER_SEC;
  	}
e8b175946   Shaibal Dutta   timekeeping: Move...
495
496
  	queue_delayed_work(system_power_efficient_wq,
  			   &sync_cmos_work, timespec_to_jiffies(&next));
82644459c   Thomas Gleixner   NTP: move the cmo...
497
  }
7bd360144   John Stultz   timekeeping: Fix ...
498
  void ntp_notify_cmos_timer(void)
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
499
  {
e8b175946   Shaibal Dutta   timekeeping: Move...
500
  	queue_delayed_work(system_power_efficient_wq, &sync_cmos_work, 0);
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
501
  }
82644459c   Thomas Gleixner   NTP: move the cmo...
502
  #else
7bd360144   John Stultz   timekeeping: Fix ...
503
  void ntp_notify_cmos_timer(void) { }
82644459c   Thomas Gleixner   NTP: move the cmo...
504
  #endif
80f225711   Ingo Molnar   time: ntp: refact...
505
506
507
508
509
510
  
  /*
   * Propagate a new txc->status value into the NTP state:
   */
  static inline void process_adj_status(struct timex *txc, struct timespec *ts)
  {
80f225711   Ingo Molnar   time: ntp: refact...
511
512
513
  	if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) {
  		time_state = TIME_OK;
  		time_status = STA_UNSYNC;
025b40abe   Alexander Gordeev   ntp: add hardpps ...
514
515
  		/* restart PPS frequency calibration */
  		pps_reset_freq_interval();
80f225711   Ingo Molnar   time: ntp: refact...
516
  	}
80f225711   Ingo Molnar   time: ntp: refact...
517
518
519
520
521
522
  
  	/*
  	 * If we turn on PLL adjustments then reset the
  	 * reference time to current time.
  	 */
  	if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
7e1b58477   John Stultz   ntp: Cleanup xtim...
523
  		time_reftime = get_seconds();
80f225711   Ingo Molnar   time: ntp: refact...
524

a2a5ac865   John Stultz   time: ntp: fix bu...
525
526
  	/* only set allowed bits */
  	time_status &= STA_RONLY;
80f225711   Ingo Molnar   time: ntp: refact...
527
  	time_status |= txc->status & ~STA_RONLY;
80f225711   Ingo Molnar   time: ntp: refact...
528
  }
cd5398bed   Richard Cochran   ntp: Fix a stale ...
529

a076b2146   John Stultz   ntp: Remove ntp_l...
530

cc244ddae   John Stultz   timekeeping: Move...
531
532
533
  static inline void process_adjtimex_modes(struct timex *txc,
  						struct timespec *ts,
  						s32 *time_tai)
80f225711   Ingo Molnar   time: ntp: refact...
534
535
536
537
538
539
  {
  	if (txc->modes & ADJ_STATUS)
  		process_adj_status(txc, ts);
  
  	if (txc->modes & ADJ_NANO)
  		time_status |= STA_NANO;
e96291653   Ingo Molnar   time: ntp: refact...
540

80f225711   Ingo Molnar   time: ntp: refact...
541
542
543
544
  	if (txc->modes & ADJ_MICRO)
  		time_status &= ~STA_NANO;
  
  	if (txc->modes & ADJ_FREQUENCY) {
2b9d1496e   Ingo Molnar   time: ntp: make 6...
545
  		time_freq = txc->freq * PPM_SCALE;
80f225711   Ingo Molnar   time: ntp: refact...
546
547
  		time_freq = min(time_freq, MAXFREQ_SCALED);
  		time_freq = max(time_freq, -MAXFREQ_SCALED);
025b40abe   Alexander Gordeev   ntp: add hardpps ...
548
549
  		/* update pps_freq */
  		pps_set_freq(time_freq);
80f225711   Ingo Molnar   time: ntp: refact...
550
551
552
553
  	}
  
  	if (txc->modes & ADJ_MAXERROR)
  		time_maxerror = txc->maxerror;
e96291653   Ingo Molnar   time: ntp: refact...
554

80f225711   Ingo Molnar   time: ntp: refact...
555
556
557
558
559
560
561
562
563
564
565
566
  	if (txc->modes & ADJ_ESTERROR)
  		time_esterror = txc->esterror;
  
  	if (txc->modes & ADJ_TIMECONST) {
  		time_constant = txc->constant;
  		if (!(time_status & STA_NANO))
  			time_constant += 4;
  		time_constant = min(time_constant, (long)MAXTC);
  		time_constant = max(time_constant, 0l);
  	}
  
  	if (txc->modes & ADJ_TAI && txc->constant > 0)
cc244ddae   John Stultz   timekeeping: Move...
567
  		*time_tai = txc->constant;
80f225711   Ingo Molnar   time: ntp: refact...
568
569
570
  
  	if (txc->modes & ADJ_OFFSET)
  		ntp_update_offset(txc->offset);
e96291653   Ingo Molnar   time: ntp: refact...
571

80f225711   Ingo Molnar   time: ntp: refact...
572
573
574
575
576
577
  	if (txc->modes & ADJ_TICK)
  		tick_usec = txc->tick;
  
  	if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
  		ntp_update_frequency();
  }
ad460967a   John Stultz   ntp: Split out ti...
578
579
580
581
  
  
  /**
   * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
582
   */
ad460967a   John Stultz   ntp: Split out ti...
583
  int ntp_validate_timex(struct timex *txc)
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
584
  {
916c7a855   Roman Zippel   ntp: fix ADJ_OFFS...
585
  	if (txc->modes & ADJ_ADJTIME) {
eea83d896   Roman Zippel   ntp: NTP4 user sp...
586
  		/* singleshot must not be used with any other mode bits */
916c7a855   Roman Zippel   ntp: fix ADJ_OFFS...
587
  		if (!(txc->modes & ADJ_OFFSET_SINGLESHOT))
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
588
  			return -EINVAL;
916c7a855   Roman Zippel   ntp: fix ADJ_OFFS...
589
590
591
592
593
594
595
  		if (!(txc->modes & ADJ_OFFSET_READONLY) &&
  		    !capable(CAP_SYS_TIME))
  			return -EPERM;
  	} else {
  		/* In order to modify anything, you gotta be super-user! */
  		 if (txc->modes && !capable(CAP_SYS_TIME))
  			return -EPERM;
53bbfa9e9   Ingo Molnar   time: ntp: clean ...
596
597
598
599
  		/*
  		 * if the quartz is off by more than 10% then
  		 * something is VERY wrong!
  		 */
916c7a855   Roman Zippel   ntp: fix ADJ_OFFS...
600
601
602
  		if (txc->modes & ADJ_TICK &&
  		    (txc->tick <  900000/USER_HZ ||
  		     txc->tick > 1100000/USER_HZ))
e96291653   Ingo Molnar   time: ntp: refact...
603
  			return -EINVAL;
52bfb3605   John Stultz   time: add ADJ_OFF...
604
  	}
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
605

ad460967a   John Stultz   ntp: Split out ti...
606
607
608
609
610
611
612
613
614
615
616
  	if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
  		return -EPERM;
  
  	return 0;
  }
  
  
  /*
   * adjtimex mainly allows reading (and writing, if superuser) of
   * kernel time-keeping variables. used by xntpd.
   */
87ace39b7   John Stultz   ntp: Rework do_ad...
617
  int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
ad460967a   John Stultz   ntp: Split out ti...
618
  {
ad460967a   John Stultz   ntp: Split out ti...
619
  	int result;
916c7a855   Roman Zippel   ntp: fix ADJ_OFFS...
620
621
622
623
624
625
626
627
628
  	if (txc->modes & ADJ_ADJTIME) {
  		long save_adjust = time_adjust;
  
  		if (!(txc->modes & ADJ_OFFSET_READONLY)) {
  			/* adjtime() is independent from ntp_adjtime() */
  			time_adjust = txc->offset;
  			ntp_update_frequency();
  		}
  		txc->offset = save_adjust;
e96291653   Ingo Molnar   time: ntp: refact...
629
  	} else {
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
630

e96291653   Ingo Molnar   time: ntp: refact...
631
632
  		/* If there are input parameters, then process them: */
  		if (txc->modes)
87ace39b7   John Stultz   ntp: Rework do_ad...
633
  			process_adjtimex_modes(txc, ts, time_tai);
eea83d896   Roman Zippel   ntp: NTP4 user sp...
634

e96291653   Ingo Molnar   time: ntp: refact...
635
  		txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
916c7a855   Roman Zippel   ntp: fix ADJ_OFFS...
636
  				  NTP_SCALE_SHIFT);
e96291653   Ingo Molnar   time: ntp: refact...
637
638
639
  		if (!(time_status & STA_NANO))
  			txc->offset /= NSEC_PER_USEC;
  	}
916c7a855   Roman Zippel   ntp: fix ADJ_OFFS...
640

eea83d896   Roman Zippel   ntp: NTP4 user sp...
641
  	result = time_state;	/* mostly `TIME_OK' */
025b40abe   Alexander Gordeev   ntp: add hardpps ...
642
643
  	/* check for errors */
  	if (is_error_status(time_status))
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
644
  		result = TIME_ERROR;
d40e944c2   Roman Zippel   ntp: improve adjt...
645
  	txc->freq	   = shift_right((time_freq >> PPM_SCALE_INV_SHIFT) *
2b9d1496e   Ingo Molnar   time: ntp: make 6...
646
  					 PPM_SCALE_INV, NTP_SCALE_SHIFT);
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
647
648
649
650
  	txc->maxerror	   = time_maxerror;
  	txc->esterror	   = time_esterror;
  	txc->status	   = time_status;
  	txc->constant	   = time_constant;
70bc42f90   Adrian Bunk   [PATCH] kernel/ti...
651
  	txc->precision	   = 1;
074b3b879   Roman Zippel   ntp: increase tim...
652
  	txc->tolerance	   = MAXFREQ_SCALED / PPM_SCALE;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
653
  	txc->tick	   = tick_usec;
87ace39b7   John Stultz   ntp: Rework do_ad...
654
  	txc->tai	   = *time_tai;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
655

025b40abe   Alexander Gordeev   ntp: add hardpps ...
656
657
  	/* fill PPS status fields */
  	pps_fill_timex(txc);
e96291653   Ingo Molnar   time: ntp: refact...
658

87ace39b7   John Stultz   ntp: Rework do_ad...
659
660
  	txc->time.tv_sec = ts->tv_sec;
  	txc->time.tv_usec = ts->tv_nsec;
eea83d896   Roman Zippel   ntp: NTP4 user sp...
661
662
  	if (!(time_status & STA_NANO))
  		txc->time.tv_usec /= NSEC_PER_USEC;
ee9851b21   Roman Zippel   ntp: cleanup ntp.c
663

ee9851b21   Roman Zippel   ntp: cleanup ntp.c
664
  	return result;
4c7ee8de9   John Stultz   [PATCH] NTP: Move...
665
  }
10a398d04   Roman Zippel   time: remove obso...
666

025b40abe   Alexander Gordeev   ntp: add hardpps ...
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
  #ifdef	CONFIG_NTP_PPS
  
  /* actually struct pps_normtime is good old struct timespec, but it is
   * semantically different (and it is the reason why it was invented):
   * pps_normtime.nsec has a range of ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ]
   * while timespec.tv_nsec has a range of [0, NSEC_PER_SEC) */
  struct pps_normtime {
  	__kernel_time_t	sec;	/* seconds */
  	long		nsec;	/* nanoseconds */
  };
  
  /* normalize the timestamp so that nsec is in the
     ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] interval */
  static inline struct pps_normtime pps_normalize_ts(struct timespec ts)
  {
  	struct pps_normtime norm = {
  		.sec = ts.tv_sec,
  		.nsec = ts.tv_nsec
  	};
  
  	if (norm.nsec > (NSEC_PER_SEC >> 1)) {
  		norm.nsec -= NSEC_PER_SEC;
  		norm.sec++;
  	}
  
  	return norm;
  }
  
  /* get current phase correction and jitter */
  static inline long pps_phase_filter_get(long *jitter)
  {
  	*jitter = pps_tf[0] - pps_tf[1];
  	if (*jitter < 0)
  		*jitter = -*jitter;
  
  	/* TODO: test various filters */
  	return pps_tf[0];
  }
  
  /* add the sample to the phase filter */
  static inline void pps_phase_filter_add(long err)
  {
  	pps_tf[2] = pps_tf[1];
  	pps_tf[1] = pps_tf[0];
  	pps_tf[0] = err;
  }
  
  /* decrease frequency calibration interval length.
   * It is halved after four consecutive unstable intervals.
   */
  static inline void pps_dec_freq_interval(void)
  {
  	if (--pps_intcnt <= -PPS_INTCOUNT) {
  		pps_intcnt = -PPS_INTCOUNT;
  		if (pps_shift > PPS_INTMIN) {
  			pps_shift--;
  			pps_intcnt = 0;
  		}
  	}
  }
  
  /* increase frequency calibration interval length.
   * It is doubled after four consecutive stable intervals.
   */
  static inline void pps_inc_freq_interval(void)
  {
  	if (++pps_intcnt >= PPS_INTCOUNT) {
  		pps_intcnt = PPS_INTCOUNT;
  		if (pps_shift < PPS_INTMAX) {
  			pps_shift++;
  			pps_intcnt = 0;
  		}
  	}
  }
  
  /* update clock frequency based on MONOTONIC_RAW clock PPS signal
   * timestamps
   *
   * At the end of the calibration interval the difference between the
   * first and last MONOTONIC_RAW clock timestamps divided by the length
   * of the interval becomes the frequency update. If the interval was
   * too long, the data are discarded.
   * Returns the difference between old and new frequency values.
   */
  static long hardpps_update_freq(struct pps_normtime freq_norm)
  {
  	long delta, delta_mod;
  	s64 ftemp;
  
  	/* check if the frequency interval was too long */
  	if (freq_norm.sec > (2 << pps_shift)) {
  		time_status |= STA_PPSERROR;
  		pps_errcnt++;
  		pps_dec_freq_interval();
  		pr_err("hardpps: PPSERROR: interval too long - %ld s
  ",
  				freq_norm.sec);
  		return 0;
  	}
  
  	/* here the raw frequency offset and wander (stability) is
  	 * calculated. If the wander is less than the wander threshold
  	 * the interval is increased; otherwise it is decreased.
  	 */
  	ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT,
  			freq_norm.sec);
  	delta = shift_right(ftemp - pps_freq, NTP_SCALE_SHIFT);
  	pps_freq = ftemp;
  	if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) {
  		pr_warning("hardpps: PPSWANDER: change=%ld
  ", delta);
  		time_status |= STA_PPSWANDER;
  		pps_stbcnt++;
  		pps_dec_freq_interval();
  	} else {	/* good sample */
  		pps_inc_freq_interval();
  	}
  
  	/* the stability metric is calculated as the average of recent
  	 * frequency changes, but is used only for performance
  	 * monitoring
  	 */
  	delta_mod = delta;
  	if (delta_mod < 0)
  		delta_mod = -delta_mod;
  	pps_stabil += (div_s64(((s64)delta_mod) <<
  				(NTP_SCALE_SHIFT - SHIFT_USEC),
  				NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN;
  
  	/* if enabled, the system clock frequency is updated */
  	if ((time_status & STA_PPSFREQ) != 0 &&
  	    (time_status & STA_FREQHOLD) == 0) {
  		time_freq = pps_freq;
  		ntp_update_frequency();
  	}
  
  	return delta;
  }
  
  /* correct REALTIME clock phase error against PPS signal */
  static void hardpps_update_phase(long error)
  {
  	long correction = -error;
  	long jitter;
  
  	/* add the sample to the median filter */
  	pps_phase_filter_add(correction);
  	correction = pps_phase_filter_get(&jitter);
  
  	/* Nominal jitter is due to PPS signal noise. If it exceeds the
  	 * threshold, the sample is discarded; otherwise, if so enabled,
  	 * the time offset is updated.
  	 */
  	if (jitter > (pps_jitter << PPS_POPCORN)) {
  		pr_warning("hardpps: PPSJITTER: jitter=%ld, limit=%ld
  ",
  		       jitter, (pps_jitter << PPS_POPCORN));
  		time_status |= STA_PPSJITTER;
  		pps_jitcnt++;
  	} else if (time_status & STA_PPSTIME) {
  		/* correct the time using the phase offset */
  		time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT,
  				NTP_INTERVAL_FREQ);
  		/* cancel running adjtime() */
  		time_adjust = 0;
  	}
  	/* update jitter */
  	pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN;
  }
  
  /*
aa6f9c595   John Stultz   ntp: Move do_adjt...
838
   * __hardpps() - discipline CPU clock oscillator to external PPS signal
025b40abe   Alexander Gordeev   ntp: add hardpps ...
839
840
841
842
843
844
845
846
847
848
   *
   * This routine is called at each PPS signal arrival in order to
   * discipline the CPU clock oscillator to the PPS signal. It takes two
   * parameters: REALTIME and MONOTONIC_RAW clock timestamps. The former
   * is used to correct clock phase error and the latter is used to
   * correct the frequency.
   *
   * This code is based on David Mills's reference nanokernel
   * implementation. It was mostly rewritten but keeps the same idea.
   */
aa6f9c595   John Stultz   ntp: Move do_adjt...
849
  void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
025b40abe   Alexander Gordeev   ntp: add hardpps ...
850
851
  {
  	struct pps_normtime pts_norm, freq_norm;
025b40abe   Alexander Gordeev   ntp: add hardpps ...
852
853
  
  	pts_norm = pps_normalize_ts(*phase_ts);
025b40abe   Alexander Gordeev   ntp: add hardpps ...
854
855
856
857
858
859
860
861
862
863
864
  	/* clear the error bits, they will be set again if needed */
  	time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
  
  	/* indicate signal presence */
  	time_status |= STA_PPSSIGNAL;
  	pps_valid = PPS_VALID;
  
  	/* when called for the first time,
  	 * just start the frequency interval */
  	if (unlikely(pps_fbase.tv_sec == 0)) {
  		pps_fbase = *raw_ts;
025b40abe   Alexander Gordeev   ntp: add hardpps ...
865
866
867
868
869
870
871
872
873
874
875
876
877
878
  		return;
  	}
  
  	/* ok, now we have a base for frequency calculation */
  	freq_norm = pps_normalize_ts(timespec_sub(*raw_ts, pps_fbase));
  
  	/* check that the signal is in the range
  	 * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */
  	if ((freq_norm.sec == 0) ||
  			(freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
  			(freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
  		time_status |= STA_PPSJITTER;
  		/* restart the frequency calibration interval */
  		pps_fbase = *raw_ts;
025b40abe   Alexander Gordeev   ntp: add hardpps ...
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
  		pr_err("hardpps: PPSJITTER: bad pulse
  ");
  		return;
  	}
  
  	/* signal is ok */
  
  	/* check if the current frequency interval is finished */
  	if (freq_norm.sec >= (1 << pps_shift)) {
  		pps_calcnt++;
  		/* restart the frequency calibration interval */
  		pps_fbase = *raw_ts;
  		hardpps_update_freq(freq_norm);
  	}
  
  	hardpps_update_phase(pts_norm.nsec);
025b40abe   Alexander Gordeev   ntp: add hardpps ...
895
  }
025b40abe   Alexander Gordeev   ntp: add hardpps ...
896
  #endif	/* CONFIG_NTP_PPS */
10a398d04   Roman Zippel   time: remove obso...
897
898
899
  static int __init ntp_tick_adj_setup(char *str)
  {
  	ntp_tick_adj = simple_strtol(str, NULL, 0);
069569e02   Ingo Molnar   time: ntp: simpli...
900
  	ntp_tick_adj <<= NTP_SCALE_SHIFT;
10a398d04   Roman Zippel   time: remove obso...
901
902
903
904
  	return 1;
  }
  
  __setup("ntp_tick_adj=", ntp_tick_adj_setup);
7dffa3c67   Roman Zippel   ntp: handle leap ...
905
906
907
908
  
  void __init ntp_init(void)
  {
  	ntp_clear();
7dffa3c67   Roman Zippel   ntp: handle leap ...
909
  }