NTP updates
Subsystems (2)
cover NTP updates
Hi,
These patches clean up the NTP code a little and add the remaining user space bits from the ntp nanokernel, so that it's e.g. now possible to enable the nanosecond resolution, which should be useful to keep time in a local network in sync (but it also needs an updated glibc/ntpd first).
I tried my best to also update the various user space APIs (e.g. compat, vsyscall), but it would be great if someone could look over it, in case I forgot something.
bye, Roman
PATCH 1/8 cleanup ntp.c
This is mostly a style cleanup of ntp.c and extracts part of do_adjtimex as ntp_update_offset(). Otherwise the functionality is still the same as before.
--- kernel/time/ntp.c | 171 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 81 deletions(-)
kernel/time/ntp.c +90 -81
@@ -35,7 +35,7 @@ static u64 tick_length, tick_length_base/* TIME_ERROR prevents overwriting the CMOS clock */ static int time_state =TIME_OK ;/* clock synchronization status */ int time_status =STA_UNSYNC ;/* clock status bits */ -static s64 time_offset;/* time adjustment (ns) */ +static s64 time_offset;/* time adjustment (ns) */ static long time_constant =2 ;/* pll time constant */ long time_maxerror =NTP_PHASE_LIMIT ;/* maximum error (us) */ long time_esterror =NTP_PHASE_LIMIT ;/* estimated error (us) */
@@ -57,6 +57,44 @@ static void ntp_update_frequency(void) tick_length_base =div_u64 (tick_length_base,NTP_INTERVAL_FREQ ); } +static void ntp_update_offset (long offset) +{ +long mtemp; +s64 freq_adj; + +if (!(time_status &STA_PLL )) +return ; + + time_offset = offset *NSEC_PER_USEC ; + +/* +* Scale the phase adjustment and +* clamp to the operating range. +*/ + time_offset =min (time_offset, (s64 )MAXPHASE *NSEC_PER_USEC ); + time_offset =max (time_offset, (s64 )-MAXPHASE *NSEC_PER_USEC ); + +/* +* Select how the frequency is to be controlled +* and in which mode (PLL or FLL). +*/ +if (time_status &STA_FREQHOLD || time_reftime ==0 ) + time_reftime = xtime.tv_sec; + mtemp = xtime.tv_sec - time_reftime; + time_reftime = xtime.tv_sec; + + freq_adj = time_offset * mtemp; + freq_adj =shift_right (freq_adj, time_constant *2 + + (SHIFT_PLL +2 ) *2 -SHIFT_NSEC ); +if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) + freq_adj +=div_s64 (time_offset << (SHIFT_NSEC -SHIFT_FLL ), mtemp); + freq_adj += time_freq; + freq_adj =min (freq_adj, (s64 )MAXFREQ_NSEC ); + time_freq =max (freq_adj, (s64)-MAXFREQ_NSEC ); + time_offset =div_s64 (time_offset,NTP_INTERVAL_FREQ ); + time_offset <<=SHIFT_UPDATE ; +} +/** * ntp_clear - Clears the NTP state variables *
@@ -131,7 +169,7 @@ void second_overflow(void)break ;case TIME_WAIT :if (!(time_status & (STA_INS |STA_DEL ))) - time_state =TIME_OK ; + time_state =TIME_OK ; }/*
@@ -234,8 +272,7 @@ static inline void notify_cmos_timer(voi*/ int do_adjtimex (struct timex *txc) { -long mtemp, save_adjust; -s64 freq_adj; +long save_adjust;int result;/* In order to modify anything, you gotta be super-user! */
@@ -272,94 +309,63 @@ int do_adjtimex(struct timex *txc) time_status &= ~STA_CLOCKERR ;/* reset STA_CLOCKERR */ #endif /* If there are input parameters, then process them */ -if (txc->modes) - { -if (txc->modes &ADJ_STATUS )/* only set allowed bits */ - time_status = (txc->status & ~STA_RONLY ) | - (time_status &STA_RONLY ); - -if (txc->modes &ADJ_FREQUENCY ) {/* p. 22 */ -if (txc->freq >MAXFREQ || txc->freq < -MAXFREQ ) { - result = -EINVAL ; - goto leave; +if (txc->modes) { +if (txc->modes &ADJ_STATUS )/* only set allowed bits */ + time_status = (txc->status & ~STA_RONLY ) | + (time_status &STA_RONLY ); + +if (txc->modes &ADJ_FREQUENCY ) { +if (txc->freq >MAXFREQ || txc->freq < -MAXFREQ ) { + result = -EINVAL ; + goto leave; + } + time_freq = ((s64 )txc->freq *NSEC_PER_USEC ) + >> (SHIFT_USEC -SHIFT_NSEC ); } - time_freq = ((s64 )txc->freq *NSEC_PER_USEC ) - >> (SHIFT_USEC -SHIFT_NSEC ); - } - -if (txc->modes &ADJ_MAXERROR ) { -if (txc->maxerror <0 || txc->maxerror >=NTP_PHASE_LIMIT ) { - result = -EINVAL ; - goto leave; + +if (txc->modes &ADJ_MAXERROR ) { +if (txc->maxerror <0 || txc->maxerror >=NTP_PHASE_LIMIT ) { + result = -EINVAL ; + goto leave; + } + time_maxerror = txc->maxerror; } - time_maxerror = txc->maxerror; - } -if (txc->modes &ADJ_ESTERROR ) { -if (txc->esterror <0 || txc->esterror >=NTP_PHASE_LIMIT ) { - result = -EINVAL ; - goto leave; +if (txc->modes &ADJ_ESTERROR ) { +if (txc->esterror <0 || txc->esterror >=NTP_PHASE_LIMIT ) { + result = -EINVAL ; + goto leave; + } + time_esterror = txc->esterror; } - time_esterror = txc->esterror; - } -if (txc->modes &ADJ_TIMECONST ) {/* p. 24 */ -if (txc->constant <0 ) {/* NTP v4 uses values > 6 */ - result = -EINVAL ; - goto leave; +if (txc->modes &ADJ_TIMECONST ) { +if (txc->constant <0 ) {/* NTP v4 uses values > 6 */ + result = -EINVAL ; + goto leave; + } + time_constant =min (txc->constant +4 , (long )MAXTC ); } - time_constant =min (txc->constant +4 , (long )MAXTC ); - } -if (txc->modes &ADJ_OFFSET ) {/* values checked earlier */ -if (txc->modes ==ADJ_OFFSET_SINGLESHOT ) { -/* adjtime() is independent from ntp_adjtime() */ - time_adjust = txc->offset; +if (txc->modes &ADJ_OFFSET ) { +if (txc->modes ==ADJ_OFFSET_SINGLESHOT ) +/* adjtime() is independent from ntp_adjtime() */ + time_adjust = txc->offset; +else +ntp_update_offset (txc->offset); } -else if (time_status &STA_PLL ) { - time_offset = txc->offset *NSEC_PER_USEC ; +if (txc->modes &ADJ_TICK ) + tick_usec = txc->tick; -/* -* Scale the phase adjustment and -* clamp to the operating range. -*/ - time_offset =min (time_offset, (s64 )MAXPHASE *NSEC_PER_USEC ); - time_offset =max (time_offset, (s64 )-MAXPHASE *NSEC_PER_USEC ); - -/* -* Select whether the frequency is to be controlled -* and in which mode (PLL or FLL). Clamp to the operating -* range. Ugly multiply/divide should be replaced someday. -*/ - -if (time_status &STA_FREQHOLD || time_reftime ==0 ) - time_reftime = xtime.tv_sec; - mtemp = xtime.tv_sec - time_reftime; - time_reftime = xtime.tv_sec; - - freq_adj = time_offset * mtemp; - freq_adj =shift_right (freq_adj, time_constant *2 + - (SHIFT_PLL +2 ) *2 -SHIFT_NSEC ); -if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) - freq_adj +=div_s64 (time_offset << (SHIFT_NSEC -SHIFT_FLL ), mtemp); - freq_adj += time_freq; - freq_adj =min (freq_adj, (s64 )MAXFREQ_NSEC ); - time_freq =max (freq_adj, (s64)-MAXFREQ_NSEC ); - time_offset =div_s64 (time_offset,NTP_INTERVAL_FREQ ); - time_offset <<=SHIFT_UPDATE ; - }/* STA_PLL */ - }/* txc->modes & ADJ_OFFSET */ -if (txc->modes &ADJ_TICK ) - tick_usec = txc->tick; - -if (txc->modes & (ADJ_TICK |ADJ_FREQUENCY |ADJ_OFFSET )) -ntp_update_frequency (); - }/* txc->modes */ -leave:if ((time_status & (STA_UNSYNC |STA_CLOCKERR )) !=0 ) +if (txc->modes & (ADJ_TICK |ADJ_FREQUENCY |ADJ_OFFSET )) +ntp_update_frequency (); + } +leave: +if (time_status & (STA_UNSYNC |STA_CLOCKERR )) result =TIME_ERROR ;if ((txc->modes ==ADJ_OFFSET_SINGLESHOT ) || - (txc->modes ==ADJ_OFFSET_SS_READ )) + (txc->modes ==ADJ_OFFSET_SS_READ )) txc->offset = save_adjust;else txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) *
@@ -384,9 +390,12 @@ leave: if ((time_status & (STA_UNSYNC|ST txc->errcnt =0 ; txc->stbcnt =0 ;write_sequnlock_irq (&xtime_lock); +do_gettimeofday (&txc->time); +notify_cmos_timer (); -return (result); + +return result; }static int __init ntp_tick_adj_setup (char *str)
Re: [PATCH 1/8] cleanup ntp.c
Quoted 6 lines · On Fri, 2008-03-14 at 19:40 +0100, [email protected] wrote:
plain text document attachment (
update_offset)
This is mostly a style cleanup ofntp.cand extracts part ofdo_adjtimexasntp_update_offset(). Otherwise the functionality is still the same as before.Signed-off-by Roman Zippel <[email protected]>
Ah crud. Ingo sent very similar changes to me a few weeks ago, and I've been too pinched for time to test and send them out.
I'll spend some time today to layer his fixes as well as my own cleanups on top.
Minor nits below:
Otherwise looks good (although I've not tested it).
-john
Quoted 18 lines
--- kernel/time/ntp.c | 171 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 81 deletions(-)Index:
linux-2.6-mm/kernel/time/ntp.c
===================================================================kernel/time/ntp.c +1
-1@@ -35,7 +35,7 @@ static u64 tick_length, tick_length_base/* TIME_ERROR prevents overwriting the CMOS clock */ static int time_state =TIME_OK ;/* clock synchronization status */ int time_status =STA_UNSYNC ;/* clock status bits */ -static s64 time_offset;/* time adjustment (ns) */ +static s64 time_offset;/* time adjustment (ns) */ static long time_constant =2 ;/* pll time constant */ long time_maxerror =NTP_PHASE_LIMIT ;/* maximum error (us) */ long time_esterror =NTP_PHASE_LIMIT ;/* estimated error (us) */
kernel/time/ntp.c static void ntp_update_frequency(void) · line 62
Quoted 6 lines
kernel/time/ntp.c +3
-0@@ -57,6 +57,44 @@ static void ntp_update_frequency(void) tick_length_base =div_u64 (tick_length_base,NTP_INTERVAL_FREQ ); } +static void ntp_update_offset (long offset) +{ +long mtemp;
Could we change this to a more descriptive name?
Maybe last_update_interval?
Quoted 212 lines
kernel/time/ntp.c +86
-80+s64 freq_adj; + +if (!(time_status &STA_PLL )) +return ; + + time_offset = offset *NSEC_PER_USEC ; + +/* +* Scale the phase adjustment and +* clamp to the operating range. +*/ + time_offset =min (time_offset, (s64 )MAXPHASE *NSEC_PER_USEC ); + time_offset =max (time_offset, (s64 )-MAXPHASE *NSEC_PER_USEC ); + +/* +* Select how the frequency is to be controlled +* and in which mode (PLL or FLL). +*/ +if (time_status &STA_FREQHOLD || time_reftime ==0 ) + time_reftime = xtime.tv_sec; + mtemp = xtime.tv_sec - time_reftime; + time_reftime = xtime.tv_sec; + + freq_adj = time_offset * mtemp; + freq_adj =shift_right (freq_adj, time_constant *2 + + (SHIFT_PLL +2 ) *2 -SHIFT_NSEC ); +if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) + freq_adj +=div_s64 (time_offset << (SHIFT_NSEC -SHIFT_FLL ), mtemp); + freq_adj += time_freq; + freq_adj =min (freq_adj, (s64 )MAXFREQ_NSEC ); + time_freq =max (freq_adj, (s64)-MAXFREQ_NSEC ); + time_offset =div_s64 (time_offset,NTP_INTERVAL_FREQ ); + time_offset <<=SHIFT_UPDATE ; +} +/** * ntp_clear - Clears the NTP state variables * @@ -131,7 +169,7 @@ void second_overflow(void)break ;case TIME_WAIT :if (!(time_status & (STA_INS |STA_DEL ))) - time_state =TIME_OK ; + time_state =TIME_OK ; }/* @@ -234,8 +272,7 @@ static inline void notify_cmos_timer(voi*/ int do_adjtimex (struct timex *txc) { -long mtemp, save_adjust; -s64 freq_adj; +long save_adjust;int result;/* In order to modify anything, you gotta be super-user! */ @@ -272,94 +309,63 @@ int do_adjtimex(struct timex *txc) time_status &= ~STA_CLOCKERR ;/* reset STA_CLOCKERR */ #endif /* If there are input parameters, then process them */ -if (txc->modes) - { -if (txc->modes &ADJ_STATUS )/* only set allowed bits */ - time_status = (txc->status & ~STA_RONLY ) | - (time_status &STA_RONLY ); - -if (txc->modes &ADJ_FREQUENCY ) {/* p. 22 */ -if (txc->freq >MAXFREQ || txc->freq < -MAXFREQ ) { - result = -EINVAL ; - goto leave; +if (txc->modes) { +if (txc->modes &ADJ_STATUS )/* only set allowed bits */ + time_status = (txc->status & ~STA_RONLY ) | + (time_status &STA_RONLY ); + +if (txc->modes &ADJ_FREQUENCY ) { +if (txc->freq >MAXFREQ || txc->freq < -MAXFREQ ) { + result = -EINVAL ; + goto leave; + } + time_freq = ((s64 )txc->freq *NSEC_PER_USEC ) + >> (SHIFT_USEC -SHIFT_NSEC ); } - time_freq = ((s64 )txc->freq *NSEC_PER_USEC ) - >> (SHIFT_USEC -SHIFT_NSEC ); - } - -if (txc->modes &ADJ_MAXERROR ) { -if (txc->maxerror <0 || txc->maxerror >=NTP_PHASE_LIMIT ) { - result = -EINVAL ; - goto leave; + +if (txc->modes &ADJ_MAXERROR ) { +if (txc->maxerror <0 || txc->maxerror >=NTP_PHASE_LIMIT ) { + result = -EINVAL ; + goto leave; + } + time_maxerror = txc->maxerror; } - time_maxerror = txc->maxerror; - } -if (txc->modes &ADJ_ESTERROR ) { -if (txc->esterror <0 || txc->esterror >=NTP_PHASE_LIMIT ) { - result = -EINVAL ; - goto leave; +if (txc->modes &ADJ_ESTERROR ) { +if (txc->esterror <0 || txc->esterror >=NTP_PHASE_LIMIT ) { + result = -EINVAL ; + goto leave; + } + time_esterror = txc->esterror; } - time_esterror = txc->esterror; - } -if (txc->modes &ADJ_TIMECONST ) {/* p. 24 */ -if (txc->constant <0 ) {/* NTP v4 uses values > 6 */ - result = -EINVAL ; - goto leave; +if (txc->modes &ADJ_TIMECONST ) { +if (txc->constant <0 ) {/* NTP v4 uses values > 6 */ + result = -EINVAL ; + goto leave; + } + time_constant =min (txc->constant +4 , (long )MAXTC ); } - time_constant =min (txc->constant +4 , (long )MAXTC ); - } -if (txc->modes &ADJ_OFFSET ) {/* values checked earlier */ -if (txc->modes ==ADJ_OFFSET_SINGLESHOT ) { -/* adjtime() is independent from ntp_adjtime() */ - time_adjust = txc->offset; +if (txc->modes &ADJ_OFFSET ) { +if (txc->modes ==ADJ_OFFSET_SINGLESHOT ) +/* adjtime() is independent from ntp_adjtime() */ + time_adjust = txc->offset; +else +ntp_update_offset (txc->offset); } -else if (time_status &STA_PLL ) { - time_offset = txc->offset *NSEC_PER_USEC ; +if (txc->modes &ADJ_TICK ) + tick_usec = txc->tick; -/* -* Scale the phase adjustment and -* clamp to the operating range. -*/ - time_offset =min (time_offset, (s64 )MAXPHASE *NSEC_PER_USEC ); - time_offset =max (time_offset, (s64 )-MAXPHASE *NSEC_PER_USEC ); - -/* -* Select whether the frequency is to be controlled -* and in which mode (PLL or FLL). Clamp to the operating -* range. Ugly multiply/divide should be replaced someday. -*/ - -if (time_status &STA_FREQHOLD || time_reftime ==0 ) - time_reftime = xtime.tv_sec; - mtemp = xtime.tv_sec - time_reftime; - time_reftime = xtime.tv_sec; - - freq_adj = time_offset * mtemp; - freq_adj =shift_right (freq_adj, time_constant *2 + - (SHIFT_PLL +2 ) *2 -SHIFT_NSEC ); -if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) - freq_adj +=div_s64 (time_offset << (SHIFT_NSEC -SHIFT_FLL ), mtemp); - freq_adj += time_freq; - freq_adj =min (freq_adj, (s64 )MAXFREQ_NSEC ); - time_freq =max (freq_adj, (s64)-MAXFREQ_NSEC ); - time_offset =div_s64 (time_offset,NTP_INTERVAL_FREQ ); - time_offset <<=SHIFT_UPDATE ; - }/* STA_PLL */ - }/* txc->modes & ADJ_OFFSET */ -if (txc->modes &ADJ_TICK ) - tick_usec = txc->tick; - -if (txc->modes & (ADJ_TICK |ADJ_FREQUENCY |ADJ_OFFSET )) -ntp_update_frequency (); - }/* txc->modes */ -leave:if ((time_status & (STA_UNSYNC |STA_CLOCKERR )) !=0 ) +if (txc->modes & (ADJ_TICK |ADJ_FREQUENCY |ADJ_OFFSET )) +ntp_update_frequency (); + } +leave: +if (time_status & (STA_UNSYNC |STA_CLOCKERR )) result =TIME_ERROR ;if ((txc->modes ==ADJ_OFFSET_SINGLESHOT ) || - (txc->modes ==ADJ_OFFSET_SS_READ )) + (txc->modes ==ADJ_OFFSET_SS_READ )) txc->offset = save_adjust;else txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) *@@ -384,9 +390,12 @@ leave: if ((time_status & (STA_UNSYNC|ST txc->errcnt =0 ; txc->stbcnt =0 ;write_sequnlock_irq (&xtime_lock); +do_gettimeofday (&txc->time); +notify_cmos_timer (); -return (result); + +return result; }static int __init ntp_tick_adj_setup (char *str)
Re: [PATCH 1/8] cleanup ntp.c
Hi,
Quoted 5 lines · john stultz
Ah crud. Ingo sent very similar changes to me a few weeks ago, and I've been too pinched for time to test and send them out.
I'll spend some time today to layer his fixes as well as my own cleanups on top.
What fixes?
Quoted 7 lines
kernel/time/ntp.c static void ntp_update_frequency(void) · line 62
Quoted 3 lines
kernel/time/ntp.c +3
-0+static void ntp_update_offset (long offset) +{ +long mtemp;Could we change this to a more descriptive name?
Maybe
last_update_interval?
It's a local variable, so IMO temp works just fine, it's not that difficult to figure out how it's used (e.g. it's like using loop_index instead of i).
bye, Roman
PATCH 2/8 NTP4 user space bits update
In reply to [email protected]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.
--- include/linux/timex.h | 12 ++++-- kernel/time/ntp.c | 91 +++++++++++++++++++++++++------------------------- 2 files changed, 56 insertions(+), 47 deletions(-)
include/linux/timex.h +9 -3
@@ -58,6 +58,8 @@#include <asm/param.h> +#define NTP_API 4/* NTP API version */ +/* * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen * for a slightly underdamped convergence characteristic. SHIFT_KH
@@ -135,6 +137,8 @@ struct timex {#define ADJ_ESTERROR 0x0008/* estimated time error */ #define ADJ_STATUS 0x0010/* clock status */ #define ADJ_TIMECONST 0x0020/* pll time constant */ +#define ADJ_MICRO 0x1000/* select microsecond resolution */ +#define ADJ_NANO 0x2000/* select nanosecond resolution */ #define ADJ_TICK 0x4000/* tick value */ #define ADJ_OFFSET_SINGLESHOT 0x8001/* old-fashioned adjtime */ #define ADJ_OFFSET_SS_READ 0xa001/* read-only adjtime */
@@ -146,8 +150,6 @@ struct timex {#define MOD_ESTERROR ADJ_ESTERROR#define MOD_STATUS ADJ_STATUS#define MOD_TIMECONST ADJ_TIMECONST -#define MOD_CLKB ADJ_TICK -#define MOD_CLKA ADJ_OFFSET_SINGLESHOT/* 0x8000 in original */ /*
@@ -169,9 +171,13 @@ struct timex {#define STA_PPSERROR 0x0800/* PPS signal calibration error (ro) */ #define STA_CLOCKERR 0x1000/* clock hardware fault (ro) */ +#define STA_NANO 0x2000/* resolution (0 = us, 1 = ns) (ro) */ +#define STA_MODE 0x4000/* mode (0 = PLL, 1 = FLL) (ro) */ +#define STA_CLK 0x8000/* clock source (0 = A, 1 = B) (ro) */ +/* read-only bits */ #define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \ - STA_PPSERROR | STA_CLOCKERR)/* read-only bits */ + STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK)/* * Clock states (time_state)
kernel/time/ntp.c +47 -44
159 lines not on this page · raw message
Re: [PATCH 2/8] NTP4 user space bits update
Quoted 11 lines · On Fri, 2008-03-14 at 19:40 +0100, [email protected] wrote:
plain text document attachment (
ntp4_user)
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 viaSTA_NANOand 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]>
I've not looked up the new NTP4-ims, but few comments below.
Quoted 88 lines
--- include/linux/timex.h | 12 ++++-- kernel/time/ntp.c | 91 +++++++++++++++++++++++++------------------------- 2 files changed, 56 insertions(+), 47 deletions(-)Index:
linux-2.6/include/linux/timex.h
===================================================================include/linux/timex.h +9
-3@@ -58,6 +58,8 @@#include <asm/param.h> +#define NTP_API 4/* NTP API version */ +/* * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen * for a slightly underdamped convergence characteristic. SHIFT_KH @@ -135,6 +137,8 @@ struct timex {#define ADJ_ESTERROR 0x0008/* estimated time error */ #define ADJ_STATUS 0x0010/* clock status */ #define ADJ_TIMECONST 0x0020/* pll time constant */ +#define ADJ_MICRO 0x1000/* select microsecond resolution */ +#define ADJ_NANO 0x2000/* select nanosecond resolution */ #define ADJ_TICK 0x4000/* tick value */ #define ADJ_OFFSET_SINGLESHOT 0x8001/* old-fashioned adjtime */ #define ADJ_OFFSET_SS_READ 0xa001/* read-only adjtime */ @@ -146,8 +150,6 @@ struct timex {#define MOD_ESTERROR ADJ_ESTERROR#define MOD_STATUS ADJ_STATUS#define MOD_TIMECONST ADJ_TIMECONST -#define MOD_CLKB ADJ_TICK -#define MOD_CLKA ADJ_OFFSET_SINGLESHOT/* 0x8000 in original */ /* @@ -169,9 +171,13 @@ struct timex {#define STA_PPSERROR 0x0800/* PPS signal calibration error (ro) */ #define STA_CLOCKERR 0x1000/* clock hardware fault (ro) */ +#define STA_NANO 0x2000/* resolution (0 = us, 1 = ns) (ro) */ +#define STA_MODE 0x4000/* mode (0 = PLL, 1 = FLL) (ro) */ +#define STA_CLK 0x8000/* clock source (0 = A, 1 = B) (ro) */ +/* read-only bits */ #define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \ - STA_PPSERROR | STA_CLOCKERR)/* read-only bits */ + STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK)/* * Clock states (time_state) Index:
linux-2.6/kernel/time/ntp.c
===================================================================kernel/time/ntp.c +8
-2@@ -65,7 +65,9 @@ static void ntp_update_offset(long offseif (!(time_status &STA_PLL ))return ; - time_offset = offset *NSEC_PER_USEC ; + time_offset = offset; +if (!(time_status &STA_NANO )) + time_offset *=NSEC_PER_USEC ;/* * Scale the phase adjustment and @@ -86,8 +88,11 @@ static void ntp_update_offset(long offse freq_adj = time_offset * mtemp; freq_adj =shift_right (freq_adj, time_constant *2 + (SHIFT_PLL +2 ) *2 -SHIFT_NSEC ); -if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) + time_status &= ~STA_MODE ; +if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) { freq_adj +=div_s64 (time_offset << (SHIFT_NSEC -SHIFT_FLL ), mtemp); + time_status |=STA_MODE ; + } freq_adj += time_freq; freq_adj =min (freq_adj, (s64 )MAXFREQ_NSEC ); time_freq =max (freq_adj, (s64)-MAXFREQ_NSEC );@@ -272,6 +277,7 @@ static inline void notify_cmos_timer(voi*/ int do_adjtimex (struct timex *txc) { +struct timespec ts;long save_adjust;int result;
kernel/time/ntp.c int do_adjtimex(struct timex *txc) · line 293
Quoted 9 lines
kernel/time/ntp.c +2
-3@@ -282,17 +288,11 @@ int do_adjtimex(struct timex *txc)/* Now we validate the data before disabling interrupts */ if ((txc->modes &ADJ_OFFSET_SINGLESHOT ) ==ADJ_OFFSET_SINGLESHOT ) { -/* singleshot must not be used with any other mode bits */ -if (txc->modes !=ADJ_OFFSET_SINGLESHOT && - txc->modes !=ADJ_OFFSET_SS_READ ) +/* singleshot must not be used with any other mode bits */ +if (txc->modes & ~ADJ_OFFSET_SS_READ )return -EINVAL ;
This could probably go in the cleanup patch, no?
Quoted 12 lines
kernel/time/ntp.c +0
-5} -if (txc->modes !=ADJ_OFFSET_SINGLESHOT && (txc->modes &ADJ_OFFSET )) -/* adjustment Offset limited to +- .512 seconds */ -if (txc->offset <= -MAXPHASE || txc->offset >=MAXPHASE ) -return -EINVAL ; -/* if the quartz is off by more than 10% something is VERY wrong ! */ if (txc->modes &ADJ_TICK ) if (txc->tick < 900000/USER_HZ ||@@ -300,51 +300,46 @@ int do_adjtimex(struct timex *txc)return -EINVAL ;
kernel/time/ntp.c int do_adjtimex(struct timex *txc) · line 310
Quoted 10 lines
kernel/time/ntp.c +0
-4write_seqlock_irq (&xtime_lock); - result = time_state;/* mostly `TIME_OK' */ /* Save for later - semantics of adjtime is to return old value */ save_adjust = time_adjust; -#if 0 /* STA_CLOCKERR is never set yet */ - time_status &= ~STA_CLOCKERR ;/* reset STA_CLOCKERR */ -#endif
This as well is just cleanup.
Quoted 5 lines
kernel/time/ntp.c +0
-3/* If there are input parameters, then process them */ if (txc->modes) { -if (txc->modes &ADJ_STATUS )/* only set allowed bits */ - time_status = (txc->status & ~STA_RONLY ) | - (time_status &STA_RONLY );
kernel/time/ntp.c int do_adjtimex(struct timex *txc) · line 318
Quoted 10 lines
kernel/time/ntp.c +10
-0+if (txc->modes &ADJ_STATUS ) { +if ((time_status &STA_PLL ) && + !(txc->status &STA_PLL )) { + time_state =TIME_OK ; + time_status =STA_UNSYNC ; + } +/* only set allowed bits */ + time_status &=STA_RONLY ; + time_status |= txc->status & ~STA_RONLY ; + }
More cleanup.
Quoted 83 lines
kernel/time/ntp.c +26
-27+if (txc->modes &ADJ_NANO ) + time_status |=STA_NANO ; +if (txc->modes &ADJ_MICRO ) + time_status &= ~STA_NANO ;if (txc->modes &ADJ_FREQUENCY ) { -if (txc->freq >MAXFREQ || txc->freq < -MAXFREQ ) { - result = -EINVAL ; - goto leave; - } - time_freq = ((s64 )txc->freq *NSEC_PER_USEC ) + time_freq =min (txc->freq,MAXFREQ ); + time_freq =min (time_freq, -MAXFREQ ); + time_freq = ((s64 )time_freq *NSEC_PER_USEC ) >> (SHIFT_USEC -SHIFT_NSEC ); } -if (txc->modes &ADJ_MAXERROR ) { -if (txc->maxerror <0 || txc->maxerror >=NTP_PHASE_LIMIT ) { - result = -EINVAL ; - goto leave; - } +if (txc->modes &ADJ_MAXERROR ) time_maxerror = txc->maxerror; - } - -if (txc->modes &ADJ_ESTERROR ) { -if (txc->esterror <0 || txc->esterror >=NTP_PHASE_LIMIT ) { - result = -EINVAL ; - goto leave; - } +if (txc->modes &ADJ_ESTERROR ) time_esterror = txc->esterror; - }if (txc->modes &ADJ_TIMECONST ) { -if (txc->constant <0 ) {/* NTP v4 uses values > 6 */ - result = -EINVAL ; - goto leave; - } - time_constant =min (txc->constant +4 , (long )MAXTC ); + 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_OFFSET ) {@@ -360,16 +355,20 @@ int do_adjtimex(struct timex *txc)if (txc->modes & (ADJ_TICK |ADJ_FREQUENCY |ADJ_OFFSET ))ntp_update_frequency (); } -leave: + + result = time_state;/* mostly `TIME_OK' */ if (time_status & (STA_UNSYNC |STA_CLOCKERR )) result =TIME_ERROR ;if ((txc->modes ==ADJ_OFFSET_SINGLESHOT ) || (txc->modes ==ADJ_OFFSET_SS_READ )) txc->offset = save_adjust; -else +else { txc->offset = ((long )shift_right (time_offset,SHIFT_UPDATE )) * -NTP_INTERVAL_FREQ /1000 ; +NTP_INTERVAL_FREQ ; +if (!(time_status &STA_NANO )) + txc->offset /=NSEC_PER_USEC ; + } txc->freq = (time_freq /NSEC_PER_USEC ) << (SHIFT_USEC -SHIFT_NSEC ); txc->maxerror = time_maxerror;@@ -391,7 +390,11 @@ leave: txc->stbcnt =0 ;write_sequnlock_irq (&xtime_lock); -do_gettimeofday (&txc->time); +getnstimeofday (&ts); + txc->time.tv_sec = ts.tv_sec; + txc->time.tv_usec = ts.tv_nsec; +if (!(time_status &STA_NANO )) + txc->time.tv_usec /=NSEC_PER_USEC ;
Re: [PATCH 2/8] NTP4 user space bits update
Hi,
Quoted 8 lines · john stultz
kernel/time/ntp.c int do_adjtimex(struct timex *txc) · line 293
Quoted 6 lines
kernel/time/ntp.c +2
-3-/* singleshot must not be used with any other mode bits */ -if (txc->modes !=ADJ_OFFSET_SINGLESHOT && - txc->modes !=ADJ_OFFSET_SS_READ ) +/* singleshot must not be used with any other mode bits */ +if (txc->modes & ~ADJ_OFFSET_SS_READ )return -EINVAL ;This could probably go in the cleanup patch, no?
It does more than simple code indentation and refactoring, so I didn't want to include it there.
Quoted 5 lines
kernel/time/ntp.c int do_adjtimex(struct timex *txc) · line 310
Quoted 3 lines
kernel/time/ntp.c +0
-3-#if 0 /* STA_CLOCKERR is never set yet */ - time_status &= ~STA_CLOCKERR ;/* reset STA_CLOCKERR */ -#endif This as well is just cleanup.
Debatable, it refers to user space APIs, so I included it here.
Quoted 4 lines
Quoted 4 lines
kernel/time/ntp.c +4
-0+if (txc->modes &ADJ_STATUS ) { +if ((time_status &STA_PLL ) && + !(txc->status &STA_PLL )) { + time_state =TIME_OK ;
Quoted 8 lines
kernel/time/ntp.c int do_adjtimex(struct timex *txc) · line 318
Quoted 6 lines
kernel/time/ntp.c +6
-0+ time_status =STA_UNSYNC ; + } +/* only set allowed bits */ + time_status &=STA_RONLY ; + time_status |= txc->status & ~STA_RONLY ; + }More cleanup.
Not really.
bye, Roman
PATCH 3/8 increase time_freq resolution
In reply to [email protected]This changes time_freq to a 64bit value and makes it static (the only outside user had no real need to modify it).
Intermediate values were already 64bit, so the change isn't that big, but it saves a little in shifts by replacing SHIFT_NSEC with TICK_LENGTH_SHIFT. PPM_SCALE is then used to convert between user space and kernel space representation.
--- arch/powerpc/kernel/time.c | 2 -- include/linux/timex.h | 11 ++++++----- kernel/time/ntp.c | 30 +++++++++++++++--------------- 3 files changed, 21 insertions(+), 22 deletions(-)
arch/powerpc/kernel/time.c +0 -2
@@ -1007,8 +1007,6 @@ void __init time_init(void) vdso_data->stamp_xsec = (u64 ) xtime.tv_sec *XSEC_PER_SEC ; vdso_data->tb_to_xs = tb_to_xs; - time_freq =0 ; -write_sequnlock_irqrestore (&xtime_lock, flags);/* Register the clocksource, if we're not running on iSeries */
include/linux/timex.h +6 -5
@@ -84,11 +84,14 @@*/ #define SHIFT_UPDATE (SHIFT_HZ + 1)/* time offset scale (shift) */ #define SHIFT_USEC 16/* frequency offset scale (shift) */ -#define SHIFT_NSEC 12/* kernel frequency offset scale */ +#define PPM_SCALE (NSEC_PER_USEC << (TICK_LENGTH_SHIFT - SHIFT_USEC)) +#define PPM_SCALE_INV_SHIFT 20 +#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + TICK_LENGTH_SHIFT)) / \ + PPM_SCALE + 1)#define MAXPHASE 512000L/* max phase error (us) */ -#define MAXFREQ (512L << SHIFT_USEC)/* max frequency error (ppm) */ -#define MAXFREQ_NSEC (512000L << SHIFT_NSEC)/* max frequency error (ppb) */ +#define MAXFREQ 500000/* max frequency error (ns/s) */ +#define MAXFREQ_SCALED ((s64)MAXFREQ << TICK_LENGTH_SHIFT)#define MINSEC 256/* min interval between updates (s) */ #define MAXSEC 2048/* max interval between updates (s) */ #define NTP_PHASE_LIMIT (MAXPHASE << 5)/* beyond max. dispersion */
@@ -208,8 +211,6 @@ extern int time_status; /* clock synchrextern long time_maxerror;/* maximum error */ extern long time_esterror;/* estimated error */ -extern long time_freq;/* frequency offset (scaled ppm) */ -extern long time_adjust;/* The amount of adjtime left */ extern void ntp_clear (void );
kernel/time/ntp.c +15 -15
@@ -39,7 +39,7 @@ static s64 time_offset; /* time adjuststatic long time_constant =2 ;/* pll time constant */ long time_maxerror =NTP_PHASE_LIMIT ;/* maximum error (us) */ long time_esterror =NTP_PHASE_LIMIT ;/* estimated error (us) */ -long time_freq;/* frequency offset (scaled ppm)*/ +static s64 time_freq;/* frequency offset (scaled ns/s)*/ static long time_reftime;/* time at last adjustment (s) */ long time_adjust;static long ntp_tick_adj;
@@ -49,7 +49,7 @@ static void ntp_update_frequency(void)u64 second_length = (u64)(tick_usec *NSEC_PER_USEC *USER_HZ ) <<TICK_LENGTH_SHIFT ; second_length += (s64 )ntp_tick_adj <<TICK_LENGTH_SHIFT ; - second_length += (s64 )time_freq << (TICK_LENGTH_SHIFT -SHIFT_NSEC ); + second_length += time_freq; tick_length_base = second_length;
@@ -86,16 +86,16 @@ static void ntp_update_offset(long offse time_reftime = xtime.tv_sec; freq_adj = time_offset * mtemp; - freq_adj =shift_right (freq_adj, time_constant *2 + - (SHIFT_PLL +2 ) *2 -SHIFT_NSEC ); + freq_adj <<=TICK_LENGTH_SHIFT -2 * (SHIFT_PLL +2 + time_constant); time_status &= ~STA_MODE ;if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) { - freq_adj +=div_s64 (time_offset << (SHIFT_NSEC -SHIFT_FLL ), mtemp); + freq_adj +=div_s64 (time_offset << (TICK_LENGTH_SHIFT -SHIFT_FLL ), + mtemp); time_status |=STA_MODE ; } freq_adj += time_freq; - freq_adj =min (freq_adj, (s64 )MAXFREQ_NSEC ); - time_freq =max (freq_adj, (s64)-MAXFREQ_NSEC ); + freq_adj =min (freq_adj,MAXFREQ_SCALED ); + time_freq =max (freq_adj, -MAXFREQ_SCALED ); time_offset =div_s64 (time_offset,NTP_INTERVAL_FREQ ); time_offset <<=SHIFT_UPDATE ; }
@@ -131,7 +131,7 @@ void second_overflow(void)long time_adj;/* Bump the maxerror field */ - time_maxerror +=MAXFREQ >>SHIFT_USEC ; + time_maxerror +=MAXFREQ /NSEC_PER_USEC ;if (time_maxerror >NTP_PHASE_LIMIT ) { time_maxerror =NTP_PHASE_LIMIT ; time_status |=STA_UNSYNC ;
@@ -323,10 +323,9 @@ int do_adjtimex(struct timex *txc) time_status &= ~STA_NANO ;if (txc->modes &ADJ_FREQUENCY ) { - time_freq =min (txc->freq,MAXFREQ ); - time_freq =min (time_freq, -MAXFREQ ); - time_freq = ((s64 )time_freq *NSEC_PER_USEC ) - >> (SHIFT_USEC -SHIFT_NSEC ); + time_freq = (s64 )txc->freq *PPM_SCALE ; + time_freq =min (time_freq,MAXFREQ_SCALED ); + time_freq =max (time_freq, -MAXFREQ_SCALED ); }if (txc->modes &ADJ_MAXERROR )
@@ -369,14 +368,15 @@ int do_adjtimex(struct timex *txc)if (!(time_status &STA_NANO )) txc->offset /=NSEC_PER_USEC ; } - txc->freq = (time_freq /NSEC_PER_USEC ) << - (SHIFT_USEC -SHIFT_NSEC ); + txc->freq =shift_right ((s32)(time_freq >>PPM_SCALE_INV_SHIFT ) * + (s64 )PPM_SCALE_INV , +TICK_LENGTH_SHIFT ); txc->maxerror = time_maxerror; txc->esterror = time_esterror; txc->status = time_status; txc->constant = time_constant; txc->precision =1 ; - txc->tolerance =MAXFREQ ; + txc->tolerance =MAXFREQ_SCALED /PPM_SCALE ; txc->tick = tick_usec;/* PPS is not implemented, so these are zero */
PATCH 4/8 increase time_offset resolution
In reply to [email protected]time_offset is already a 64bit value but its resolution barely used, so this makes better use of it by replacing SHIFT_UPDATE with TICK_LENGTH_SHIFT.
Side note: the SHIFT_HZ in SHIFT_UPDATE was incorrect for CONFIG_NO_HZ and the primary reason for changing time_offset to 64bit to avoid the overflow.
--- include/linux/timex.h | 9 ++------- kernel/time/ntp.c | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 19 deletions(-)
include/linux/timex.h +2 -7
@@ -74,27 +74,22 @@#define MAXTC 10/* maximum time constant (shift) */ /* -* The SHIFT_UPDATE define establishes the decimal point of the -* time_offset variable which represents the current offset with -* respect to standard time. -* * SHIFT_USEC defines the scaling (shift) of the time_freq and * time_tolerance variables, which represent the current frequency * offset and maximum frequency tolerance. */ -#define SHIFT_UPDATE (SHIFT_HZ + 1)/* time offset scale (shift) */ #define SHIFT_USEC 16/* frequency offset scale (shift) */ #define PPM_SCALE (NSEC_PER_USEC << (TICK_LENGTH_SHIFT - SHIFT_USEC))#define PPM_SCALE_INV_SHIFT 20#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + TICK_LENGTH_SHIFT)) / \ PPM_SCALE + 1) -#define MAXPHASE 512000L/* max phase error (us) */ +#define MAXPHASE 500000000l/* max phase error (ns) */ #define MAXFREQ 500000/* max frequency error (ns/s) */ #define MAXFREQ_SCALED ((s64)MAXFREQ << TICK_LENGTH_SHIFT)#define MINSEC 256/* min interval between updates (s) */ #define MAXSEC 2048/* max interval between updates (s) */ -#define NTP_PHASE_LIMIT (MAXPHASE << 5)/* beyond max. dispersion */ +#define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5)/* beyond max. dispersion */ /* * syscall interface - used (mainly by NTP daemon)
kernel/time/ntp.c +11 -12
@@ -65,16 +65,15 @@ static void ntp_update_offset(long offseif (!(time_status &STA_PLL ))return ; - time_offset = offset;if (!(time_status &STA_NANO )) - time_offset *=NSEC_PER_USEC ; + offset *=NSEC_PER_USEC ;/* * Scale the phase adjustment and * clamp to the operating range. */ - time_offset =min (time_offset, (s64 )MAXPHASE *NSEC_PER_USEC ); - time_offset =max (time_offset, (s64 )-MAXPHASE *NSEC_PER_USEC ); + offset =min (offset,MAXPHASE ); + offset =max (offset, -MAXPHASE );/* * Select how the frequency is to be controlled
@@ -85,19 +84,19 @@ static void ntp_update_offset(long offse mtemp = xtime.tv_sec - time_reftime; time_reftime = xtime.tv_sec; - freq_adj = time_offset * mtemp; + freq_adj = (s64 )offset * mtemp; freq_adj <<=TICK_LENGTH_SHIFT -2 * (SHIFT_PLL +2 + time_constant); time_status &= ~STA_MODE ;if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) { - freq_adj +=div_s64 (time_offset << (TICK_LENGTH_SHIFT -SHIFT_FLL ), + freq_adj +=div_s64 ((s64 )offset << (TICK_LENGTH_SHIFT -SHIFT_FLL ), mtemp); time_status |=STA_MODE ; } freq_adj += time_freq; freq_adj =min (freq_adj,MAXFREQ_SCALED ); time_freq =max (freq_adj, -MAXFREQ_SCALED ); - time_offset =div_s64 (time_offset,NTP_INTERVAL_FREQ ); - time_offset <<=SHIFT_UPDATE ; + + time_offset =div_s64 ((s64 )offset <<TICK_LENGTH_SHIFT ,NTP_INTERVAL_FREQ ); }/**
@@ -128,7 +127,7 @@ void ntp_clear(void)*/ void second_overflow (void ) { -long time_adj; +s64 time_adj;/* Bump the maxerror field */ time_maxerror +=MAXFREQ /NSEC_PER_USEC ;
@@ -184,7 +183,7 @@ void second_overflow(void) tick_length = tick_length_base; time_adj =shift_right (time_offset,SHIFT_PLL + time_constant); time_offset -= time_adj; - tick_length += (s64 )time_adj << (TICK_LENGTH_SHIFT -SHIFT_UPDATE ); + tick_length += time_adj;if (unlikely (time_adjust)) {if (time_adjust >MAX_TICKADJ ) {
@@ -363,8 +362,8 @@ int do_adjtimex(struct timex *txc) (txc->modes == ADJ_OFFSET_SS_READ)) txc->offset = save_adjust; else { - txc->offset = ((long )shift_right (time_offset,SHIFT_UPDATE )) * -NTP_INTERVAL_FREQ ; + txc->offset =shift_right (time_offset *NTP_INTERVAL_FREQ , +TICK_LENGTH_SHIFT );if (!(time_status &STA_NANO )) txc->offset /=NSEC_PER_USEC ; }
PATCH 5/8 support for TAI
In reply to [email protected]This adds support for setting the TAI value (International Atomic Time). The value is reported back to userspace via timex (as we don't have a ntp_gettime() syscall).
--- include/linux/compat.h | 3 ++- include/linux/timex.h | 4 +++- kernel/compat.c | 3 ++- kernel/time/ntp.c | 7 +++++++ 4 files changed, 14 insertions(+), 3 deletions(-)
include/linux/compat.h +2 -1
@@ -65,10 +65,11 @@ struct compat_timex {compat_long_t calcnt;compat_long_t errcnt;compat_long_t stbcnt; +compat_int_t tai; compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; - compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; + compat_int_t :32 ; compat_int_t :32 ; compat_int_t :32 ; };#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
include/linux/timex.h +4 -1
@@ -116,9 +116,11 @@ struct timex {long errcnt;/* calibration errors (ro) */ long stbcnt;/* stability limit exceeded (ro) */ +int tai;/* TAI offset (ro) */ + int :32; int :32; int :32; int :32; int :32; int :32; int :32; int :32; - int :32; int :32; int :32; int :32; + int :32; int :32; int :32; };/*
@@ -135,6 +135,7 @@ struct timex {#define ADJ_ESTERROR 0x0008/* estimated time error */ #define ADJ_STATUS 0x0010/* clock status */ #define ADJ_TIMECONST 0x0020/* pll time constant */ +#define ADJ_TAI 0x0080/* set TAI offset */ #define ADJ_MICRO 0x1000/* select microsecond resolution */ #define ADJ_NANO 0x2000/* select nanosecond resolution */ #define ADJ_TICK 0x4000/* tick value */
kernel/compat.c +2 -1
@@ -955,7 +955,8 @@ asmlinkage long compat_sys_adjtimex(stru__put_user (txc.jitcnt, &utp->jitcnt) ||__put_user (txc.calcnt, &utp->calcnt) ||__put_user (txc.errcnt, &utp->errcnt) || - __put_user(txc.stbcnt, &utp->stbcnt)) +__put_user (txc.stbcnt, &utp->stbcnt) || + __put_user(txc.tai, &utp->tai)) ret = -EFAULT;return ret;
kernel/time/ntp.c +7 -0
@@ -35,6 +35,7 @@ static u64 tick_length, tick_length_base/* TIME_ERROR prevents overwriting the CMOS clock */ static int time_state =TIME_OK ;/* clock synchronization status */ int time_status =STA_UNSYNC ;/* clock status bits */ +static long time_tai;/* TAI offset (s) */ static s64 time_offset;/* time adjustment (ns) */ static long time_constant =2 ;/* pll time constant */ long time_maxerror =NTP_PHASE_LIMIT ;/* maximum error (us) */
@@ -162,6 +163,7 @@ void second_overflow(void)case TIME_DEL :if ((xtime.tv_sec +1 ) %86400 ==0 ) { xtime.tv_sec++; + time_tai--; wall_to_monotonic.tv_sec--; time_state =TIME_WAIT ; printk(KERN_NOTICE "Clock: deleting leap second "
@@ -169,6 +171,7 @@ void second_overflow(void) }break ;case TIME_OOP : + time_tai++; time_state =TIME_WAIT ;break ;case TIME_WAIT :
@@ -340,6 +343,9 @@ int do_adjtimex(struct timex *txc) time_constant =max (time_constant,0l ); } +if (txc->modes &ADJ_TAI && txc->constant >0 ) + time_tai = txc->constant; +if (txc->modes &ADJ_OFFSET ) {if (txc->modes ==ADJ_OFFSET_SINGLESHOT )/* adjtime() is independent from ntp_adjtime() */
@@ -375,6 +381,7 @@ int do_adjtimex(struct timex *txc) txc->precision =1 ; txc->tolerance =MAXFREQ_SCALED /PPM_SCALE ; txc->tick = tick_usec; + txc->tai = time_tai;/* PPS is not implemented, so these are zero */ txc->ppsfreq =0 ;
Re: [PATCH 5/8] support for TAI
Quoted 7 lines · On Fri, 2008-03-14 at 19:40 +0100, [email protected] wrote:
plain text document attachment (
time_tai)
This adds support for setting the TAI value (International Atomic Time). The value is reported back to userspace via timex (as we don't have antp_gettime()syscall).Signed-off-by Roman Zippel <[email protected]>
Very cool. I just was talking with someone who was looking for a TAI interface.
Minor nit below.
-john
kernel/time/ntp.c static u64 tick_length, tick_length_base · line 38
Quoted 9 lines
Index:
linux-2.6-mm/kernel/time/ntp.c
===================================================================kernel/time/ntp.c +1
-0@@ -35,6 +35,7 @@ static u64 tick_length, tick_length_base/* TIME_ERROR prevents overwriting the CMOS clock */ static int time_state =TIME_OK ;/* clock synchronization status */ int time_status =STA_UNSYNC ;/* clock status bits */ +static long time_tai;/* TAI offset (s) */
I think timekeeping.c would be the better place for time_tai, keeping it closer to xtime and wall_to_monotonic's definitions.
Quoted 12 lines
kernel/time/ntp.c +1
-0static s64 time_offset;/* time adjustment (ns) */ static long time_constant =2 ;/* pll time constant */ long time_maxerror =NTP_PHASE_LIMIT ;/* maximum error (us) */ @@ -162,6 +163,7 @@ void second_overflow(void)case TIME_DEL :if ((xtime.tv_sec +1 ) %86400 ==0 ) { xtime.tv_sec++; + time_tai--; wall_to_monotonic.tv_sec--; time_state =TIME_WAIT ; printk(KERN_NOTICE "Clock: deleting leap second "
kernel/time/ntp.c void second_overflow(void) · line 177
Quoted 7 lines
kernel/time/ntp.c +1
-0@@ -169,6 +171,7 @@ void second_overflow(void) }break ;case TIME_OOP : + time_tai++; time_state =TIME_WAIT ;break ;case TIME_WAIT :
These manipulations could also be done in the timekeeping_insert/remove_second interface I suggested earlier.
Quoted 19 lines
kernel/time/ntp.c +4
-0@@ -340,6 +343,9 @@ int do_adjtimex(struct timex *txc) time_constant =max (time_constant,0l ); } +if (txc->modes &ADJ_TAI && txc->constant >0 ) + time_tai = txc->constant; +if (txc->modes &ADJ_OFFSET ) {if (txc->modes ==ADJ_OFFSET_SINGLESHOT )/* adjtime() is independent from ntp_adjtime() */ @@ -375,6 +381,7 @@ int do_adjtimex(struct timex *txc) txc->precision =1 ; txc->tolerance =MAXFREQ_SCALED /PPM_SCALE ; txc->tick = tick_usec; + txc->tai = time_tai;/* PPS is not implemented, so these are zero */ txc->ppsfreq =0 ;
PATCH 6/8 Rename TICK_LENGTH_SHIFT to NTP_SCALE_SHIFT
In reply to [email protected]As TICK_LENGTH_SHIFT is used for more than just the tick length, the name isn't quite approriate anymore, so this renames it to NTP_SCALE_SHIFT.
--- arch/powerpc/kernel/time.c | 2 +- include/linux/timex.h | 8 ++++---- kernel/time/ntp.c | 20 ++++++++++---------- kernel/time/timekeeping.c | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-)
arch/powerpc/kernel/time.c +1 -1
@@ -149,7 +149,7 @@ EXPORT_SYMBOL(tb_ticks_per_sec); /* foru64 tb_to_xs;unsigned tb_to_us; -#define TICKLEN_SCALE TICK_LENGTH_SHIFT +#define TICKLEN_SCALE NTP_SCALE_SHIFTu64 last_tick_len;/* units are ns / 2^TICKLEN_SCALE */ u64 ticklen_to_xs;/* 0.64 fraction */
include/linux/timex.h +4 -4
@@ -79,14 +79,14 @@* offset and maximum frequency tolerance. */ #define SHIFT_USEC 16/* frequency offset scale (shift) */ -#define PPM_SCALE (NSEC_PER_USEC << (TICK_LENGTH_SHIFT - SHIFT_USEC)) +#define PPM_SCALE (NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC))#define PPM_SCALE_INV_SHIFT 20 -#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + TICK_LENGTH_SHIFT)) / \ +#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \ PPM_SCALE + 1)#define MAXPHASE 500000000l/* max phase error (ns) */ #define MAXFREQ 500000/* max frequency error (ns/s) */ -#define MAXFREQ_SCALED ((s64)MAXFREQ << TICK_LENGTH_SHIFT) +#define MAXFREQ_SCALED ((s64)MAXFREQ << NTP_SCALE_SHIFT)#define MINSEC 256/* min interval between updates (s) */ #define MAXSEC 2048/* max interval between updates (s) */ #define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5)/* beyond max. dispersion */
@@ -228,7 +228,7 @@ static inline int ntp_synced(void) __x <0 ? -(-__x >> __s) : __x >> __s; \ }) -#define TICK_LENGTH_SHIFT 32 +#define NTP_SCALE_SHIFT 32#ifdef CONFIG_NO_HZ #define NTP_INTERVAL_FREQ (2)
kernel/time/ntp.c +10 -10
@@ -27,7 +27,7 @@ static u64 tick_length, tick_length_base#define MAX_TICKADJ 500/* microsecs */ #define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \ - TICK_LENGTH_SHIFT) / NTP_INTERVAL_FREQ) + NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)/* * phase-lock loop variables
@@ -48,13 +48,13 @@ static long ntp_tick_adj;static void ntp_update_frequency (void ) {u64 second_length = (u64)(tick_usec *NSEC_PER_USEC *USER_HZ ) - <<TICK_LENGTH_SHIFT ; - second_length += (s64 )ntp_tick_adj <<TICK_LENGTH_SHIFT ; + <<NTP_SCALE_SHIFT ; + second_length += (s64 )ntp_tick_adj <<NTP_SCALE_SHIFT ; second_length += time_freq; tick_length_base = second_length; - tick_nsec =div_u64 (second_length,HZ ) >>TICK_LENGTH_SHIFT ; + tick_nsec =div_u64 (second_length,HZ ) >>NTP_SCALE_SHIFT ; tick_length_base =div_u64 (tick_length_base,NTP_INTERVAL_FREQ ); }
@@ -86,10 +86,10 @@ static void ntp_update_offset(long offse time_reftime = xtime.tv_sec; freq_adj = (s64 )offset * mtemp; - freq_adj <<=TICK_LENGTH_SHIFT -2 * (SHIFT_PLL +2 + time_constant); + freq_adj <<=NTP_SCALE_SHIFT -2 * (SHIFT_PLL +2 + time_constant); time_status &= ~STA_MODE ;if (mtemp >=MINSEC && (time_status &STA_FLL || mtemp >MAXSEC )) { - freq_adj +=div_s64 ((s64 )offset << (TICK_LENGTH_SHIFT -SHIFT_FLL ), + freq_adj +=div_s64 ((s64 )offset << (NTP_SCALE_SHIFT -SHIFT_FLL ), mtemp); time_status |=STA_MODE ; }
@@ -97,7 +97,7 @@ static void ntp_update_offset(long offse freq_adj =min (freq_adj,MAXFREQ_SCALED ); time_freq =max (freq_adj, -MAXFREQ_SCALED ); - time_offset =div_s64 ((s64 )offset <<TICK_LENGTH_SHIFT ,NTP_INTERVAL_FREQ ); + time_offset =div_s64 ((s64 )offset <<NTP_SCALE_SHIFT ,NTP_INTERVAL_FREQ ); }/**
@@ -197,7 +197,7 @@ void second_overflow(void) tick_length -=MAX_TICKADJ_SCALED ; }else { tick_length += (s64)(time_adjust *NSEC_PER_USEC / -NTP_INTERVAL_FREQ ) <<TICK_LENGTH_SHIFT ; +NTP_INTERVAL_FREQ ) <<NTP_SCALE_SHIFT ; time_adjust =0 ; } }
@@ -369,13 +369,13 @@ int do_adjtimex(struct timex *txc) txc->offset = save_adjust; else { txc->offset =shift_right (time_offset *NTP_INTERVAL_FREQ , -TICK_LENGTH_SHIFT ); +NTP_SCALE_SHIFT );if (!(time_status &STA_NANO )) txc->offset /=NSEC_PER_USEC ; } txc->freq =shift_right ((s32)(time_freq >>PPM_SCALE_INV_SHIFT ) * (s64 )PPM_SCALE_INV , -TICK_LENGTH_SHIFT ); +NTP_SCALE_SHIFT ); txc->maxerror = time_maxerror; txc->esterror = time_esterror; txc->status = time_status;
kernel/time/timekeeping.c +5 -5
@@ -365,7 +365,7 @@ static __always_inline int clocksource_b* here. This is tuned so that an error of about 1 msec is adjusted * within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks). */ - error2 = clock->error >> (TICK_LENGTH_SHIFT +22 -2 *SHIFT_HZ ); + error2 = clock->error >> (NTP_SCALE_SHIFT +22 -2 *SHIFT_HZ ); error2 =abs (error2);for (look_ahead =0 ; error2 >0 ; look_ahead++) error2 >>=2 ;
@@ -375,7 +375,7 @@ static __always_inline int clocksource_b* remove the single look ahead already included in the error. */ tick_error =current_tick_length () >> - (TICK_LENGTH_SHIFT - clock->shift +1 ); + (NTP_SCALE_SHIFT - clock->shift +1 ); tick_error -= clock->xtime_interval >>1 ; error = ((error - tick_error) >> look_ahead) + tick_error;
@@ -406,7 +406,7 @@ static void clocksource_adjust(s64 offses64 error, interval = clock->cycle_interval;int adj; - error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift -1 ); + error = clock->error >> (NTP_SCALE_SHIFT - clock->shift -1 );if (error > interval) { error >>=2 ;if (likely (error <= interval))
@@ -428,7 +428,7 @@ static void clocksource_adjust(s64 offse clock->xtime_interval += interval; clock->xtime_nsec -= offset; clock->error -= (interval - offset) << - (TICK_LENGTH_SHIFT - clock->shift); + (NTP_SCALE_SHIFT - clock->shift); }/**
@@ -468,7 +468,7 @@ void update_wall_time(void)/* accumulate error between NTP and clock interval */ clock->error +=current_tick_length (); - clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift); + clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift); }/* correct the clock when NTP error is too big */
PATCH 7/8 Remove current_tick_length()
In reply to [email protected]current_tick_length used to do a little more, but now it just returns tick_length, which we can also access directly at the few places, where it's needed.
--- include/linux/timex.h | 4 ++-- kernel/time/ntp.c | 16 ++-------------- kernel/time/timekeeping.c | 5 ++--- 3 files changed, 6 insertions(+), 19 deletions(-)
include/linux/timex.h +2 -2
@@ -234,8 +234,8 @@ static inline int ntp_synced(void)#endif #define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ) -/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */ -extern u64 current_tick_length (void ); +/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */ +extern u64 tick_length;extern void second_overflow (void );extern void update_ntp_one_tick (void );
kernel/time/ntp.c +2 -14
@@ -23,7 +23,8 @@*/ unsigned long tick_usec =TICK_USEC ;/* USER_HZ period (usec) */ unsigned long tick_nsec;/* ACTHZ period (nsec) */ -static u64 tick_length, tick_length_base; +u64 tick_length; +static u64 tick_length_base;#define MAX_TICKADJ 500/* microsecs */ #define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \
@@ -203,19 +204,6 @@ void second_overflow(void) } } -/* -* Return how long ticks are at the moment, that is, how much time -* update_wall_time_one_tick will add to xtime next time we call it -* (assuming no calls to do_adjtimex in the meantime). -* The return value is in fixed-point nanoseconds shifted by the -* specified number of bits to the right of the binary point. -* This function has no side-effects. -*/ -u64 current_tick_length (void ) -{ -return tick_length; -} -#ifdef CONFIG_GENERIC_CMOS_UPDATE /* Disable the cmos update - used by virtualization and embedded */
kernel/time/timekeeping.c +2 -3
@@ -374,8 +374,7 @@ static __always_inline int clocksource_b* Now calculate the error in (1 << look_ahead) ticks, but first * remove the single look ahead already included in the error. */ - tick_error =current_tick_length () >> - (NTP_SCALE_SHIFT - clock->shift +1 ); + tick_error = tick_length >> (NTP_SCALE_SHIFT - clock->shift +1 ); tick_error -= clock->xtime_interval >>1 ; error = ((error - tick_error) >> look_ahead) + tick_error;
@@ -467,7 +466,7 @@ void update_wall_time(void) }/* accumulate error between NTP and clock interval */ - clock->error +=current_tick_length (); + clock->error += tick_length; clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift); }
Re: [PATCH 7/8] Remove current_tick_length()
Quoted 6 lines · On Fri, 2008-03-14 at 19:40 +0100, [email protected] wrote:
plain text document attachment (
tick_length)current_tick_lengthused to do a little more, but now it just returnstick_length, which we can also access directly at the few places, where it's needed.Signed-off-by Roman Zippel <[email protected]>
Hrm. I'm not sure I like using a global variable instead of using an accessor function. At least with the accessor function folks couldn't just tweak the value outside ntp as easily.
Is there any additional rational for this change?
thanks
-john
Re: [PATCH 7/8] Remove current_tick_length()
Hi,
Quoted 11 lines · john stultz
Quoted 6 lines · On Fri, 2008-03-14 at 19:40 +0100, [email protected] wrote:
plain text document attachment (
tick_length)current_tick_lengthused to do a little more, but now it just returnstick_length, which we can also access directly at the few places, where it's needed.Signed-off-by Roman Zippel <[email protected]>Hrm. I'm not sure I like using a global variable instead of using an accessor function. At least with the accessor function folks couldn't just tweak the value outside ntp as easily.
Why would someone do something silly like this?
Quoted 1 line
Is there any additional rational for this change?
Useless bloat?
bye, Roman
Re: [PATCH 7/8] Remove current_tick_length()
Quoted 10 lines · Roman Zippel
Hi,
Quoted 6 lines · john stultz
Quoted 5 lines · On Fri, 2008-03-14 at 19:40 +0100, [email protected] wrote:
plain text document attachment (
tick_length)current_tick_lengthused to do a little more, but now it just returnstick_length, which we can also access directly at the few places, where it's needed.
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by Roman Zippel <[email protected]>Hrm. I'm not sure I like using a global variable instead of using an accessor function. At least with the accessor function folks couldn't just tweak the value outside ntp as easily.
Why would someone do something silly like this?
Its not a huge deal, but we've seen globally scoped timekeeping variables misused either accidentally or intentionally. Awhile back ppc was corrupting time_offset by using it for a timezone offset value.
So I think its a valid maintainability issue.
Quoted 3 lines
Quoted 1 line
Is there any additional rational for this change?
Useless bloat?
I agree its a trade off. But do you have performance numbers to make the maintainability trade off worth it? (I admit, it is used in the timer_interrupt, so it may very well be worth it, but we might want to check first).
thanks
-john
Re: [PATCH 7/8] Remove current_tick_length()
Hi,
Quoted 7 lines · john stultz
Quoted 1 line
Why would someone do something silly like this?
Its not a huge deal, but we've seen globally scoped timekeeping variables misused either accidentally or intentionally. Awhile back ppc was corrupting
time_offsetby using it for a timezone offset value.So I think its a valid maintainability issue.
ppc used to do a whole lot more than that, so I don't think that counts as a valid example.tick_length is overwritten at every timer and modifying it would have barely any effect compared to other values which are already exported.
Quoted 8 lines
Quoted 3 lines
Quoted 1 line
Is there any additional rational for this change?
Useless bloat?
I agree its a trade off. But do you have performance numbers to make the maintainability trade off worth it? (I admit, it is used in the
timer_interrupt, so it may very well be worth it, but we might want to check first).
It depends on the architecture, but it's effects regularly executed code and every byte counts.
bye, Roman
Re: [PATCH 7/8] Remove current_tick_length()
Quoted 11 lines · Roman Zippel
Quoted 8 lines
Quoted 3 lines
Quoted 1 line
Is there any additional rational for this change?
Useless bloat?
I agree its a trade off. But do you have performance numbers to make the maintainability trade off worth it? (I admit, it is used in the
timer_interrupt, so it may very well be worth it, but we might want to check first).It depends on the architecture, but it's effects regularly executed code and every byte counts.
Then make the original function an inline. With -O2 it should compile to exactly the same thing.
Re: [PATCH 7/8] Remove current_tick_length()
Hi,
Quoted 2 lines · Ray Lee
Then make the original function an inline. With -O2 it should compile to exactly the same thing.
This would also defeat John's intention of keeping the value static.
bye, Roman
Re: [PATCH 7/8] Remove current_tick_length()
Quoted 8 lines · Roman Zippel
Hi,
Quoted 2 lines · Ray Lee
Then make the original function an inline. With -O2 it should compile to exactly the same thing.
This would also defeat John's intention of keeping the value static.
Well, don't mistake me for being fanatical about it. Having the values be static is cleaner, but if its a real performance issue, then clearly performance wins.
I do like Ray's suggestion, and think using the inline'd function is preferred to the raw variable, as it better establishes through use if nothing else, the read-only nature of the value outside of ntp.
thanks
-john
Re: [PATCH 7/8] Remove current_tick_length()
Hi,
Quoted 4 lines · john stultz
Quoted 3 lines · Roman Zippel
Hi,
On Sat, 15 Mar 2008, Ray Lee wrote:
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Then make the original function an inline. With -O2 it should compile to exactly the same thing.
This would also defeat John's intention of keeping the value static.
Well, don't mistake me for being fanatical about it. Having the values be static is cleaner, but if its a real performance issue, then clearly performance wins.
There are two aspects, such functions tend to generate slightly larger and slower code.
Quoted 3 lines
I do like Ray's suggestion, and think using the inline'd function is preferred to the raw variable, as it better establishes through use if nothing else, the read-only nature of the value outside of ntp.
In other languages one would use private or protected for this, but we don't have this. I'm not too fond of an inline function, as it would mark it as some kind of public API, which it isn't. It's just an internal value used by the timekeeping code, which happens to be needed by a few source files. If you want to make a little more private, it would be better to move it to header under kernel/time/.
bye, Roman
PATCH 8/8 handle leap second via timer
In reply to [email protected]Remove the leap second handling from second_overflow(), which doesn't has to check for it every second anymore. With CONFIG_NO_HZ this also makes sure the leap second is handled close to the full second. Additionally this makes it possible to abort a leap second properly by resetting the STA_INS/STA_DEL status bits.
--- include/linux/clocksource.h | 2 include/linux/timex.h | 1 kernel/time/ntp.c | 133 +++++++++++++++++++++++++++++--------------- kernel/time/timekeeping.c | 4 - 4 files changed, 95 insertions(+), 45 deletions(-)
include/linux/timex.h +1 -0
@@ -210,6 +210,7 @@ extern long time_esterror; /* estimatedextern long time_adjust;/* The amount of adjtime left */ +extern void ntp_init (void );extern void ntp_clear (void );/**
kernel/time/ntp.c +90 -43
195 lines not on this page · raw message
kernel/time/timekeeping.c +2 -2
@@ -53,7 +53,7 @@ void update_xtime_cache(u64 nsec)timespec_add_ns (&xtime_cache, nsec); } -static struct clocksource *clock;/* pointer to current clocksource */ +struct clocksource *clock;#ifdef CONFIG_GENERIC_TIME
@@ -241,7 +241,7 @@ void __init timekeeping_init(void)write_seqlock_irqsave (&xtime_lock, flags); -ntp_clear (); +ntp_init (); clock =clocksource_get_next ();clocksource_calculate_interval (clock,NTP_INTERVAL_LENGTH );
include/linux/clocksource.h +2 -0
@@ -93,6 +93,8 @@ struct clocksource {#endif }; +extern struct clocksource *clock;/* current clocksource */ +/* * Clock source flags bits:: */
Re: [PATCH 8/8] handle leap second via timer
Quoted 8 lines · On Fri, 2008-03-14 at 19:40 +0100, [email protected] wrote:
plain text document attachment (
leap_sec)
Remove the leap second handling fromsecond_overflow(), which doesn't has to check for it every second anymore. WithCONFIG_NO_HZthis also makes sure the leap second is handled close to the full second. Additionally this makes it possible to abort a leap second properly by resetting the STA_INS/STA_DEL status bits.Signed-off-by Roman Zippel <[email protected]>
Looks interesting. Small comment below.
Quoted 73 lines
kernel/time/ntp.c +22
-35-void second_overflow (void ) +static enum hrtimer_restart ntp_leap_second (struct hrtimer *timer) { -s64 time_adj; +enum hrtimer_restart res =HRTIMER_NORESTART ; -/* 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 ; - } +write_seqlock_irq (&xtime_lock); -/* -* 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. The microtime() -* routine or external clock driver will insure that reported time is -* always monotonic. The ugly divides should be replaced. -*/ switch (time_state) {case TIME_OK : -if (time_status &STA_INS ) - time_state =TIME_INS ; -else if (time_status &STA_DEL ) - time_state =TIME_DEL ;break ;case TIME_INS : -if (xtime.tv_sec %86400 ==0 ) { - xtime.tv_sec--; - wall_to_monotonic.tv_sec++; - time_state =TIME_OOP ; -printk (KERN_NOTICE "Clock: inserting leap second " -"23:59:60 UTC\n" ); - } + xtime.tv_sec--; + wall_to_monotonic.tv_sec++; + time_state =TIME_OOP ; +printk (KERN_NOTICE "Clock: " +"inserting leap second 23:59:60 UTC\n" ); + leap_timer.expires =ktime_add_ns (leap_timer.expires, +NSEC_PER_SEC ); + res =HRTIMER_RESTART ;break ;case TIME_DEL : -if ((xtime.tv_sec +1 ) %86400 ==0 ) { - xtime.tv_sec++; - time_tai--; - wall_to_monotonic.tv_sec--; - time_state =TIME_WAIT ; -printk (KERN_NOTICE "Clock: deleting leap second " -"23:59:59 UTC\n" ); - } + xtime.tv_sec++; + time_tai--; + wall_to_monotonic.tv_sec--; + time_state =TIME_WAIT ; +printk (KERN_NOTICE "Clock: " +"deleting leap second 23:59:59 UTC\n" );break ;case TIME_OOP : time_tai++; time_state =TIME_WAIT ; -break ; +/* fall through */ case TIME_WAIT :if (!(time_status & (STA_INS |STA_DEL ))) time_state =TIME_OK ; +break ; + } +update_vsyscall (&xtime, clock); +
<snip>
include/linux/clocksource.h struct clocksource { · line 100
Quoted 13 lines
Index:
linux-2.6/include/linux/clocksource.h
===================================================================include/linux/clocksource.h +2
-0@@ -93,6 +93,8 @@ struct clocksource {#endif }; +extern struct clocksource *clock;/* current clocksource */ +/* * Clock source flags bits:: */
Instead of exporting the clocksource making it global, could you use a timekeeping_insert/remove_second() style interface?
That would help remove the xtime/wall_to_monotonic references in ntp.c as well, cleaning up things nicely.
thanks
-john
Re: [PATCH 8/8] handle leap second via timer
Hi,
Quoted 2 lines · john stultz
Instead of exporting the clocksource making it global, could you use a timekeeping_insert/remove_second() style interface?
Sounds good.
bye, Roman
Re: [PATCH 8/8] handle leap second via timer
Quoted 9 lines · On Sat, 15 Mar 2008 04:18:39 +0100 (CET) Roman Zippel <[email protected]>…
Hi,
Quoted 2 lines · john stultz
Instead of exporting the clocksource making it global, could you use a timekeeping_insert/remove_second() style interface?
Sounds good.
It sounds like a few updates are in the pipeline, but I merged this series as-is into -mm.
I'll normally push ntp changes through Thomas's git-hrt tree, however this patch series has dependencies upon at least
introduce-explicit-signed-unsigned-64bit-divide.patch convert-a-few-do_div-user.patch rename-div64_64-to-div64_u64.patch rename-div64_64-to-div64_u64-mm.patch remove-div_long_long_rem.patch
so they can't go into git-hrt immediately.
The idealised algorithm is
- 2.6.26 opens
- Thomas merges git-hrt
- I merge the above patches
- I then send these ntp patches to Thomas
- He merges them into git-hrt
- He does another git-hrt -> Linus merge
And that's all OK, but various lags might cause us to miss the merge window, as I merge the -mm stuff last, and some git-tree maintainers are dawdlers.
So if Thomas wants to ack these I can merge them directly late in the 2.6.26 merge window.
Re: [PATCH 8/8] handle leap second via timer
Quoted 23 lines · Andrew Morton
It sounds like a few updates are in the pipeline, but I merged this series as-is into -mm.
I'll normally push ntp changes through Thomas's git-hrt tree, however this patch series has dependencies upon at least
introduce-explicit-signed-unsigned-64bit-divide.patch convert-a-few-do_div-user.patch rename-div64_64-to-div64_u64.patch rename-div64_64-to-div64_u64-mm.patch remove-div_long_long_rem.patch
so they can't go into git-hrt immediately.
The idealised algorithm is
- 2.6.26 opens
- Thomas merges git-hrt
- I merge the above patches
- I then send these ntp patches to Thomas
- He merges them into git-hrt
- He does another git-hrt -> Linus merge
Quoted 3 lines
And that's all OK, but various lags might cause us to miss the merge window, as I merge the -mm stuff last, and some git-tree maintainers are dawdlers.
:)
Quoted 2 lines
So if Thomas wants to ack these I can merge them directly late in the 2.6.26 merge window.
Fine for me either way.
Thanks,
tglx
Quoted 10 lines · On Fri, 2008-03-14 at 19:40 +0100, [email protected] wrote:
Hi,
These patches clean up the NTP code a little and add the remaining user space bits from the ntp nanokernel, so that it's e.g. now possible to enable the nanosecond resolution, which should be useful to keep time in a local network in sync (but it also needs an updated glibc/ntpd first).
I tried my best to also update the various user space APIs (e.g. compat, vsyscall), but it would be great if someone could look over it, in case I forgot something.
Hey Roman,
BTW, These don't seem to apply to the current -git tree, or Andrew's
-mm. What should I be testing them against?
thanks
-john
Hi,
Quoted 2 lines · john stultz
BTW, These don't seem to apply to the current -git tree, or Andrew's
-mm. What should I be testing them against?
Sorry, I forgot to mentioned that it depends on the div64 patches I recently posted.
bye, Roman