History

ntp: Consolidate the RTC update implementation

The code for the legacy RTC and the RTC class based update are pretty much the same. Consolidate the common parts into one function and just invoke the actual setter functions. For RTC class based devices the update code checks whether the offset is valid for the device, which is usually not the case for the first invocation. If it's not the same it stores the correct offset and lets the caller try again. That's not much different from the previous approach where the first invocation had a pretty low probability to actually hit the allowed window.

Thomas Gleixner committed 5 years ago

Commit 76e87d91 parent 69eca251 file · +52 −92Browse files

Unified · Split

kernel/time/ntp.c+52−92
@@ -564,118 +564,53 @@ static inline bool rtc_tv_nsec_ok(unsigned long set_offset_nsec, · 563 unmodified lines
564 return false;564 return false;
565}565}
566 566
567#ifdef CONFIG_GENERIC_CMOS_UPDATE
568int __weak update_persistent_clock64(struct timespec64 now64)
569{
570 return -ENODEV;
571}
572#else
573static inline int update_persistent_clock64(struct timespec64 now64)
574{
575 return -ENODEV;
576}
577#endif
578
567#ifdef CONFIG_RTC_SYSTOHC579#ifdef CONFIG_RTC_SYSTOHC
568/*580/* Save NTP synchronized time to the RTC */
569 * rtc_set_ntp_time - Save NTP synchronized time to the RTC581static int update_rtc(struct timespec64 *to_set, unsigned long *offset_nsec)
570 */
571static int rtc_set_ntp_time(struct timespec64 now, unsigned long *offset_nsec)
572{582{
573 struct timespec64 to_set;
574 struct rtc_device *rtc;583 struct rtc_device *rtc;
575 struct rtc_time tm;584 struct rtc_time tm;
576 int err = -ENODEV;585 int err = -ENODEV;
577 bool ok;
578 586
579 rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);587 rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
580 if (!rtc)588 if (!rtc)
581 goto out_err;589 return -ENODEV;
582 590
583 if (!rtc->ops || !rtc->ops->set_time)591 if (!rtc->ops || !rtc->ops->set_time)
584 goto out_close;592 goto out_close;
585 593
586 /* Store the update offset for this RTC */594 /* First call might not have the correct offset */
587 *offset_nsec = rtc->set_offset_nsec;595 if (*offset_nsec == rtc->set_offset_nsec) {
588 596 rtc_time64_to_tm(to_set->tv_sec, &tm);
589 ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now);597 err = rtc_set_time(rtc, &tm);
590 if (!ok) {598 } else {
591 err = -EPROTO;599 /* Store the update offset and let the caller try again */
592 goto out_close;600 *offset_nsec = rtc->set_offset_nsec;
601 err = -EAGAIN;
593 }602 }
594
595 rtc_time64_to_tm(to_set.tv_sec, &tm);
596
597 err = rtc_set_time(rtc, &tm);
598
599out_close:603out_close:
600 rtc_class_close(rtc);604 rtc_class_close(rtc);
601out_err:
602 return err;605 return err;
603}606}
604
605static void sync_rtc_clock(void)
606{
607 unsigned long offset_nsec;
608 struct timespec64 adjust;
609 int rc;
610
611 ktime_get_real_ts64(&adjust);
612
613 if (persistent_clock_is_local)
614 adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
615
616 /*
617 * The current RTC in use will provide the nanoseconds offset prior
618 * to a full second it wants to be called at, and invokes
619 * rtc_tv_nsec_ok() internally.
620 */
621 rc = rtc_set_ntp_time(adjust, &offset_nsec);
622 if (rc == -ENODEV)
623 return;
624
625 sched_sync_hw_clock(offset_nsec, rc != 0);
626}
627#else607#else
628static inline void sync_rtc_clock(void) { }608static inline int update_rtc(struct timespec64 *to_set, unsigned long *offset_nsec)
629#endif
630
631#ifdef CONFIG_GENERIC_CMOS_UPDATE
632int __weak update_persistent_clock64(struct timespec64 now64)
633{609{
634 return -ENODEV;610 return -ENODEV;
635}611}
636#endif612#endif
637 613
638static bool sync_cmos_clock(void)
639{
640 static bool no_cmos;
641 struct timespec64 now;
642 struct timespec64 adjust;
643 int rc = -EPROTO;
644 long target_nsec = NSEC_PER_SEC / 2;
645
646 if (!IS_ENABLED(CONFIG_GENERIC_CMOS_UPDATE))
647 return false;
648
649 if (no_cmos)
650 return false;
651
652 /*
653 * Historically update_persistent_clock64() has followed x86
654 * semantics, which match the MC146818A/etc RTC. This RTC will store
655 * 'adjust' and then in .5s it will advance once second.
656 *
657 * Architectures are strongly encouraged to use rtclib and not
658 * implement this legacy API.
659 */
660 ktime_get_real_ts64(&now);
661 if (rtc_tv_nsec_ok(target_nsec, &adjust, &now)) {
662 if (persistent_clock_is_local)
663 adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
664 rc = update_persistent_clock64(adjust);
665 /*
666 * The machine does not support update_persistent_clock64 even
667 * though it defines CONFIG_GENERIC_CMOS_UPDATE.
668 */
669 if (rc == -ENODEV) {
670 no_cmos = true;
671 return false;
672 }
673 }
674
675 sched_sync_hw_clock(target_nsec, rc != 0);
676 return true;
677}
678
679/*614/*
680 * If we have an externally synchronized Linux clock, then update RTC clock615 * If we have an externally synchronized Linux clock, then update RTC clock
681 * accordingly every ~11 minutes. Generally RTCs can only store second616 * accordingly every ~11 minutes. Generally RTCs can only store second
@@ -686,6 +621,15 @@ static bool sync_cmos_clock(void) · 4 unmodified lines
686 */621 */
687static void sync_hw_clock(struct work_struct *work)622static void sync_hw_clock(struct work_struct *work)
688{623{
624 /*
625 * The default synchronization offset is 500ms for the deprecated
626 * update_persistent_clock64() under the assumption that it uses
627 * the infamous CMOS clock (MC146818).
628 */
629 static unsigned long offset_nsec = NSEC_PER_SEC / 2;
630 struct timespec64 now, to_set;
631 int res = -EAGAIN;
632
689 /*633 /*
690 * Don't update if STA_UNSYNC is set and if ntp_notify_cmos_timer()634 * Don't update if STA_UNSYNC is set and if ntp_notify_cmos_timer()
691 * managed to schedule the work between the timer firing and the635 * managed to schedule the work between the timer firing and the
@@ -694,10 +638,26 @@ static void sync_hw_clock(struct work_struct *work) · 2 unmodified lines
694 if (!ntp_synced() || hrtimer_is_queued(&sync_hrtimer))638 if (!ntp_synced() || hrtimer_is_queued(&sync_hrtimer))
695 return;639 return;
696 640
697 if (sync_cmos_clock())641 ktime_get_real_ts64(&now);
698 return;642 /* If @now is not in the allowed window, try again */
643 if (!rtc_tv_nsec_ok(offset_nsec, &to_set, &now))
644 goto rearm;
699 645
700 sync_rtc_clock();646 /* Take timezone adjusted RTCs into account */
647 if (persistent_clock_is_local)
648 to_set.tv_sec -= (sys_tz.tz_minuteswest * 60);
649
650 /* Try the legacy RTC first. */
651 res = update_persistent_clock64(to_set);
652 if (res != -ENODEV)
653 goto rearm;
654
655 /* Try the RTC class */
656 res = update_rtc(&to_set, &offset_nsec);
657 if (res == -ENODEV)
658 return;
659rearm:
660 sched_sync_hw_clock(offset_nsec, res != 0);
701}661}
702 662
703void ntp_notify_cmos_timer(void)663void ntp_notify_cmos_timer(void)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t