Add clock_settime(2) support for auxiliary clocks. The function affects the
AUX offset which is added to the "monotonic" clock readout of these clocks.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/timekeeping.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
---
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -2757,9 +2757,48 @@ static int aux_get_timespec(clockid_t id
return ktime_get_aux_ts64(id, tp) ? 0 : -ENODEV;
}
+static int aux_clock_set(const clockid_t id, const struct timespec64 *tnew)
+{
+ struct tk_data *tkd = aux_get_tk_data(id);
+ struct timekeeper *tks;
+ ktime_t tnow, nsecs;
+
+ if (!timespec64_valid_settod(tnew))
+ return -EINVAL;
+ if (!tkd)
+ return -ENODEV;
+
+ tks = &tkd->shadow_timekeeper;
+
+ guard(raw_spinlock_irq)(&tkd->lock);
+ if (!tks->clock_valid)
+ return -ENODEV;
+
+ /* Forward the timekeeper base time */
+ timekeeping_forward_now(tks);
+ /*
+ * Get the updated base time. tkr_mono.base has not been
+ * updated yet, so do that first. That makes the update
+ * in timekeeping_update_from_shadow() redundant, but
+ * that's harmless. After that @tnow can be calculated
+ * by using tkr_mono::cycle_last, which has been set
+ * by timekeeping_forward_now().
+ */
+ tk_update_ktime_data(tks);
+ nsecs = timekeeping_cycles_to_ns(&tks->tkr_mono, tks->tkr_mono.cycle_last);
+ tnow = ktime_add(tks->tkr_mono.base, nsecs);
+
+ /* Calculate the new AUX offset */
+ tks->offs_aux = ktime_sub(timespec64_to_ktime(*tnew), tnow);
+
+ timekeeping_update_from_shadow(tkd, TK_UPDATE_ALL);
+ return 0;
+}
+
const struct k_clock clock_aux = {
.clock_getres = aux_get_res,
.clock_get_timespec = aux_get_timespec,
+ .clock_set = aux_clock_set,
};
static __init void tk_aux_setup(void)
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote: > > Add clock_settime(2) support for auxiliary clocks. The function affects the > AUX offset which is added to the "monotonic" clock readout of these clocks. > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > --- Minor fretting: I worry a little that the difference here between the default timekeeper where set adjusts the REALTIME offset from MONOTONIC, and here where it directly adjusts "mono" might confuse later readers? Would something about that be useful to have in a comment? Either way, Acked-by: John Stultz <jstultz@google.com>
On Thu, Jun 26 2025 at 21:23, John Stultz wrote: > On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote: >> >> Add clock_settime(2) support for auxiliary clocks. The function affects the >> AUX offset which is added to the "monotonic" clock readout of these clocks. >> >> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> >> --- > > Minor fretting: I worry a little that the difference here between the > default timekeeper where set adjusts the REALTIME offset from > MONOTONIC, and here where it directly adjusts "mono" might confuse > later readers? Actually it's not really that different. In both cases the new offset to the monotonic clock is calculated and stored in the relevant tk::offs_* member. The difference is that the core timekeeper operates on xtime, but for simplicity I chose to calculate the resulting tk::offs_aux directly from the monotonic base. That's valid with the aux clocks as they don't need any of the xtime parts. I added some blurb to it.
On Fri, Jun 27 2025 at 16:18, Thomas Gleixner wrote: > On Thu, Jun 26 2025 at 21:23, John Stultz wrote: >> On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote: >>> >>> Add clock_settime(2) support for auxiliary clocks. The function affects the >>> AUX offset which is added to the "monotonic" clock readout of these clocks. >>> >>> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> >>> --- >> >> Minor fretting: I worry a little that the difference here between the >> default timekeeper where set adjusts the REALTIME offset from >> MONOTONIC, and here where it directly adjusts "mono" might confuse >> later readers? > > Actually it's not really that different. > > In both cases the new offset to the monotonic clock is calculated and > stored in the relevant tk::offs_* member. > > The difference is that the core timekeeper operates on xtime, but for > simplicity I chose to calculate the resulting tk::offs_aux directly from > the monotonic base. That's valid with the aux clocks as they don't > need any of the xtime parts. Actually using xtime and adjusting it and xtime_to_mono does not work for those auxiliary clocks because the offset to clock "monotonic" is allowed to be negative, unless it would result in a overall negative time readout. This is required for those clocks because the TSN/PTP zoo out there especially in automation/automotive uses clockmasters starting at the epoch for their specialized networks. So if the clockmaster starts up _after_ the client, then the pile of xtime sanity checks would prevent setting the clock back to the epoch. I tried to work around that, but the result was more horrible and fragile than the current approach with the aux specific offset. Don't ask :) Thanks, tglx
The following commit has been merged into the timers/ptp branch of tip:
Commit-ID: 60ecc26ec5af567a55f362ad92c0cac8b894541c
Gitweb: https://git.kernel.org/tip/60ecc26ec5af567a55f362ad92c0cac8b894541c
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Wed, 25 Jun 2025 20:38:34 +02:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Fri, 27 Jun 2025 20:13:12 +02:00
timekeeping: Provide time setter for auxiliary clocks
Add clock_settime(2) support for auxiliary clocks. The function affects the
AUX offset which is added to the "monotonic" clock readout of these clocks.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: John Stultz <jstultz@google.com>
Link: https://lore.kernel.org/all/20250625183757.995688714@linutronix.de
---
kernel/time/timekeeping.c | 44 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+)
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 10c6e37..b6ac784 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -2765,9 +2765,53 @@ static int aux_get_timespec(clockid_t id, struct timespec64 *tp)
return ktime_get_aux_ts64(id, tp) ? 0 : -ENODEV;
}
+static int aux_clock_set(const clockid_t id, const struct timespec64 *tnew)
+{
+ struct tk_data *aux_tkd = aux_get_tk_data(id);
+ struct timekeeper *aux_tks;
+ ktime_t tnow, nsecs;
+
+ if (!timespec64_valid_settod(tnew))
+ return -EINVAL;
+ if (!aux_tkd)
+ return -ENODEV;
+
+ aux_tks = &aux_tkd->shadow_timekeeper;
+
+ guard(raw_spinlock_irq)(&aux_tkd->lock);
+ if (!aux_tks->clock_valid)
+ return -ENODEV;
+
+ /* Forward the timekeeper base time */
+ timekeeping_forward_now(aux_tks);
+ /*
+ * Get the updated base time. tkr_mono.base has not been
+ * updated yet, so do that first. That makes the update
+ * in timekeeping_update_from_shadow() redundant, but
+ * that's harmless. After that @tnow can be calculated
+ * by using tkr_mono::cycle_last, which has been set
+ * by timekeeping_forward_now().
+ */
+ tk_update_ktime_data(aux_tks);
+ nsecs = timekeeping_cycles_to_ns(&aux_tks->tkr_mono, aux_tks->tkr_mono.cycle_last);
+ tnow = ktime_add(aux_tks->tkr_mono.base, nsecs);
+
+ /*
+ * Calculate the new AUX offset as delta to @tnow ("monotonic").
+ * That avoids all the tk::xtime back and forth conversions as
+ * xtime ("realtime") is not applicable for auxiliary clocks and
+ * kept in sync with "monotonic".
+ */
+ aux_tks->offs_aux = ktime_sub(timespec64_to_ktime(*tnew), tnow);
+
+ timekeeping_update_from_shadow(aux_tkd, TK_UPDATE_ALL);
+ return 0;
+}
+
const struct k_clock clock_aux = {
.clock_getres = aux_get_res,
.clock_get_timespec = aux_get_timespec,
+ .clock_set = aux_clock_set,
};
static __init void tk_aux_setup(void)
© 2016 - 2025 Red Hat, Inc.