Commit 33e62e83 authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

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: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Acked-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20201206220542.166871172@linutronix.de
parent c9e6189f
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -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

drivers/rtc/systohc.c

deleted100644 → 0
+0 −61
Original line number Diff line number Diff line
// 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;
}
+0 −34
Original line number Diff line number Diff line
@@ -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)

+85 −3
Original line number Diff line number Diff line
@@ -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)