summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2017-09-21 12:11:49 +0100
committerRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2022-01-12 12:12:59 +0000
commit346def82f72d61787918e02cccfb1678d5533e2b (patch)
tree6a2c9545ed273c3a6ff2daf5f8742d11b97f1bd0
parent60da2cdd80754128d61ce6a3db7f9f65fc49046d (diff)
rtc: add procfs sysctl to control RTC updates
Add a procfs sysctl to allow the RTC updates by the NTP code to be disabled. This is necessary if one wishes to adjust the RTC trimming. When performing such an adjustment, one would want to compare the RTC against a good reference. One way to do that is to synchronise the systems own time using NTP, but doing so causes the kernel to set the RTC every 11 minutes. This repeated setting prevents measuring the long-term drift of the RTC, and so prevents any attempt to trim the RTC for better accuracy. This sysctl defaults to enabled, so existing behaviour is preserved. When one wishes to adjust the long-term drift, the RTC update can be disabled via: echo 0 > /proc/sys/kernel/ntp_rtc_sync, the drift measured, and the update subsequently re-enabled. The next update will be triggered by the next successful adjtimex call. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--kernel/sysctl.c13
-rw-r--r--kernel/time/ntp.c7
2 files changed, 18 insertions, 2 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 083be6af29d7..03fb15efcdc2 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -108,6 +108,8 @@
#if defined(CONFIG_SYSCTL)
+extern unsigned int sysctl_ntp_rtc_sync;
+
/* Constants used for minimum and maximum */
#ifdef CONFIG_LOCKUP_DETECTOR
static int sixty = 60;
@@ -1771,6 +1773,17 @@ int proc_do_static_key(struct ctl_table *table, int write,
}
static struct ctl_table kern_table[] = {
+#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
+ {
+ .procname = "ntp_rtc_sync",
+ .data = &sysctl_ntp_rtc_sync,
+ .maxlen = sizeof(sysctl_ntp_rtc_sync),
+ .mode = 0644,
+ .proc_handler = proc_douintvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ },
+#endif
{
.procname = "sched_child_runs_first",
.data = &sysctl_sched_child_runs_first,
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 406dccb79c2b..85a56b888671 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -494,6 +494,7 @@ out:
return leap;
}
+unsigned int sysctl_ntp_rtc_sync = true;
#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
static void sync_hw_clock(struct work_struct *work);
static DECLARE_WORK(sync_work, sync_hw_clock);
@@ -635,7 +636,8 @@ static void sync_hw_clock(struct work_struct *work)
* managed to schedule the work between the timer firing and the
* work being able to rearm the timer. Wait for the timer to expire.
*/
- if (!ntp_synced() || hrtimer_is_queued(&sync_hrtimer))
+ if (!ntp_synced() || !sysctl_ntp_rtc_sync ||
+ hrtimer_is_queued(&sync_hrtimer))
return;
ktime_get_real_ts64(&now);
@@ -667,7 +669,8 @@ void ntp_notify_cmos_timer(void)
* rearmed this queues the work immediately again. No big issue,
* just a pointless work scheduled.
*/
- if (ntp_synced() && !hrtimer_is_queued(&sync_hrtimer))
+ if (ntp_synced() && sysctl_ntp_rtc_sync &&
+ !hrtimer_is_queued(&sync_hrtimer))
queue_work(system_freezable_power_efficient_wq, &sync_work);
}