diff options
Diffstat (limited to 'kernel/time/ntp.c')
| -rw-r--r-- | kernel/time/ntp.c | 134 |
1 files changed, 42 insertions, 92 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 6e039b144daf..f03fd83b170b 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
| @@ -34,8 +34,6 @@ unsigned long tick_nsec; | |||
| 34 | static u64 tick_length; | 34 | static u64 tick_length; |
| 35 | static u64 tick_length_base; | 35 | static u64 tick_length_base; |
| 36 | 36 | ||
| 37 | static struct hrtimer leap_timer; | ||
| 38 | |||
| 39 | #define MAX_TICKADJ 500LL /* usecs */ | 37 | #define MAX_TICKADJ 500LL /* usecs */ |
| 40 | #define MAX_TICKADJ_SCALED \ | 38 | #define MAX_TICKADJ_SCALED \ |
| 41 | (((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) | 39 | (((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) |
| @@ -381,70 +379,63 @@ u64 ntp_tick_length(void) | |||
| 381 | 379 | ||
| 382 | 380 | ||
| 383 | /* | 381 | /* |
| 384 | * Leap second processing. If in leap-insert state at the end of the | 382 | * this routine handles the overflow of the microsecond field |
| 385 | * day, the system clock is set back one second; if in leap-delete | 383 | * |
| 386 | * state, the system clock is set ahead one second. | 384 | * The tricky bits of code to handle the accurate clock support |
| 385 | * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. | ||
| 386 | * They were originally developed for SUN and DEC kernels. | ||
| 387 | * All the kudos should go to Dave for this stuff. | ||
| 388 | * | ||
| 389 | * Also handles leap second processing, and returns leap offset | ||
| 387 | */ | 390 | */ |
| 388 | static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer) | 391 | int second_overflow(unsigned long secs) |
| 389 | { | 392 | { |
| 390 | enum hrtimer_restart res = HRTIMER_NORESTART; | 393 | s64 delta; |
| 391 | unsigned long flags; | ||
| 392 | int leap = 0; | 394 | int leap = 0; |
| 395 | unsigned long flags; | ||
| 393 | 396 | ||
| 394 | spin_lock_irqsave(&ntp_lock, flags); | 397 | spin_lock_irqsave(&ntp_lock, flags); |
| 398 | |||
| 399 | /* | ||
| 400 | * Leap second processing. If in leap-insert state at the end of the | ||
| 401 | * day, the system clock is set back one second; if in leap-delete | ||
| 402 | * state, the system clock is set ahead one second. | ||
| 403 | */ | ||
| 395 | switch (time_state) { | 404 | switch (time_state) { |
| 396 | case TIME_OK: | 405 | case TIME_OK: |
| 406 | if (time_status & STA_INS) | ||
| 407 | time_state = TIME_INS; | ||
| 408 | else if (time_status & STA_DEL) | ||
| 409 | time_state = TIME_DEL; | ||
| 397 | break; | 410 | break; |
| 398 | case TIME_INS: | 411 | case TIME_INS: |
| 399 | leap = -1; | 412 | if (secs % 86400 == 0) { |
| 400 | time_state = TIME_OOP; | 413 | leap = -1; |
| 401 | printk(KERN_NOTICE | 414 | time_state = TIME_OOP; |
| 402 | "Clock: inserting leap second 23:59:60 UTC\n"); | 415 | printk(KERN_NOTICE |
| 403 | hrtimer_add_expires_ns(&leap_timer, NSEC_PER_SEC); | 416 | "Clock: inserting leap second 23:59:60 UTC\n"); |
| 404 | res = HRTIMER_RESTART; | 417 | } |
| 405 | break; | 418 | break; |
| 406 | case TIME_DEL: | 419 | case TIME_DEL: |
| 407 | leap = 1; | 420 | if ((secs + 1) % 86400 == 0) { |
| 408 | time_tai--; | 421 | leap = 1; |
| 409 | time_state = TIME_WAIT; | 422 | time_tai--; |
| 410 | printk(KERN_NOTICE | 423 | time_state = TIME_WAIT; |
| 411 | "Clock: deleting leap second 23:59:59 UTC\n"); | 424 | printk(KERN_NOTICE |
| 425 | "Clock: deleting leap second 23:59:59 UTC\n"); | ||
| 426 | } | ||
| 412 | break; | 427 | break; |
| 413 | case TIME_OOP: | 428 | case TIME_OOP: |
| 414 | time_tai++; | 429 | time_tai++; |
| 415 | time_state = TIME_WAIT; | 430 | time_state = TIME_WAIT; |
| 416 | /* fall through */ | 431 | break; |
| 432 | |||
| 417 | case TIME_WAIT: | 433 | case TIME_WAIT: |
| 418 | if (!(time_status & (STA_INS | STA_DEL))) | 434 | if (!(time_status & (STA_INS | STA_DEL))) |
| 419 | time_state = TIME_OK; | 435 | time_state = TIME_OK; |
| 420 | break; | 436 | break; |
| 421 | } | 437 | } |
| 422 | spin_unlock_irqrestore(&ntp_lock, flags); | ||
| 423 | 438 | ||
| 424 | /* | ||
| 425 | * We have to call this outside of the ntp_lock to keep | ||
| 426 | * the proper locking hierarchy | ||
| 427 | */ | ||
| 428 | if (leap) | ||
| 429 | timekeeping_leap_insert(leap); | ||
| 430 | |||
| 431 | return res; | ||
| 432 | } | ||
| 433 | |||
| 434 | /* | ||
| 435 | * this routine handles the overflow of the microsecond field | ||
| 436 | * | ||
| 437 | * The tricky bits of code to handle the accurate clock support | ||
| 438 | * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. | ||
| 439 | * They were originally developed for SUN and DEC kernels. | ||
| 440 | * All the kudos should go to Dave for this stuff. | ||
| 441 | */ | ||
| 442 | void second_overflow(void) | ||
| 443 | { | ||
| 444 | s64 delta; | ||
| 445 | unsigned long flags; | ||
| 446 | |||
| 447 | spin_lock_irqsave(&ntp_lock, flags); | ||
| 448 | 439 | ||
| 449 | /* Bump the maxerror field */ | 440 | /* Bump the maxerror field */ |
| 450 | time_maxerror += MAXFREQ / NSEC_PER_USEC; | 441 | time_maxerror += MAXFREQ / NSEC_PER_USEC; |
| @@ -481,15 +472,17 @@ void second_overflow(void) | |||
| 481 | tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ) | 472 | tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ) |
| 482 | << NTP_SCALE_SHIFT; | 473 | << NTP_SCALE_SHIFT; |
| 483 | time_adjust = 0; | 474 | time_adjust = 0; |
| 475 | |||
| 476 | |||
| 477 | |||
| 484 | out: | 478 | out: |
| 485 | spin_unlock_irqrestore(&ntp_lock, flags); | 479 | spin_unlock_irqrestore(&ntp_lock, flags); |
| 480 | |||
| 481 | return leap; | ||
| 486 | } | 482 | } |
| 487 | 483 | ||
| 488 | #ifdef CONFIG_GENERIC_CMOS_UPDATE | 484 | #ifdef CONFIG_GENERIC_CMOS_UPDATE |
| 489 | 485 | ||
| 490 | /* Disable the cmos update - used by virtualization and embedded */ | ||
| 491 | int no_sync_cmos_clock __read_mostly; | ||
| 492 | |||
| 493 | static void sync_cmos_clock(struct work_struct *work); | 486 | static void sync_cmos_clock(struct work_struct *work); |
| 494 | 487 | ||
| 495 | static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); | 488 | static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); |
| @@ -536,35 +529,13 @@ static void sync_cmos_clock(struct work_struct *work) | |||
| 536 | 529 | ||
| 537 | static void notify_cmos_timer(void) | 530 | static void notify_cmos_timer(void) |
| 538 | { | 531 | { |
| 539 | if (!no_sync_cmos_clock) | 532 | schedule_delayed_work(&sync_cmos_work, 0); |
| 540 | schedule_delayed_work(&sync_cmos_work, 0); | ||
| 541 | } | 533 | } |
| 542 | 534 | ||
| 543 | #else | 535 | #else |
| 544 | static inline void notify_cmos_timer(void) { } | 536 | static inline void notify_cmos_timer(void) { } |
| 545 | #endif | 537 | #endif |
| 546 | 538 | ||
| 547 | /* | ||
| 548 | * Start the leap seconds timer: | ||
| 549 | */ | ||
| 550 | static inline void ntp_start_leap_timer(struct timespec *ts) | ||
| 551 | { | ||
| 552 | long now = ts->tv_sec; | ||
| 553 | |||
| 554 | if (time_status & STA_INS) { | ||
| 555 | time_state = TIME_INS; | ||
| 556 | now += 86400 - now % 86400; | ||
| 557 | hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS); | ||
| 558 | |||
| 559 | return; | ||
| 560 | } | ||
| 561 | |||
| 562 | if (time_status & STA_DEL) { | ||
| 563 | time_state = TIME_DEL; | ||
| 564 | now += 86400 - (now + 1) % 86400; | ||
| 565 | hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS); | ||
| 566 | } | ||
| 567 | } | ||
| 568 | 539 | ||
| 569 | /* | 540 | /* |
| 570 | * Propagate a new txc->status value into the NTP state: | 541 | * Propagate a new txc->status value into the NTP state: |
| @@ -589,22 +560,6 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts) | |||
| 589 | time_status &= STA_RONLY; | 560 | time_status &= STA_RONLY; |
| 590 | time_status |= txc->status & ~STA_RONLY; | 561 | time_status |= txc->status & ~STA_RONLY; |
| 591 | 562 | ||
| 592 | switch (time_state) { | ||
| 593 | case TIME_OK: | ||
| 594 | ntp_start_leap_timer(ts); | ||
| 595 | break; | ||
| 596 | case TIME_INS: | ||
| 597 | case TIME_DEL: | ||
| 598 | time_state = TIME_OK; | ||
| 599 | ntp_start_leap_timer(ts); | ||
| 600 | case TIME_WAIT: | ||
| 601 | if (!(time_status & (STA_INS | STA_DEL))) | ||
| 602 | time_state = TIME_OK; | ||
| 603 | break; | ||
| 604 | case TIME_OOP: | ||
| 605 | hrtimer_restart(&leap_timer); | ||
| 606 | break; | ||
| 607 | } | ||
| 608 | } | 563 | } |
| 609 | /* | 564 | /* |
| 610 | * Called with the xtime lock held, so we can access and modify | 565 | * Called with the xtime lock held, so we can access and modify |
| @@ -686,9 +641,6 @@ int do_adjtimex(struct timex *txc) | |||
| 686 | (txc->tick < 900000/USER_HZ || | 641 | (txc->tick < 900000/USER_HZ || |
| 687 | txc->tick > 1100000/USER_HZ)) | 642 | txc->tick > 1100000/USER_HZ)) |
| 688 | return -EINVAL; | 643 | return -EINVAL; |
| 689 | |||
| 690 | if (txc->modes & ADJ_STATUS && time_state != TIME_OK) | ||
| 691 | hrtimer_cancel(&leap_timer); | ||
| 692 | } | 644 | } |
| 693 | 645 | ||
| 694 | if (txc->modes & ADJ_SETOFFSET) { | 646 | if (txc->modes & ADJ_SETOFFSET) { |
| @@ -1010,6 +962,4 @@ __setup("ntp_tick_adj=", ntp_tick_adj_setup); | |||
| 1010 | void __init ntp_init(void) | 962 | void __init ntp_init(void) |
| 1011 | { | 963 | { |
| 1012 | ntp_clear(); | 964 | ntp_clear(); |
| 1013 | hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); | ||
| 1014 | leap_timer.function = ntp_leap_second; | ||
| 1015 | } | 965 | } |
