diff options
author | John Stultz <john.stultz@linaro.org> | 2012-05-03 15:30:07 -0400 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2013-03-22 19:19:58 -0400 |
commit | cc244ddae6d4c6902ac9d7d64023534f8c44a7eb (patch) | |
tree | 9f9e26d214bd0113d8722c0a683e003cbc1bf165 /kernel | |
parent | e445cf1c4257cc0238d72e4129eb4739f46fd3de (diff) |
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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/time/ntp.c | 18 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 44 |
2 files changed, 54 insertions, 8 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 072bb066bb7d..59e2749be0fa 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -53,9 +53,6 @@ static int time_state = TIME_OK; | |||
53 | /* clock status bits: */ | 53 | /* clock status bits: */ |
54 | static int time_status = STA_UNSYNC; | 54 | static int time_status = STA_UNSYNC; |
55 | 55 | ||
56 | /* TAI offset (secs): */ | ||
57 | static long time_tai; | ||
58 | |||
59 | /* time adjustment (nsecs): */ | 56 | /* time adjustment (nsecs): */ |
60 | static s64 time_offset; | 57 | static s64 time_offset; |
61 | 58 | ||
@@ -415,7 +412,6 @@ int second_overflow(unsigned long secs) | |||
415 | else if (secs % 86400 == 0) { | 412 | else if (secs % 86400 == 0) { |
416 | leap = -1; | 413 | leap = -1; |
417 | time_state = TIME_OOP; | 414 | time_state = TIME_OOP; |
418 | time_tai++; | ||
419 | printk(KERN_NOTICE | 415 | printk(KERN_NOTICE |
420 | "Clock: inserting leap second 23:59:60 UTC\n"); | 416 | "Clock: inserting leap second 23:59:60 UTC\n"); |
421 | } | 417 | } |
@@ -425,7 +421,6 @@ int second_overflow(unsigned long secs) | |||
425 | time_state = TIME_OK; | 421 | time_state = TIME_OK; |
426 | else if ((secs + 1) % 86400 == 0) { | 422 | else if ((secs + 1) % 86400 == 0) { |
427 | leap = 1; | 423 | leap = 1; |
428 | time_tai--; | ||
429 | time_state = TIME_WAIT; | 424 | time_state = TIME_WAIT; |
430 | printk(KERN_NOTICE | 425 | printk(KERN_NOTICE |
431 | "Clock: deleting leap second 23:59:59 UTC\n"); | 426 | "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) | |||
579 | * Called with ntp_lock held, so we can access and modify | 574 | * Called with ntp_lock held, so we can access and modify |
580 | * all the global NTP state: | 575 | * all the global NTP state: |
581 | */ | 576 | */ |
582 | static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts) | 577 | static inline void process_adjtimex_modes(struct timex *txc, |
578 | struct timespec *ts, | ||
579 | s32 *time_tai) | ||
583 | { | 580 | { |
584 | if (txc->modes & ADJ_STATUS) | 581 | if (txc->modes & ADJ_STATUS) |
585 | process_adj_status(txc, ts); | 582 | process_adj_status(txc, ts); |
@@ -613,7 +610,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts | |||
613 | } | 610 | } |
614 | 611 | ||
615 | if (txc->modes & ADJ_TAI && txc->constant > 0) | 612 | if (txc->modes & ADJ_TAI && txc->constant > 0) |
616 | time_tai = txc->constant; | 613 | *time_tai = txc->constant; |
617 | 614 | ||
618 | if (txc->modes & ADJ_OFFSET) | 615 | if (txc->modes & ADJ_OFFSET) |
619 | ntp_update_offset(txc->offset); | 616 | ntp_update_offset(txc->offset); |
@@ -632,6 +629,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts | |||
632 | int do_adjtimex(struct timex *txc) | 629 | int do_adjtimex(struct timex *txc) |
633 | { | 630 | { |
634 | struct timespec ts; | 631 | struct timespec ts; |
632 | u32 time_tai, orig_tai; | ||
635 | int result; | 633 | int result; |
636 | 634 | ||
637 | /* Validate the data before disabling interrupts */ | 635 | /* Validate the data before disabling interrupts */ |
@@ -671,6 +669,7 @@ int do_adjtimex(struct timex *txc) | |||
671 | } | 669 | } |
672 | 670 | ||
673 | getnstimeofday(&ts); | 671 | getnstimeofday(&ts); |
672 | orig_tai = time_tai = timekeeping_get_tai_offset(); | ||
674 | 673 | ||
675 | raw_spin_lock_irq(&ntp_lock); | 674 | raw_spin_lock_irq(&ntp_lock); |
676 | 675 | ||
@@ -687,7 +686,7 @@ int do_adjtimex(struct timex *txc) | |||
687 | 686 | ||
688 | /* If there are input parameters, then process them: */ | 687 | /* If there are input parameters, then process them: */ |
689 | if (txc->modes) | 688 | if (txc->modes) |
690 | process_adjtimex_modes(txc, &ts); | 689 | process_adjtimex_modes(txc, &ts, &time_tai); |
691 | 690 | ||
692 | txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, | 691 | txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, |
693 | NTP_SCALE_SHIFT); | 692 | NTP_SCALE_SHIFT); |
@@ -716,6 +715,9 @@ int do_adjtimex(struct timex *txc) | |||
716 | 715 | ||
717 | raw_spin_unlock_irq(&ntp_lock); | 716 | raw_spin_unlock_irq(&ntp_lock); |
718 | 717 | ||
718 | if (time_tai != orig_tai) | ||
719 | timekeeping_set_tai_offset(time_tai); | ||
720 | |||
719 | txc->time.tv_sec = ts.tv_sec; | 721 | txc->time.tv_sec = ts.tv_sec; |
720 | txc->time.tv_usec = ts.tv_nsec; | 722 | txc->time.tv_usec = ts.tv_nsec; |
721 | if (!(time_status & STA_NANO)) | 723 | if (!(time_status & STA_NANO)) |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 0355f125d585..937098aab498 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -513,6 +513,48 @@ error: /* even if we error out, we forwarded the time, so call update */ | |||
513 | } | 513 | } |
514 | EXPORT_SYMBOL(timekeeping_inject_offset); | 514 | EXPORT_SYMBOL(timekeeping_inject_offset); |
515 | 515 | ||
516 | |||
517 | /** | ||
518 | * timekeeping_get_tai_offset - Returns current TAI offset from UTC | ||
519 | * | ||
520 | */ | ||
521 | s32 timekeeping_get_tai_offset(void) | ||
522 | { | ||
523 | struct timekeeper *tk = &timekeeper; | ||
524 | unsigned int seq; | ||
525 | s32 ret; | ||
526 | |||
527 | do { | ||
528 | seq = read_seqbegin(&tk->lock); | ||
529 | ret = tk->tai_offset; | ||
530 | } while (read_seqretry(&tk->lock, seq)); | ||
531 | |||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | /** | ||
536 | * __timekeeping_set_tai_offset - Lock free worker function | ||
537 | * | ||
538 | */ | ||
539 | void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) | ||
540 | { | ||
541 | tk->tai_offset = tai_offset; | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * timekeeping_set_tai_offset - Sets the current TAI offset from UTC | ||
546 | * | ||
547 | */ | ||
548 | void timekeeping_set_tai_offset(s32 tai_offset) | ||
549 | { | ||
550 | struct timekeeper *tk = &timekeeper; | ||
551 | unsigned long flags; | ||
552 | |||
553 | write_seqlock_irqsave(&tk->lock, flags); | ||
554 | __timekeeping_set_tai_offset(tk, tai_offset); | ||
555 | write_sequnlock_irqrestore(&tk->lock, flags); | ||
556 | } | ||
557 | |||
516 | /** | 558 | /** |
517 | * change_clocksource - Swaps clocksources if a new one is available | 559 | * change_clocksource - Swaps clocksources if a new one is available |
518 | * | 560 | * |
@@ -1143,6 +1185,8 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk) | |||
1143 | tk_set_wall_to_mono(tk, | 1185 | tk_set_wall_to_mono(tk, |
1144 | timespec_sub(tk->wall_to_monotonic, ts)); | 1186 | timespec_sub(tk->wall_to_monotonic, ts)); |
1145 | 1187 | ||
1188 | __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); | ||
1189 | |||
1146 | clock_was_set_delayed(); | 1190 | clock_was_set_delayed(); |
1147 | } | 1191 | } |
1148 | } | 1192 | } |