timekeeping: Move TAI managment into timekeeping core from ntp
Currently NTP manages the TAI offset. Since there's plans for a CLOCK_TAI clockid, push the TAI management into the timekeeping core. CC: Thomas Gleixner <tglx@linutronix.de> CC: Eric Dumazet <eric.dumazet@gmail.com> CC: Richard Cochran <richardcochran@gmail.com> Signed-off-by: John Stultz <john.stultz@linaro.org>
This commit is contained in:
parent
e445cf1c42
commit
cc244ddae6
|
@ -181,6 +181,8 @@ extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
|
||||||
extern int timekeeping_valid_for_hres(void);
|
extern int timekeeping_valid_for_hres(void);
|
||||||
extern u64 timekeeping_max_deferment(void);
|
extern u64 timekeeping_max_deferment(void);
|
||||||
extern int timekeeping_inject_offset(struct timespec *ts);
|
extern int timekeeping_inject_offset(struct timespec *ts);
|
||||||
|
extern s32 timekeeping_get_tai_offset(void);
|
||||||
|
extern void timekeeping_set_tai_offset(s32 tai_offset);
|
||||||
|
|
||||||
struct tms;
|
struct tms;
|
||||||
extern void do_sys_times(struct tms *);
|
extern void do_sys_times(struct tms *);
|
||||||
|
|
|
@ -62,6 +62,9 @@ struct timekeeper {
|
||||||
ktime_t offs_boot;
|
ktime_t offs_boot;
|
||||||
/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
|
/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
|
||||||
struct timespec raw_time;
|
struct timespec raw_time;
|
||||||
|
/* The current UTC to TAI offset in seconds */
|
||||||
|
s32 tai_offset;
|
||||||
|
|
||||||
/* Seqlock for all timekeeper values */
|
/* Seqlock for all timekeeper values */
|
||||||
seqlock_t lock;
|
seqlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,9 +53,6 @@ static int time_state = TIME_OK;
|
||||||
/* clock status bits: */
|
/* clock status bits: */
|
||||||
static int time_status = STA_UNSYNC;
|
static int time_status = STA_UNSYNC;
|
||||||
|
|
||||||
/* TAI offset (secs): */
|
|
||||||
static long time_tai;
|
|
||||||
|
|
||||||
/* time adjustment (nsecs): */
|
/* time adjustment (nsecs): */
|
||||||
static s64 time_offset;
|
static s64 time_offset;
|
||||||
|
|
||||||
|
@ -415,7 +412,6 @@ int second_overflow(unsigned long secs)
|
||||||
else if (secs % 86400 == 0) {
|
else if (secs % 86400 == 0) {
|
||||||
leap = -1;
|
leap = -1;
|
||||||
time_state = TIME_OOP;
|
time_state = TIME_OOP;
|
||||||
time_tai++;
|
|
||||||
printk(KERN_NOTICE
|
printk(KERN_NOTICE
|
||||||
"Clock: inserting leap second 23:59:60 UTC\n");
|
"Clock: inserting leap second 23:59:60 UTC\n");
|
||||||
}
|
}
|
||||||
|
@ -425,7 +421,6 @@ int second_overflow(unsigned long secs)
|
||||||
time_state = TIME_OK;
|
time_state = TIME_OK;
|
||||||
else if ((secs + 1) % 86400 == 0) {
|
else if ((secs + 1) % 86400 == 0) {
|
||||||
leap = 1;
|
leap = 1;
|
||||||
time_tai--;
|
|
||||||
time_state = TIME_WAIT;
|
time_state = TIME_WAIT;
|
||||||
printk(KERN_NOTICE
|
printk(KERN_NOTICE
|
||||||
"Clock: deleting leap second 23:59:59 UTC\n");
|
"Clock: deleting leap second 23:59:59 UTC\n");
|
||||||
|
@ -579,7 +574,9 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
|
||||||
* Called with ntp_lock held, so we can access and modify
|
* Called with ntp_lock held, so we can access and modify
|
||||||
* all the global NTP state:
|
* all the global NTP state:
|
||||||
*/
|
*/
|
||||||
static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts)
|
static inline void process_adjtimex_modes(struct timex *txc,
|
||||||
|
struct timespec *ts,
|
||||||
|
s32 *time_tai)
|
||||||
{
|
{
|
||||||
if (txc->modes & ADJ_STATUS)
|
if (txc->modes & ADJ_STATUS)
|
||||||
process_adj_status(txc, ts);
|
process_adj_status(txc, ts);
|
||||||
|
@ -613,7 +610,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts
|
||||||
}
|
}
|
||||||
|
|
||||||
if (txc->modes & ADJ_TAI && txc->constant > 0)
|
if (txc->modes & ADJ_TAI && txc->constant > 0)
|
||||||
time_tai = txc->constant;
|
*time_tai = txc->constant;
|
||||||
|
|
||||||
if (txc->modes & ADJ_OFFSET)
|
if (txc->modes & ADJ_OFFSET)
|
||||||
ntp_update_offset(txc->offset);
|
ntp_update_offset(txc->offset);
|
||||||
|
@ -632,6 +629,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts
|
||||||
int do_adjtimex(struct timex *txc)
|
int do_adjtimex(struct timex *txc)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
u32 time_tai, orig_tai;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* Validate the data before disabling interrupts */
|
/* Validate the data before disabling interrupts */
|
||||||
|
@ -671,6 +669,7 @@ int do_adjtimex(struct timex *txc)
|
||||||
}
|
}
|
||||||
|
|
||||||
getnstimeofday(&ts);
|
getnstimeofday(&ts);
|
||||||
|
orig_tai = time_tai = timekeeping_get_tai_offset();
|
||||||
|
|
||||||
raw_spin_lock_irq(&ntp_lock);
|
raw_spin_lock_irq(&ntp_lock);
|
||||||
|
|
||||||
|
@ -687,7 +686,7 @@ int do_adjtimex(struct timex *txc)
|
||||||
|
|
||||||
/* If there are input parameters, then process them: */
|
/* If there are input parameters, then process them: */
|
||||||
if (txc->modes)
|
if (txc->modes)
|
||||||
process_adjtimex_modes(txc, &ts);
|
process_adjtimex_modes(txc, &ts, &time_tai);
|
||||||
|
|
||||||
txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
|
txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
|
||||||
NTP_SCALE_SHIFT);
|
NTP_SCALE_SHIFT);
|
||||||
|
@ -716,6 +715,9 @@ int do_adjtimex(struct timex *txc)
|
||||||
|
|
||||||
raw_spin_unlock_irq(&ntp_lock);
|
raw_spin_unlock_irq(&ntp_lock);
|
||||||
|
|
||||||
|
if (time_tai != orig_tai)
|
||||||
|
timekeeping_set_tai_offset(time_tai);
|
||||||
|
|
||||||
txc->time.tv_sec = ts.tv_sec;
|
txc->time.tv_sec = ts.tv_sec;
|
||||||
txc->time.tv_usec = ts.tv_nsec;
|
txc->time.tv_usec = ts.tv_nsec;
|
||||||
if (!(time_status & STA_NANO))
|
if (!(time_status & STA_NANO))
|
||||||
|
|
|
@ -513,6 +513,48 @@ error: /* even if we error out, we forwarded the time, so call update */
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(timekeeping_inject_offset);
|
EXPORT_SYMBOL(timekeeping_inject_offset);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* timekeeping_get_tai_offset - Returns current TAI offset from UTC
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
s32 timekeeping_get_tai_offset(void)
|
||||||
|
{
|
||||||
|
struct timekeeper *tk = &timekeeper;
|
||||||
|
unsigned int seq;
|
||||||
|
s32 ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
seq = read_seqbegin(&tk->lock);
|
||||||
|
ret = tk->tai_offset;
|
||||||
|
} while (read_seqretry(&tk->lock, seq));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __timekeeping_set_tai_offset - Lock free worker function
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset)
|
||||||
|
{
|
||||||
|
tk->tai_offset = tai_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* timekeeping_set_tai_offset - Sets the current TAI offset from UTC
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void timekeeping_set_tai_offset(s32 tai_offset)
|
||||||
|
{
|
||||||
|
struct timekeeper *tk = &timekeeper;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
write_seqlock_irqsave(&tk->lock, flags);
|
||||||
|
__timekeeping_set_tai_offset(tk, tai_offset);
|
||||||
|
write_sequnlock_irqrestore(&tk->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* change_clocksource - Swaps clocksources if a new one is available
|
* change_clocksource - Swaps clocksources if a new one is available
|
||||||
*
|
*
|
||||||
|
@ -1143,6 +1185,8 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)
|
||||||
tk_set_wall_to_mono(tk,
|
tk_set_wall_to_mono(tk,
|
||||||
timespec_sub(tk->wall_to_monotonic, ts));
|
timespec_sub(tk->wall_to_monotonic, ts));
|
||||||
|
|
||||||
|
__timekeeping_set_tai_offset(tk, tk->tai_offset - leap);
|
||||||
|
|
||||||
clock_was_set_delayed();
|
clock_was_set_delayed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue