2020-12-06 22:10:21

by Thomas Gleixner

[permalink] [raw]
Subject: [patch 6/8] ntp, rtc: Move rtc_set_ntp_time() to ntp code

rtc_set_ntp_time() is not really RTC functionality as the code is just a
user of RTC. Move it into the NTP code which allows further cleanups.

Requested-by: Alexandre Belloni <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
---
drivers/rtc/Makefile | 1
drivers/rtc/systohc.c | 61 ----------------------------------
include/linux/rtc.h | 34 -------------------
kernel/time/ntp.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 85 insertions(+), 99 deletions(-)

--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -6,7 +6,6 @@
ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG

obj-$(CONFIG_RTC_LIB) += lib.o
-obj-$(CONFIG_RTC_SYSTOHC) += systohc.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
rtc-core-y := class.o interface.o
--- a/drivers/rtc/systohc.c
+++ /dev/null
@@ -1,61 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/rtc.h>
-#include <linux/time.h>
-
-/**
- * rtc_set_ntp_time - Save NTP synchronized time to the RTC
- * @now: Current time of day
- * @target_nsec: pointer for desired now->tv_nsec value
- *
- * Replacement for the NTP platform function update_persistent_clock64
- * that stores time for later retrieval by rtc_hctosys.
- *
- * Returns 0 on successful RTC update, -ENODEV if a RTC update is not
- * possible at all, and various other -errno for specific temporary failure
- * cases.
- *
- * -EPROTO is returned if now.tv_nsec is not close enough to *target_nsec.
- *
- * If temporary failure is indicated the caller should try again 'soon'
- */
-int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec)
-{
- struct rtc_device *rtc;
- struct rtc_time tm;
- struct timespec64 to_set;
- int err = -ENODEV;
- bool ok;
-
- rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
- if (!rtc)
- goto out_err;
-
- if (!rtc->ops || !rtc->ops->set_time)
- goto out_close;
-
- /* Compute the value of tv_nsec we require the caller to supply in
- * now.tv_nsec. This is the value such that (now +
- * set_offset_nsec).tv_nsec == 0.
- */
- set_normalized_timespec64(&to_set, 0, -rtc->set_offset_nsec);
- *target_nsec = to_set.tv_nsec;
-
- /* The ntp code must call this with the correct value in tv_nsec, if
- * it does not we update target_nsec and return EPROTO to make the ntp
- * code try again later.
- */
- ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now);
- if (!ok) {
- err = -EPROTO;
- goto out_close;
- }
-
- rtc_time64_to_tm(to_set.tv_sec, &tm);
-
- err = rtc_set_time(rtc, &tm);
-
-out_close:
- rtc_class_close(rtc);
-out_err:
- return err;
-}
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -165,7 +165,6 @@ int __rtc_register_device(struct module

extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
-extern int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec);
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
extern int rtc_read_alarm(struct rtc_device *rtc,
struct rtc_wkalrm *alrm);
@@ -205,39 +204,6 @@ static inline bool is_leap_year(unsigned
return (!(year % 4) && (year % 100)) || !(year % 400);
}

-/* Determine if we can call to driver to set the time. Drivers can only be
- * called to set a second aligned time value, and the field set_offset_nsec
- * specifies how far away from the second aligned time to call the driver.
- *
- * This also computes 'to_set' which is the time we are trying to set, and has
- * a zero in tv_nsecs, such that:
- * to_set - set_delay_nsec == now +/- FUZZ
- *
- */
-static inline bool rtc_tv_nsec_ok(s64 set_offset_nsec,
- struct timespec64 *to_set,
- const struct timespec64 *now)
-{
- /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */
- const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5;
- struct timespec64 delay = {.tv_sec = 0,
- .tv_nsec = set_offset_nsec};
-
- *to_set = timespec64_add(*now, delay);
-
- if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) {
- to_set->tv_nsec = 0;
- return true;
- }
-
- if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) {
- to_set->tv_sec++;
- to_set->tv_nsec = 0;
- return true;
- }
- return false;
-}
-
#define rtc_register_device(device) \
__rtc_register_device(THIS_MODULE, device)

--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -519,15 +519,94 @@ static void sched_sync_hw_clock(unsigned
hrtimer_start(&sync_hrtimer, exp, HRTIMER_MODE_ABS);
}

+/*
+ * Determine if we can call to driver to set the time. Drivers can only be
+ * called to set a second aligned time value, and the field set_offset_nsec
+ * specifies how far away from the second aligned time to call the driver.
+ *
+ * This also computes 'to_set' which is the time we are trying to set, and has
+ * a zero in tv_nsecs, such that:
+ * to_set - set_delay_nsec == now +/- FUZZ
+ *
+ */
+static inline bool rtc_tv_nsec_ok(long set_offset_nsec,
+ struct timespec64 *to_set,
+ const struct timespec64 *now)
+{
+ /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */
+ const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5;
+ struct timespec64 delay = {.tv_sec = 0,
+ .tv_nsec = set_offset_nsec};
+
+ *to_set = timespec64_add(*now, delay);
+
+ if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) {
+ to_set->tv_nsec = 0;
+ return true;
+ }
+
+ if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) {
+ to_set->tv_sec++;
+ to_set->tv_nsec = 0;
+ return true;
+ }
+ return false;
+}
+
+#ifdef CONFIG_RTC_SYSTOHC
+/*
+ * rtc_set_ntp_time - Save NTP synchronized time to the RTC
+ */
+static int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec)
+{
+ struct rtc_device *rtc;
+ struct rtc_time tm;
+ struct timespec64 to_set;
+ int err = -ENODEV;
+ bool ok;
+
+ rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
+ if (!rtc)
+ goto out_err;
+
+ if (!rtc->ops || !rtc->ops->set_time)
+ goto out_close;
+
+ /*
+ * Compute the value of tv_nsec we require the caller to supply in
+ * now.tv_nsec. This is the value such that (now +
+ * set_offset_nsec).tv_nsec == 0.
+ */
+ set_normalized_timespec64(&to_set, 0, -rtc->set_offset_nsec);
+ *target_nsec = to_set.tv_nsec;
+
+ /*
+ * The ntp code must call this with the correct value in tv_nsec, if
+ * it does not we update target_nsec and return EPROTO to make the ntp
+ * code try again later.
+ */
+ ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now);
+ if (!ok) {
+ err = -EPROTO;
+ goto out_close;
+ }
+
+ rtc_time64_to_tm(to_set.tv_sec, &tm);
+
+ err = rtc_set_time(rtc, &tm);
+
+out_close:
+ rtc_class_close(rtc);
+out_err:
+ return err;
+}
+
static void sync_rtc_clock(void)
{
unsigned long offset_nsec;
struct timespec64 adjust;
int rc;

- if (!IS_ENABLED(CONFIG_RTC_SYSTOHC))
- return;
-
ktime_get_real_ts64(&adjust);

if (persistent_clock_is_local)
@@ -544,6 +623,9 @@ static void sync_rtc_clock(void)

sched_sync_hw_clock(offset_nsec, rc != 0);
}
+#else
+static inline void sync_rtc_clock(void) { }
+#endif

#ifdef CONFIG_GENERIC_CMOS_UPDATE
int __weak update_persistent_clock64(struct timespec64 now64)


2020-12-07 21:04:02

by Jason Gunthorpe

[permalink] [raw]
Subject: Re: [patch 6/8] ntp, rtc: Move rtc_set_ntp_time() to ntp code

On Sun, Dec 06, 2020 at 10:46:19PM +0100, Thomas Gleixner wrote:
> rtc_set_ntp_time() is not really RTC functionality as the code is just a
> user of RTC. Move it into the NTP code which allows further cleanups.
>
> Requested-by: Alexandre Belloni <[email protected]>
> Signed-off-by: Thomas Gleixner <[email protected]>
> ---
> drivers/rtc/Makefile | 1
> drivers/rtc/systohc.c | 61 ----------------------------------
> include/linux/rtc.h | 34 -------------------
> kernel/time/ntp.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++--
> 4 files changed, 85 insertions(+), 99 deletions(-)

Fair enough, it is asymmetric with how HCTOSYS works, but not a big
deal

Reviewed-by: Jason Gunthorpe <[email protected]>

Jason

2020-12-09 03:56:37

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [patch 6/8] ntp, rtc: Move rtc_set_ntp_time() to ntp code

On 07/12/2020 16:59:52-0400, Jason Gunthorpe wrote:
> On Sun, Dec 06, 2020 at 10:46:19PM +0100, Thomas Gleixner wrote:
> > rtc_set_ntp_time() is not really RTC functionality as the code is just a
> > user of RTC. Move it into the NTP code which allows further cleanups.
> >
> > Requested-by: Alexandre Belloni <[email protected]>
> > Signed-off-by: Thomas Gleixner <[email protected]>
> > ---
> > drivers/rtc/Makefile | 1
> > drivers/rtc/systohc.c | 61 ----------------------------------
> > include/linux/rtc.h | 34 -------------------
> > kernel/time/ntp.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++--
> > 4 files changed, 85 insertions(+), 99 deletions(-)
>
> Fair enough, it is asymmetric with how HCTOSYS works, but not a big
> deal
>

It is already asymmetric as hctosys will always happen as soon as the
rtc driver is loaded but systohc will only actually be called only if
ntp is enabled.

I must admit I did consider moving it ou of the rtc subsystem instead of
having it moved in class.c to solve the issue with rtc drivers compiled
as modules but I still carry the nasty BITS_PER_LONG check to keep
systemd happy on a 32bit userspace.

--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

Subject: [tip: timers/core] ntp, rtc: Move rtc_set_ntp_time() to ntp code

The following commit has been merged into the timers/core branch of tip:

Commit-ID: 33e62e832384c8cb523044e0e9d99d7133f98e93
Gitweb: https://git.kernel.org/tip/33e62e832384c8cb523044e0e9d99d7133f98e93
Author: Thomas Gleixner <[email protected]>
AuthorDate: Sun, 06 Dec 2020 22:46:19 +01:00
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 11 Dec 2020 10:40:52 +01:00

ntp, rtc: Move rtc_set_ntp_time() to ntp code

rtc_set_ntp_time() is not really RTC functionality as the code is just a
user of RTC. Move it into the NTP code which allows further cleanups.

Requested-by: Alexandre Belloni <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Reviewed-by: Jason Gunthorpe <[email protected]>
Acked-by: Alexandre Belloni <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

---
drivers/rtc/Makefile | 1 +-
drivers/rtc/systohc.c | 61 +-----------------------------
include/linux/rtc.h | 34 +----------------
kernel/time/ntp.c | 88 ++++++++++++++++++++++++++++++++++++++++--
4 files changed, 85 insertions(+), 99 deletions(-)
delete mode 100644 drivers/rtc/systohc.c

diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index bfb5746..bb8f319 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -6,7 +6,6 @@
ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG

obj-$(CONFIG_RTC_LIB) += lib.o
-obj-$(CONFIG_RTC_SYSTOHC) += systohc.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
rtc-core-y := class.o interface.o
diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c
deleted file mode 100644
index 8b70f05..0000000
--- a/drivers/rtc/systohc.c
+++ /dev/null
@@ -1,61 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/rtc.h>
-#include <linux/time.h>
-
-/**
- * rtc_set_ntp_time - Save NTP synchronized time to the RTC
- * @now: Current time of day
- * @target_nsec: pointer for desired now->tv_nsec value
- *
- * Replacement for the NTP platform function update_persistent_clock64
- * that stores time for later retrieval by rtc_hctosys.
- *
- * Returns 0 on successful RTC update, -ENODEV if a RTC update is not
- * possible at all, and various other -errno for specific temporary failure
- * cases.
- *
- * -EPROTO is returned if now.tv_nsec is not close enough to *target_nsec.
- *
- * If temporary failure is indicated the caller should try again 'soon'
- */
-int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec)
-{
- struct rtc_device *rtc;
- struct rtc_time tm;
- struct timespec64 to_set;
- int err = -ENODEV;
- bool ok;
-
- rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
- if (!rtc)
- goto out_err;
-
- if (!rtc->ops || !rtc->ops->set_time)
- goto out_close;
-
- /* Compute the value of tv_nsec we require the caller to supply in
- * now.tv_nsec. This is the value such that (now +
- * set_offset_nsec).tv_nsec == 0.
- */
- set_normalized_timespec64(&to_set, 0, -rtc->set_offset_nsec);
- *target_nsec = to_set.tv_nsec;
-
- /* The ntp code must call this with the correct value in tv_nsec, if
- * it does not we update target_nsec and return EPROTO to make the ntp
- * code try again later.
- */
- ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now);
- if (!ok) {
- err = -EPROTO;
- goto out_close;
- }
-
- rtc_time64_to_tm(to_set.tv_sec, &tm);
-
- err = rtc_set_time(rtc, &tm);
-
-out_close:
- rtc_class_close(rtc);
-out_err:
- return err;
-}
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 22d1575..ff62680 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -165,7 +165,6 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc);

extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
-extern int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec);
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
extern int rtc_read_alarm(struct rtc_device *rtc,
struct rtc_wkalrm *alrm);
@@ -205,39 +204,6 @@ static inline bool is_leap_year(unsigned int year)
return (!(year % 4) && (year % 100)) || !(year % 400);
}

