Skip to content

Commit eea83d8

Browse files
Roman Zippeltorvalds
authored andcommitted
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 <[email protected]> Cc: john stultz <[email protected]> Cc: Thomas Gleixner <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent ee9851b commit eea83d8

File tree

2 files changed

+56
-47
lines changed

2 files changed

+56
-47
lines changed

include/linux/timex.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858

5959
#include <asm/param.h>
6060

61+
#define NTP_API 4 /* NTP API version */
62+
6163
/*
6264
* SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
6365
* for a slightly underdamped convergence characteristic. SHIFT_KH
@@ -135,6 +137,8 @@ struct timex {
135137
#define ADJ_ESTERROR 0x0008 /* estimated time error */
136138
#define ADJ_STATUS 0x0010 /* clock status */
137139
#define ADJ_TIMECONST 0x0020 /* pll time constant */
140+
#define ADJ_MICRO 0x1000 /* select microsecond resolution */
141+
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
138142
#define ADJ_TICK 0x4000 /* tick value */
139143
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
140144
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
@@ -146,8 +150,6 @@ struct timex {
146150
#define MOD_ESTERROR ADJ_ESTERROR
147151
#define MOD_STATUS ADJ_STATUS
148152
#define MOD_TIMECONST ADJ_TIMECONST
149-
#define MOD_CLKB ADJ_TICK
150-
#define MOD_CLKA ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */
151153

152154

153155
/*
@@ -169,9 +171,13 @@ struct timex {
169171
#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
170172

171173
#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
174+
#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */
175+
#define STA_MODE 0x4000 /* mode (0 = PLL, 1 = FLL) (ro) */
176+
#define STA_CLK 0x8000 /* clock source (0 = A, 1 = B) (ro) */
172177

178+
/* read-only bits */
173179
#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
174-
STA_PPSERROR | STA_CLOCKERR) /* read-only bits */
180+
STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK)
175181

176182
/*
177183
* Clock states (time_state)

kernel/time/ntp.c

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ static void ntp_update_offset(long offset)
6565
if (!(time_status & STA_PLL))
6666
return;
6767

68-
time_offset = offset * NSEC_PER_USEC;
68+
time_offset = offset;
69+
if (!(time_status & STA_NANO))
70+
time_offset *= NSEC_PER_USEC;
6971

7072
/*
7173
* Scale the phase adjustment and
@@ -86,8 +88,11 @@ static void ntp_update_offset(long offset)
8688
freq_adj = time_offset * mtemp;
8789
freq_adj = shift_right(freq_adj, time_constant * 2 +
8890
(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)) {
9093
freq_adj += div_s64(time_offset << (SHIFT_NSEC - SHIFT_FLL), mtemp);
94+
time_status |= STA_MODE;
95+
}
9196
freq_adj += time_freq;
9297
freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC);
9398
time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC);
@@ -272,6 +277,7 @@ static inline void notify_cmos_timer(void) { }
272277
*/
273278
int do_adjtimex(struct timex *txc)
274279
{
280+
struct timespec ts;
275281
long save_adjust;
276282
int result;
277283

@@ -282,69 +288,58 @@ int do_adjtimex(struct timex *txc)
282288
/* Now we validate the data before disabling interrupts */
283289

284290
if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) {
285-
/* singleshot must not be used with any other mode bits */
286-
if (txc->modes != ADJ_OFFSET_SINGLESHOT &&
287-
txc->modes != ADJ_OFFSET_SS_READ)
291+
/* singleshot must not be used with any other mode bits */
292+
if (txc->modes & ~ADJ_OFFSET_SS_READ)
288293
return -EINVAL;
289294
}
290295

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-
296296
/* if the quartz is off by more than 10% something is VERY wrong ! */
297297
if (txc->modes & ADJ_TICK)
298298
if (txc->tick < 900000/USER_HZ ||
299299
txc->tick > 1100000/USER_HZ)
300300
return -EINVAL;
301301

302302
write_seqlock_irq(&xtime_lock);
303-
result = time_state; /* mostly `TIME_OK' */
304303

305304
/* Save for later - semantics of adjtime is to return old value */
306305
save_adjust = time_adjust;
307306

308-
#if 0 /* STA_CLOCKERR is never set yet */
309-
time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
310-
#endif
311307
/* If there are input parameters, then process them */
312308
if (txc->modes) {
313-
if (txc->modes & ADJ_STATUS) /* only set allowed bits */
314-
time_status = (txc->status & ~STA_RONLY) |
315-
(time_status & STA_RONLY);
309+
if (txc->modes & ADJ_STATUS) {
310+
if ((time_status & STA_PLL) &&
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;
316324

317325
if (txc->modes & ADJ_FREQUENCY) {
318-
if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
319-
result = -EINVAL;
320-
goto leave;
321-
}
322-
time_freq = ((s64)txc->freq * NSEC_PER_USEC)
326+
time_freq = min(txc->freq, MAXFREQ);
327+
time_freq = min(time_freq, -MAXFREQ);
328+
time_freq = ((s64)time_freq * NSEC_PER_USEC)
323329
>> (SHIFT_USEC - SHIFT_NSEC);
324330
}
325331

326-
if (txc->modes & ADJ_MAXERROR) {
327-
if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
328-
result = -EINVAL;
329-
goto leave;
330-
}
332+
if (txc->modes & ADJ_MAXERROR)
331333
time_maxerror = txc->maxerror;
332-
}
333-
334-
if (txc->modes & ADJ_ESTERROR) {
335-
if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
336-
result = -EINVAL;
337-
goto leave;
338-
}
334+
if (txc->modes & ADJ_ESTERROR)
339335
time_esterror = txc->esterror;
340-
}
341336

342337
if (txc->modes & ADJ_TIMECONST) {
343-
if (txc->constant < 0) { /* NTP v4 uses values > 6 */
344-
result = -EINVAL;
345-
goto leave;
346-
}
347-
time_constant = min(txc->constant + 4, (long)MAXTC);
338+
time_constant = txc->constant;
339+
if (!(time_status & STA_NANO))
340+
time_constant += 4;
341+
time_constant = min(time_constant, (long)MAXTC);
342+
time_constant = max(time_constant, 0l);
348343
}
349344

350345
if (txc->modes & ADJ_OFFSET) {
@@ -360,16 +355,20 @@ int do_adjtimex(struct timex *txc)
360355
if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
361356
ntp_update_frequency();
362357
}
363-
leave:
358+
359+
result = time_state; /* mostly `TIME_OK' */
364360
if (time_status & (STA_UNSYNC|STA_CLOCKERR))
365361
result = TIME_ERROR;
366362

367363
if ((txc->modes == ADJ_OFFSET_SINGLESHOT) ||
368364
(txc->modes == ADJ_OFFSET_SS_READ))
369365
txc->offset = save_adjust;
370-
else
366+
else {
371367
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+
}
373372
txc->freq = (time_freq / NSEC_PER_USEC) <<
374373
(SHIFT_USEC - SHIFT_NSEC);
375374
txc->maxerror = time_maxerror;
@@ -391,7 +390,11 @@ int do_adjtimex(struct timex *txc)
391390
txc->stbcnt = 0;
392391
write_sequnlock_irq(&xtime_lock);
393392

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

396399
notify_cmos_timer();
397400

0 commit comments

Comments
 (0)