Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ntp: Make the RTC sync offset less obscure

The current RTC set_offset_nsec value is not really intuitive to
understand.

tsched twrite(t2.tv_sec - 1) t2 (seconds increment)

The offset is calculated from twrite based on the assumption that t2 -
twrite == 1s. That means for the MC146818 RTC the offset needs to be
negative so that the write happens 500ms before t2.

It's easier to understand when the whole calculation is based on t2. That
avoids negative offsets and the meaning is obvious:

t2 - twrite: The time defined by the chip when seconds increment
after the write.

twrite - tsched: The time for the transport to the point where the chip
is updated.

==> set_offset_nsec = t2 - tsched
ttransport = twrite - tsched
tRTCinc = t2 - twrite
==> set_offset_nsec = ttransport + tRTCinc

tRTCinc is a chip property and can be obtained from the data sheet.

ttransport depends on how the RTC is connected. It is close to 0 for
directly accessible RTCs. For RTCs behind a slow bus, e.g. i2c, it's the
time required to send the update over the bus. This can be estimated or
even calibrated, but that's a different problem.

Adjust the implementation and update comments accordingly.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20201206220542.263204937@linutronix.de

+61 -32
+7 -2
drivers/rtc/class.c
··· 200 200 201 201 device_initialize(&rtc->dev); 202 202 203 - /* Drivers can revise this default after allocating the device. */ 204 - rtc->set_offset_nsec = 5 * NSEC_PER_MSEC; 203 + /* 204 + * Drivers can revise this default after allocating the device. 205 + * The default is what most RTCs do: Increment seconds exactly one 206 + * second after the write happened. This adds a default transport 207 + * time of 5ms which is at least halfways close to reality. 208 + */ 209 + rtc->set_offset_nsec = NSEC_PER_SEC + 5 * NSEC_PER_MSEC; 205 210 206 211 rtc->irq_freq = 1; 207 212 rtc->max_user_freq = 64;
+1 -1
drivers/rtc/rtc-cmos.c
··· 869 869 goto cleanup2; 870 870 871 871 /* Set the sync offset for the periodic 11min update correct */ 872 - cmos_rtc.rtc->set_offset_nsec = -(NSEC_PER_SEC / 2); 872 + cmos_rtc.rtc->set_offset_nsec = NSEC_PER_SEC / 2; 873 873 874 874 /* export at least the first block of NVRAM */ 875 875 nvmem_cfg.size = address_space - NVRAM_OFFSET;
+29 -6
include/linux/rtc.h
··· 110 110 /* Some hardware can't support UIE mode */ 111 111 int uie_unsupported; 112 112 113 - /* Number of nsec it takes to set the RTC clock. This influences when 114 - * the set ops are called. An offset: 115 - * - of 0.5 s will call RTC set for wall clock time 10.0 s at 9.5 s 116 - * - of 1.5 s will call RTC set for wall clock time 10.0 s at 8.5 s 117 - * - of -0.5 s will call RTC set for wall clock time 10.0 s at 10.5 s 113 + /* 114 + * This offset specifies the update timing of the RTC. 115 + * 116 + * tsched t1 write(t2.tv_sec - 1sec)) t2 RTC increments seconds 117 + * 118 + * The offset defines how tsched is computed so that the write to 119 + * the RTC (t2.tv_sec - 1sec) is correct versus the time required 120 + * for the transport of the write and the time which the RTC needs 121 + * to increment seconds the first time after the write (t2). 122 + * 123 + * For direct accessible RTCs tsched ~= t1 because the write time 124 + * is negligible. For RTCs behind slow busses the transport time is 125 + * significant and has to be taken into account. 126 + * 127 + * The time between the write (t1) and the first increment after 128 + * the write (t2) is RTC specific. For a MC146818 RTC it's 500ms, 129 + * for many others it's exactly 1 second. Consult the datasheet. 130 + * 131 + * The value of this offset is also used to calculate the to be 132 + * written value (t2.tv_sec - 1sec) at tsched. 133 + * 134 + * The default value for this is NSEC_PER_SEC + 10 msec default 135 + * transport time. The offset can be adjusted by drivers so the 136 + * calculation for the to be written value at tsched becomes 137 + * correct: 138 + * 139 + * newval = tsched + set_offset_nsec - NSEC_PER_SEC 140 + * and (tsched + set_offset_nsec) % NSEC_PER_SEC == 0 118 141 */ 119 - long set_offset_nsec; 142 + unsigned long set_offset_nsec; 120 143 121 144 bool registered; 122 145
+24 -23
kernel/time/ntp.c
··· 520 520 } 521 521 522 522 /* 523 - * Determine if we can call to driver to set the time. Drivers can only be 524 - * called to set a second aligned time value, and the field set_offset_nsec 525 - * specifies how far away from the second aligned time to call the driver. 523 + * Check whether @now is correct versus the required time to update the RTC 524 + * and calculate the value which needs to be written to the RTC so that the 525 + * next seconds increment of the RTC after the write is aligned with the next 526 + * seconds increment of clock REALTIME. 526 527 * 527 - * This also computes 'to_set' which is the time we are trying to set, and has 528 - * a zero in tv_nsecs, such that: 529 - * to_set - set_delay_nsec == now +/- FUZZ 528 + * tsched t1 write(t2.tv_sec - 1sec)) t2 RTC increments seconds 530 529 * 530 + * t2.tv_nsec == 0 531 + * tsched = t2 - set_offset_nsec 532 + * newval = t2 - NSEC_PER_SEC 533 + * 534 + * ==> neval = tsched + set_offset_nsec - NSEC_PER_SEC 535 + * 536 + * As the execution of this code is not guaranteed to happen exactly at 537 + * tsched this allows it to happen within a fuzzy region: 538 + * 539 + * abs(now - tsched) < FUZZ 540 + * 541 + * If @now is not inside the allowed window the function returns false. 531 542 */ 532 - static inline bool rtc_tv_nsec_ok(long set_offset_nsec, 543 + static inline bool rtc_tv_nsec_ok(unsigned long set_offset_nsec, 533 544 struct timespec64 *to_set, 534 545 const struct timespec64 *now) 535 546 { 536 547 /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */ 537 548 const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5; 538 - struct timespec64 delay = {.tv_sec = 0, 549 + struct timespec64 delay = {.tv_sec = -1, 539 550 .tv_nsec = set_offset_nsec}; 540 551 541 552 *to_set = timespec64_add(*now, delay); ··· 568 557 /* 569 558 * rtc_set_ntp_time - Save NTP synchronized time to the RTC 570 559 */ 571 - static int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec) 560 + static int rtc_set_ntp_time(struct timespec64 now, unsigned long *offset_nsec) 572 561 { 562 + struct timespec64 to_set; 573 563 struct rtc_device *rtc; 574 564 struct rtc_time tm; 575 - struct timespec64 to_set; 576 565 int err = -ENODEV; 577 566 bool ok; 578 567 ··· 583 572 if (!rtc->ops || !rtc->ops->set_time) 584 573 goto out_close; 585 574 586 - /* 587 - * Compute the value of tv_nsec we require the caller to supply in 588 - * now.tv_nsec. This is the value such that (now + 589 - * set_offset_nsec).tv_nsec == 0. 590 - */ 591 - set_normalized_timespec64(&to_set, 0, -rtc->set_offset_nsec); 592 - *target_nsec = to_set.tv_nsec; 575 + /* Store the update offset for this RTC */ 576 + *offset_nsec = rtc->set_offset_nsec; 593 577 594 - /* 595 - * The ntp code must call this with the correct value in tv_nsec, if 596 - * it does not we update target_nsec and return EPROTO to make the ntp 597 - * code try again later. 598 - */ 599 578 ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now); 600 579 if (!ok) { 601 580 err = -EPROTO; ··· 658 657 * implement this legacy API. 659 658 */ 660 659 ktime_get_real_ts64(&now); 661 - if (rtc_tv_nsec_ok(-1 * target_nsec, &adjust, &now)) { 660 + if (rtc_tv_nsec_ok(target_nsec, &adjust, &now)) { 662 661 if (persistent_clock_is_local) 663 662 adjust.tv_sec -= (sys_tz.tz_minuteswest * 60); 664 663 rc = update_persistent_clock64(adjust);