-/* Determine if we can call to driver to set the time. Drivers can only be
- * called to set a second aligned time value, and the field set_offset_nsec
- * specifies how far away from the second aligned time to call the driver.
- *
- * This also computes 'to_set' which is the time we are trying to set, and has
- * a zero in tv_nsecs, such that:
- * to_set - set_delay_nsec == now +/- FUZZ
- *
- */
-static inline bool rtc_tv_nsec_ok(s64 set_offset_nsec,
- struct timespec64 *to_set,
- const struct timespec64 *now)
-{
- /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */
- const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5;
- struct timespec64 delay = {.tv_sec = 0,
- .tv_nsec = set_offset_nsec};
-
- *to_set = timespec64_add(*now, delay);
-
- if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) {
- to_set->tv_nsec = 0;
- return true;
- }
-
- if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) {
- to_set->tv_sec++;
- to_set->tv_nsec = 0;
- return true;
- }
- return false;
-}
-
#define rtc_register_device(device) \
__rtc_register_device(THIS_MODULE, device)

diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index ff1a7b8..84a5546 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -519,15 +519,94 @@ static void sched_sync_hw_clock(unsigned long offset_nsec, bool retry)
hrtimer_start(&sync_hrtimer, exp, HRTIMER_MODE_ABS);
}

+/*
+ * Determine if we can call to driver to set the time. Drivers can only be
+ * called to set a second aligned time value, and the field set_offset_nsec
+ * specifies how far away from the second aligned time to call the driver.
+ *
+ * This also computes 'to_set' which is the time we are trying to set, and has
+ * a zero in tv_nsecs, such that:
+ * to_set - set_delay_nsec == now +/- FUZZ
+ *
+ */
+static inline bool rtc_tv_nsec_ok(long set_offset_nsec,
+ struct timespec64 *to_set,
+ const struct timespec64 *now)
+{
+ /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */
+ const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5;
+ struct timespec64 delay = {.tv_sec = 0,
+ .tv_nsec = set_offset_nsec};
+
+ *to_set = timespec64_add(*now, delay);
+
+ if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) {
+ to_set->tv_nsec = 0;
+ return true;
+ }
+
+ if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) {
+ to_set->tv_sec++;
+ to_set->tv_nsec = 0;
+ return true;
+ }
+ return false;
+}
+
+#ifdef CONFIG_RTC_SYSTOHC
+/*
+ * rtc_set_ntp_time - Save NTP synchronized time to the RTC
+ */
+static int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec)
+{
+ struct rtc_device *rtc;
+ struct rtc_time tm;
+ struct timespec64 to_set;
+ int err = -ENODEV;
+ bool ok;
+
+ rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
+ if (!rtc)
+ goto out_err;
+
+ if (!rtc->ops || !rtc->ops->set_time)
+ goto out_close;
+
+ /*
+ * Compute the value of tv_nsec we require the caller to supply in
+ * now.tv_nsec. This is the value such that (now +
+ * set_offset_nsec).tv_nsec == 0.
+ */
+ set_normalized_timespec64(&to_set, 0, -rtc->set_offset_nsec);
+ *target_nsec = to_set.tv_nsec;
+
+ /*
+ * The ntp code must call this with the correct value in tv_nsec, if
+ * it does not we update target_nsec and return EPROTO to make the ntp
+ * code try again later.
+ */
+ ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now);
+ if (!ok) {
+ err = -EPROTO;
+ goto out_close;
+ }
+
+ rtc_time64_to_tm(to_set.tv_sec, &tm);
+
+ err = rtc_set_time(rtc, &tm);
+
+out_close:
+ rtc_class_close(rtc);
+out_err:
+ return err;
+}
+
static void sync_rtc_clock(void)
{
unsigned long offset_nsec;
struct timespec64 adjust;
int rc;

- if (!IS_ENABLED(CONFIG_RTC_SYSTOHC))
- return;
-
ktime_get_real_ts64(&adjust);

if (persistent_clock_is_local)
@@ -544,6 +623,9 @@ static void sync_rtc_clock(void)

sched_sync_hw_clock(offset_nsec, rc != 0);
}
+#else
+static inline void sync_rtc_clock(void) { }
+#endif

#ifdef CONFIG_GENERIC_CMOS_UPDATE
int __weak update_persistent_clock64(struct timespec64 now64)