summaryrefslogtreecommitdiffstats
path: root/include/linux/rtc.h
diff options
context:
space:
mode:
authorJason Gunthorpe <jgunthorpe@obsidianresearch.com>2017-10-13 13:54:33 -0400
committerJohn Stultz <john.stultz@linaro.org>2017-10-30 18:03:24 -0400
commit0f295b0650c90362b4111f46d7f9149a0a4191be (patch)
tree4589b6e58d710ac1f2967317305c6c8fc28903d3 /include/linux/rtc.h
parent9e66317d3c92ddaab330c125dfe9d06eee268aff (diff)
rtc: Allow rtc drivers to specify the tv_nsec value for ntp
ntp is currently hardwired to try and call the rtc set when wall clock tv_nsec is 0.5 seconds. This historical behaviour works well with certain PC RTCs, but is not universal to all rtc hardware. Change how this works by introducing the driver specific concept of set_offset_nsec, the delay between current wall clock time and the target time to set (with a 0 tv_nsecs). For x86-style CMOS set_offset_nsec should be -0.5 s which causes the last second to be written 0.5 s after it has started. For compat with the old rtc_set_ntp_time, the value is defaulted to + 0.5 s, which causes the next second to be written 0.5s before it starts, as things were before this patch. Testing shows many non-x86 RTCs would like set_offset_nsec ~= 0, so ultimately each RTC driver should set the set_offset_nsec according to its needs, and non x86 architectures should stop using update_persistent_clock64 in order to access this feature. Future patches will revise the drivers as needed. Since CMOS and RTC now have very different handling they are split into two dedicated code paths, sharing the support code, and ifdefs are replaced with IS_ENABLED. Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@kernel.org> Cc: Miroslav Lichvar <mlichvar@redhat.com> Cc: Richard Cochran <richardcochran@gmail.com> Cc: Prarit Bhargava <prarit@redhat.com> Cc: Stephen Boyd <stephen.boyd@linaro.org> Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'include/linux/rtc.h')
-rw-r--r--include/linux/rtc.h43
1 files changed, 42 insertions, 1 deletions
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index e6d0f9c1cafd..5b13fa029fd6 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -135,6 +135,14 @@ struct rtc_device {
135 /* Some hardware can't support UIE mode */ 135 /* Some hardware can't support UIE mode */
136 int uie_unsupported; 136 int uie_unsupported;
137 137
138 /* Number of nsec it takes to set the RTC clock. This influences when
139 * the set ops are called. An offset:
140 * - of 0.5 s will call RTC set for wall clock time 10.0 s at 9.5 s
141 * - of 1.5 s will call RTC set for wall clock time 10.0 s at 8.5 s
142 * - of -0.5 s will call RTC set for wall clock time 10.0 s at 10.5 s
143 */
144 long set_offset_nsec;
145
138 bool registered; 146 bool registered;
139 147
140 struct nvmem_config *nvmem_config; 148 struct nvmem_config *nvmem_config;
@@ -172,7 +180,7 @@ extern void devm_rtc_device_unregister(struct device *dev,
172 180
173extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); 181extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
174extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); 182extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
175extern int rtc_set_ntp_time(struct timespec64 now); 183extern int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec);
176int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); 184int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
177extern int rtc_read_alarm(struct rtc_device *rtc, 185extern int rtc_read_alarm(struct rtc_device *rtc,
178 struct rtc_wkalrm *alrm); 186 struct rtc_wkalrm *alrm);
@@ -221,6 +229,39 @@ static inline bool is_leap_year(unsigned int year)
221 return (!(year % 4) && (year % 100)) || !(year % 400); 229 return (!(year % 4) && (year % 100)) || !(year % 400);
222} 230}
223 231
232/* Determine if we can call to driver to set the time. Drivers can only be
233 * called to set a second aligned time value, and the field set_offset_nsec
234 * specifies how far away from the second aligned time to call the driver.
235 *
236 * This also computes 'to_set' which is the time we are trying to set, and has
237 * a zero in tv_nsecs, such that:
238 * to_set - set_delay_nsec == now +/- FUZZ
239 *
240 */
241static inline bool rtc_tv_nsec_ok(s64 set_offset_nsec,
242 struct timespec64 *to_set,
243 const struct timespec64 *now)
244{
245 /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */
246 const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5;
247 struct timespec64 delay = {.tv_sec = 0,
248 .tv_nsec = set_offset_nsec};
249
250 *to_set = timespec64_add(*now, delay);
251
252 if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) {
253 to_set->tv_nsec = 0;
254 return true;
255 }
256
257 if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) {
258 to_set->tv_sec++;
259 to_set->tv_nsec = 0;
260 return true;
261 }
262 return false;
263}
264
224#define rtc_register_device(device) \ 265#define rtc_register_device(device) \
225 __rtc_register_device(THIS_MODULE, device) 266 __rtc_register_device(THIS_MODULE, device)
226 267