* [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series
@ 2025-06-25 18:38 Thomas Gleixner
2025-06-25 18:38 ` [patch V3 01/11] timekeeping: Update auxiliary timekeepers on clocksource change Thomas Gleixner
` (10 more replies)
0 siblings, 11 replies; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
This is the remaining series of V2, which can be found here:
https://lore.kernel.org/all/20250519082042.742926976@linutronix.de
The first 15 patches of V2 have been merged into the tip tree and this is
the update of the remaining 11, which addresses the review feedback.
Changes vs. V2:
- Use kobject.h, clockid_t and cleanup the sysfs init - Thomas W.
- Use aux_tkd, aux_tks instead of tkd, tks in aux clock specific
functions for clarity - John
- Remove misleading clock TAI comment - John
The series applies on top of:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/ptp
and is available from git:
git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git timers/ptp/clocks
A small update for PTP to support auxiliary clocks in
PTP_SYS_OFFSET_EXTENDED is going to be sent seperately as it has a
dependency on pending PTP changes.
Thanks,
tglx
---
Documentation/ABI/stable/sysfs-kernel-time-aux-clocks | 5
include/linux/posix-timers.h | 5
include/linux/timekeeping.h | 11
kernel/time/posix-timers.c | 3
kernel/time/posix-timers.h | 1
kernel/time/timekeeping.c | 484 +++++++++++++++---
6 files changed, 451 insertions(+), 58 deletions(-)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 01/11] timekeeping: Update auxiliary timekeepers on clocksource change
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 4:43 ` John Stultz
2025-06-25 18:38 ` [patch V3 02/11] timekeeping: Provide time getters for auxiliary clocks Thomas Gleixner
` (9 subsequent siblings)
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Propagate a system clocksource change to the auxiliary timekeepers so that
they can pick up the new clocksource.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/timekeeping.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
---
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -119,8 +119,10 @@ static struct tk_fast tk_fast_raw ____c
#ifdef CONFIG_POSIX_AUX_CLOCKS
static __init void tk_aux_setup(void);
+static void tk_aux_update_clocksource(void);
#else
static inline void tk_aux_setup(void) { }
+static inline void tk_aux_update_clocksource(void) { }
#endif
unsigned long timekeeper_lock_irqsave(void)
@@ -1548,6 +1550,8 @@ static int change_clocksource(void *data
timekeeping_update_from_shadow(&tk_core, TK_UPDATE_ALL);
}
+ tk_aux_update_clocksource();
+
if (old) {
if (old->disable)
old->disable(old);
@@ -2651,6 +2655,30 @@ EXPORT_SYMBOL(hardpps);
#endif /* CONFIG_NTP_PPS */
#ifdef CONFIG_POSIX_AUX_CLOCKS
+
+/* Bitmap for the activated auxiliary timekeepers */
+static unsigned long aux_timekeepers;
+
+/* Invoked from timekeeping after a clocksource change */
+static void tk_aux_update_clocksource(void)
+{
+ unsigned long active = READ_ONCE(aux_timekeepers);
+ unsigned int id;
+
+ for_each_set_bit(id, &active, BITS_PER_LONG) {
+ struct tk_data *tkd = &timekeeper_data[id + TIMEKEEPER_AUX_FIRST];
+ struct timekeeper *tks = &tkd->shadow_timekeeper;
+
+ guard(raw_spinlock_irqsave)(&tkd->lock);
+ if (!tks->clock_valid)
+ continue;
+
+ timekeeping_forward_now(tks);
+ tk_setup_internals(tks, tk_core.timekeeper.tkr_mono.clock);
+ timekeeping_update_from_shadow(tkd, TK_UPDATE_ALL);
+ }
+}
+
static __init void tk_aux_setup(void)
{
for (int i = TIMEKEEPER_AUX_FIRST; i <= TIMEKEEPER_AUX_LAST; i++)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 02/11] timekeeping: Provide time getters for auxiliary clocks
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
2025-06-25 18:38 ` [patch V3 01/11] timekeeping: Update auxiliary timekeepers on clocksource change Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 4:18 ` John Stultz
2025-06-25 18:38 ` [patch V3 03/11] timekeeping: Add minimal posix-timers support " Thomas Gleixner
` (8 subsequent siblings)
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Provide interfaces similar to the ktime_get*() family which provide access
to the auxiliary clocks.
These interfaces have a boolean return value, which indicates whether the
accessed clock is valid or not.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V3: Remove misleading TAI comment and use aux_tkd* for clarity - John
---
include/linux/posix-timers.h | 5 +++
include/linux/timekeeping.h | 11 +++++++
kernel/time/timekeeping.c | 65 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 81 insertions(+)
---
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -37,6 +37,11 @@ static inline int clockid_to_fd(const cl
return ~(clk >> 3);
}
+static inline bool clockid_aux_valid(clockid_t id)
+{
+ return IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS) && id >= CLOCK_AUX && id <= CLOCK_AUX_LAST;
+}
+
#ifdef CONFIG_POSIX_TIMERS
#include <linux/signal_types.h>
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -263,6 +263,17 @@ extern bool timekeeping_rtc_skipresume(v
extern void timekeeping_inject_sleeptime64(const struct timespec64 *delta);
+/*
+ * Auxiliary clock interfaces
+ */
+#ifdef CONFIG_POSIX_AUX_CLOCKS
+extern bool ktime_get_aux(clockid_t id, ktime_t *kt);
+extern bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt);
+#else
+static inline bool ktime_get_aux(clockid_t id, ktime_t *kt) { return false; }
+static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { return false; }
+#endif
+
/**
* struct system_time_snapshot - simultaneous raw/real time capture with
* counter value
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -2659,6 +2659,18 @@ EXPORT_SYMBOL(hardpps);
/* Bitmap for the activated auxiliary timekeepers */
static unsigned long aux_timekeepers;
+static inline unsigned int clockid_to_tkid(unsigned int id)
+{
+ return TIMEKEEPER_AUX_FIRST + id - CLOCK_AUX;
+}
+
+static inline struct tk_data *aux_get_tk_data(clockid_t id)
+{
+ if (!clockid_aux_valid(id))
+ return NULL;
+ return &timekeeper_data[clockid_to_tkid(id)];
+}
+
/* Invoked from timekeeping after a clocksource change */
static void tk_aux_update_clocksource(void)
{
@@ -2679,6 +2691,59 @@ static void tk_aux_update_clocksource(vo
}
}
+/**
+ * ktime_get_aux - Get time for a AUX clock
+ * @id: ID of the clock to read (CLOCK_AUX...)
+ * @kt: Pointer to ktime_t to store the time stamp
+ *
+ * Returns: True if the timestamp is valid, false otherwise
+ */
+bool ktime_get_aux(clockid_t id, ktime_t *kt)
+{
+ struct tk_data *aux_tkd = aux_get_tk_data(id);
+ struct timekeeper *aux_tk;
+ unsigned int seq;
+ ktime_t base;
+ u64 nsecs;
+
+ WARN_ON(timekeeping_suspended);
+
+ if (!aux_tkd)
+ return false;
+
+ aux_tk = &aux_tkd->timekeeper;
+ do {
+ seq = read_seqcount_begin(&aux_tkd->seq);
+ if (!aux_tk->clock_valid)
+ return false;
+
+ base = ktime_add(aux_tk->tkr_mono.base, aux_tk->offs_aux);
+ nsecs = timekeeping_get_ns(&aux_tk->tkr_mono);
+ } while (read_seqcount_retry(&aux_tkd->seq, seq));
+
+ *kt = ktime_add_ns(base, nsecs);
+ return true;
+}
+EXPORT_SYMBOL_GPL(ktime_get_aux);
+
+/**
+ * ktime_get_aux_ts64 - Get time for a AUX clock
+ * @id: ID of the clock to read (CLOCK_AUX...)
+ * @ts: Pointer to timespec64 to store the time stamp
+ *
+ * Returns: True if the timestamp is valid, false otherwise
+ */
+bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *ts)
+{
+ ktime_t now;
+
+ if (!ktime_get_aux(id, &now))
+ return false;
+ *ts = ktime_to_timespec64(now);
+ return true;
+}
+EXPORT_SYMBOL_GPL(ktime_get_aux_ts64);
+
static __init void tk_aux_setup(void)
{
for (int i = TIMEKEEPER_AUX_FIRST; i <= TIMEKEEPER_AUX_LAST; i++)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 03/11] timekeeping: Add minimal posix-timers support for auxiliary clocks
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
2025-06-25 18:38 ` [patch V3 01/11] timekeeping: Update auxiliary timekeepers on clocksource change Thomas Gleixner
2025-06-25 18:38 ` [patch V3 02/11] timekeeping: Provide time getters for auxiliary clocks Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 4:19 ` John Stultz
2025-06-25 18:38 ` [patch V3 04/11] timekeeping: Provide time setter " Thomas Gleixner
` (7 subsequent siblings)
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Provide clock_getres(2) and clock_gettime(2) for auxiliary clocks.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/posix-timers.c | 3 +++
kernel/time/posix-timers.h | 1 +
kernel/time/timekeeping.c | 21 +++++++++++++++++++++
3 files changed, 25 insertions(+)
---
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -1526,6 +1526,9 @@ static const struct k_clock * const posi
[CLOCK_REALTIME_ALARM] = &alarm_clock,
[CLOCK_BOOTTIME_ALARM] = &alarm_clock,
[CLOCK_TAI] = &clock_tai,
+#ifdef CONFIG_POSIX_AUX_CLOCKS
+ [CLOCK_AUX ... CLOCK_AUX_LAST] = &clock_aux,
+#endif
};
static const struct k_clock *clockid_to_kclock(const clockid_t id)
--- a/kernel/time/posix-timers.h
+++ b/kernel/time/posix-timers.h
@@ -41,6 +41,7 @@ extern const struct k_clock clock_posix_
extern const struct k_clock clock_process;
extern const struct k_clock clock_thread;
extern const struct k_clock alarm_clock;
+extern const struct k_clock clock_aux;
void posix_timer_queue_signal(struct k_itimer *timr);
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -2655,6 +2655,7 @@ EXPORT_SYMBOL(hardpps);
#endif /* CONFIG_NTP_PPS */
#ifdef CONFIG_POSIX_AUX_CLOCKS
+#include "posix-timers.h"
/* Bitmap for the activated auxiliary timekeepers */
static unsigned long aux_timekeepers;
@@ -2744,6 +2745,26 @@ bool ktime_get_aux_ts64(clockid_t id, st
}
EXPORT_SYMBOL_GPL(ktime_get_aux_ts64);
+static int aux_get_res(clockid_t id, struct timespec64 *tp)
+{
+ if (!clockid_aux_valid(id))
+ return -ENODEV;
+
+ tp->tv_sec = 0;
+ tp->tv_nsec = 1;
+ return 0;
+}
+
+static int aux_get_timespec(clockid_t id, struct timespec64 *tp)
+{
+ return ktime_get_aux_ts64(id, tp) ? 0 : -ENODEV;
+}
+
+const struct k_clock clock_aux = {
+ .clock_getres = aux_get_res,
+ .clock_get_timespec = aux_get_timespec,
+};
+
static __init void tk_aux_setup(void)
{
for (int i = TIMEKEEPER_AUX_FIRST; i <= TIMEKEEPER_AUX_LAST; i++)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 04/11] timekeeping: Provide time setter for auxiliary clocks
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
` (2 preceding siblings ...)
2025-06-25 18:38 ` [patch V3 03/11] timekeeping: Add minimal posix-timers support " Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 4:23 ` John Stultz
2025-06-25 18:38 ` [patch V3 05/11] timekeeping: Make timekeeping_inject_offset() reusable Thomas Gleixner
` (6 subsequent siblings)
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
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)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 05/11] timekeeping: Make timekeeping_inject_offset() reusable
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
` (3 preceding siblings ...)
2025-06-25 18:38 ` [patch V3 04/11] timekeeping: Provide time setter " Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 4:26 ` John Stultz
2025-06-25 18:38 ` [patch V3 06/11] timekeeping: Add auxiliary clock support to __timekeeping_inject_offset() Thomas Gleixner
` (5 subsequent siblings)
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Split out the inner workings for auxiliary clock support and feed the core time
keeper into it.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/timekeeping.c | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
---
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1433,32 +1433,32 @@ EXPORT_SYMBOL(do_settimeofday64);
/**
* __timekeeping_inject_offset - Adds or subtracts from the current time.
+ * @tkd: Pointer to the timekeeper to modify
* @ts: Pointer to the timespec variable containing the offset
*
* Adds or subtracts an offset value from the current time.
*/
-static int __timekeeping_inject_offset(const struct timespec64 *ts)
+static int __timekeeping_inject_offset(struct tk_data *tkd, const struct timespec64 *ts)
{
- struct timekeeper *tks = &tk_core.shadow_timekeeper;
+ struct timekeeper *tks = &tkd->shadow_timekeeper;
struct timespec64 tmp;
if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
-
timekeeping_forward_now(tks);
/* Make sure the proposed value is valid */
tmp = timespec64_add(tk_xtime(tks), *ts);
if (timespec64_compare(&tks->wall_to_monotonic, ts) > 0 ||
!timespec64_valid_settod(&tmp)) {
- timekeeping_restore_shadow(&tk_core);
+ timekeeping_restore_shadow(tkd);
return -EINVAL;
}
tk_xtime_add(tks, ts);
tk_set_wall_to_mono(tks, timespec64_sub(tks->wall_to_monotonic, *ts));
- timekeeping_update_from_shadow(&tk_core, TK_UPDATE_ALL);
+ timekeeping_update_from_shadow(tkd, TK_UPDATE_ALL);
return 0;
}
@@ -1467,7 +1467,7 @@ static int timekeeping_inject_offset(con
int ret;
scoped_guard (raw_spinlock_irqsave, &tk_core.lock)
- ret = __timekeeping_inject_offset(ts);
+ ret = __timekeeping_inject_offset(&tk_core, ts);
/* Signal hrtimers about time change */
if (!ret)
@@ -2568,6 +2568,7 @@ EXPORT_SYMBOL_GPL(random_get_entropy_fal
*/
int do_adjtimex(struct __kernel_timex *txc)
{
+ struct tk_data *tkd = &tk_core;
struct timespec64 delta, ts;
struct audit_ntp_data ad;
bool offset_set = false;
@@ -2585,16 +2586,19 @@ int do_adjtimex(struct __kernel_timex *t
ktime_get_real_ts64(&ts);
add_device_randomness(&ts, sizeof(ts));
- scoped_guard (raw_spinlock_irqsave, &tk_core.lock) {
- struct timekeeper *tks = &tk_core.shadow_timekeeper;
+ scoped_guard (raw_spinlock_irqsave, &tkd->lock) {
+ struct timekeeper *tks = &tkd->shadow_timekeeper;
s32 orig_tai, tai;
+ if (!tks->clock_valid)
+ return -ENODEV;
+
if (txc->modes & ADJ_SETOFFSET) {
delta.tv_sec = txc->time.tv_sec;
delta.tv_nsec = txc->time.tv_usec;
if (!(txc->modes & ADJ_NANO))
delta.tv_nsec *= 1000;
- ret = __timekeeping_inject_offset(&delta);
+ ret = __timekeeping_inject_offset(tkd, &delta);
if (ret)
return ret;
@@ -2607,7 +2611,7 @@ int do_adjtimex(struct __kernel_timex *t
if (tai != orig_tai) {
__timekeeping_set_tai_offset(tks, tai);
- timekeeping_update_from_shadow(&tk_core, TK_CLOCK_WAS_SET);
+ timekeeping_update_from_shadow(tkd, TK_CLOCK_WAS_SET);
clock_set = true;
} else {
tk_update_leap_state_all(&tk_core);
@@ -2615,7 +2619,7 @@ int do_adjtimex(struct __kernel_timex *t
/* Update the multiplier immediately if frequency was set directly */
if (txc->modes & (ADJ_FREQUENCY | ADJ_TICK))
- clock_set |= __timekeeping_advance(&tk_core, TK_ADV_FREQ);
+ clock_set |= __timekeeping_advance(tkd, TK_ADV_FREQ);
}
if (txc->modes & ADJ_SETOFFSET)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 06/11] timekeeping: Add auxiliary clock support to __timekeeping_inject_offset()
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
` (4 preceding siblings ...)
2025-06-25 18:38 ` [patch V3 05/11] timekeeping: Make timekeeping_inject_offset() reusable Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 4:54 ` John Stultz
2025-06-25 18:38 ` [patch V3 07/11] timekeeping: Make do_adjtimex() reusable Thomas Gleixner
` (4 subsequent siblings)
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Redirect the relative offset adjustment to the auxiliary clock offset
instead of modifying CLOCK_REALTIME, which has no meaning in context of
these clocks.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/timekeeping.c | 34 ++++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 8 deletions(-)
---
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1448,16 +1448,34 @@ static int __timekeeping_inject_offset(s
timekeeping_forward_now(tks);
- /* Make sure the proposed value is valid */
- tmp = timespec64_add(tk_xtime(tks), *ts);
- if (timespec64_compare(&tks->wall_to_monotonic, ts) > 0 ||
- !timespec64_valid_settod(&tmp)) {
- timekeeping_restore_shadow(tkd);
- return -EINVAL;
+ if (!IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS) || tks->id == TIMEKEEPER_CORE) {
+ /* Make sure the proposed value is valid */
+ tmp = timespec64_add(tk_xtime(tks), *ts);
+ if (timespec64_compare(&tks->wall_to_monotonic, ts) > 0 ||
+ !timespec64_valid_settod(&tmp)) {
+ timekeeping_restore_shadow(tkd);
+ return -EINVAL;
+ }
+
+ tk_xtime_add(tks, ts);
+ tk_set_wall_to_mono(tks, timespec64_sub(tks->wall_to_monotonic, *ts));
+ } else {
+ struct tk_read_base *tkr_mono = &tks->tkr_mono;
+ ktime_t now, offs;
+
+ /* Get the current time */
+ now = ktime_add_ns(tkr_mono->base, timekeeping_get_ns(tkr_mono));
+ /* Add the relative offset change */
+ offs = ktime_add(tks->offs_aux, timespec64_to_ktime(*ts));
+
+ /* Prevent that the resulting time becomes negative */
+ if (ktime_add(now, offs) < 0) {
+ timekeeping_restore_shadow(tkd);
+ return -EINVAL;
+ }
+ tks->offs_aux = offs;
}
- tk_xtime_add(tks, ts);
- tk_set_wall_to_mono(tks, timespec64_sub(tks->wall_to_monotonic, *ts));
timekeeping_update_from_shadow(tkd, TK_UPDATE_ALL);
return 0;
}
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 07/11] timekeeping: Make do_adjtimex() reusable
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
` (5 preceding siblings ...)
2025-06-25 18:38 ` [patch V3 06/11] timekeeping: Add auxiliary clock support to __timekeeping_inject_offset() Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 4:56 ` John Stultz
2025-06-25 18:38 ` [patch V3 08/11] timekeeping: Prepare do_adtimex() for auxiliary clocks Thomas Gleixner
` (3 subsequent siblings)
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Split out the actual functionality of adjtimex() and make do_adjtimex() a
wrapper which feeds the core timekeeper into it and handles the result
including audit at the call site.
This allows to reuse the actual functionality for auxiliary clocks.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/timekeeping.c | 110 +++++++++++++++++++++++++---------------------
1 file changed, 60 insertions(+), 50 deletions(-)
---
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -2580,17 +2580,18 @@ unsigned long random_get_entropy_fallbac
}
EXPORT_SYMBOL_GPL(random_get_entropy_fallback);
-/**
- * do_adjtimex() - Accessor function to NTP __do_adjtimex function
- * @txc: Pointer to kernel_timex structure containing NTP parameters
- */
-int do_adjtimex(struct __kernel_timex *txc)
+struct adjtimex_result {
+ struct audit_ntp_data ad;
+ struct timespec64 delta;
+ bool clock_set;
+};
+
+static int __do_adjtimex(struct tk_data *tkd, struct __kernel_timex *txc,
+ struct adjtimex_result *result)
{
- struct tk_data *tkd = &tk_core;
- struct timespec64 delta, ts;
- struct audit_ntp_data ad;
- bool offset_set = false;
- bool clock_set = false;
+ struct timekeeper *tks = &tkd->shadow_timekeeper;
+ struct timespec64 ts;
+ s32 orig_tai, tai;
int ret;
/* Validate the data before disabling interrupts */
@@ -2599,56 +2600,65 @@ int do_adjtimex(struct __kernel_timex *t
return ret;
add_device_randomness(txc, sizeof(*txc));
- audit_ntp_init(&ad);
-
ktime_get_real_ts64(&ts);
add_device_randomness(&ts, sizeof(ts));
- scoped_guard (raw_spinlock_irqsave, &tkd->lock) {
- struct timekeeper *tks = &tkd->shadow_timekeeper;
- s32 orig_tai, tai;
-
- if (!tks->clock_valid)
- return -ENODEV;
-
- if (txc->modes & ADJ_SETOFFSET) {
- delta.tv_sec = txc->time.tv_sec;
- delta.tv_nsec = txc->time.tv_usec;
- if (!(txc->modes & ADJ_NANO))
- delta.tv_nsec *= 1000;
- ret = __timekeeping_inject_offset(tkd, &delta);
- if (ret)
- return ret;
-
- offset_set = delta.tv_sec != 0;
- clock_set = true;
- }
-
- orig_tai = tai = tks->tai_offset;
- ret = ntp_adjtimex(tks->id, txc, &ts, &tai, &ad);
-
- if (tai != orig_tai) {
- __timekeeping_set_tai_offset(tks, tai);
- timekeeping_update_from_shadow(tkd, TK_CLOCK_WAS_SET);
- clock_set = true;
- } else {
- tk_update_leap_state_all(&tk_core);
- }
-
- /* Update the multiplier immediately if frequency was set directly */
- if (txc->modes & (ADJ_FREQUENCY | ADJ_TICK))
- clock_set |= __timekeeping_advance(tkd, TK_ADV_FREQ);
+ guard(raw_spinlock_irqsave)(&tkd->lock);
+
+ if (!tks->clock_valid)
+ return -ENODEV;
+
+ if (txc->modes & ADJ_SETOFFSET) {
+ result->delta.tv_sec = txc->time.tv_sec;
+ result->delta.tv_nsec = txc->time.tv_usec;
+ if (!(txc->modes & ADJ_NANO))
+ result->delta.tv_nsec *= 1000;
+ ret = __timekeeping_inject_offset(tkd, &result->delta);
+ if (ret)
+ return ret;
+ result->clock_set = true;
+ }
+
+ orig_tai = tai = tks->tai_offset;
+ ret = ntp_adjtimex(tks->id, txc, &ts, &tai, &result->ad);
+
+ if (tai != orig_tai) {
+ __timekeeping_set_tai_offset(tks, tai);
+ timekeeping_update_from_shadow(tkd, TK_CLOCK_WAS_SET);
+ result->clock_set = true;
+ } else {
+ tk_update_leap_state_all(&tk_core);
}
+ /* Update the multiplier immediately if frequency was set directly */
+ if (txc->modes & (ADJ_FREQUENCY | ADJ_TICK))
+ result->clock_set |= __timekeeping_advance(tkd, TK_ADV_FREQ);
+
+ return ret;
+}
+
+/**
+ * do_adjtimex() - Accessor function to NTP __do_adjtimex function
+ * @txc: Pointer to kernel_timex structure containing NTP parameters
+ */
+int do_adjtimex(struct __kernel_timex *txc)
+{
+ struct adjtimex_result result = { };
+ int ret;
+
+ ret = __do_adjtimex(&tk_core, txc, &result);
+ if (ret < 0)
+ return ret;
+
if (txc->modes & ADJ_SETOFFSET)
- audit_tk_injoffset(delta);
+ audit_tk_injoffset(result.delta);
- audit_ntp_log(&ad);
+ audit_ntp_log(&result.ad);
- if (clock_set)
+ if (result.clock_set)
clock_was_set(CLOCK_SET_WALL);
- ntp_notify_cmos_timer(offset_set);
+ ntp_notify_cmos_timer(result.delta.tv_sec != 0);
return ret;
}
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 08/11] timekeeping: Prepare do_adtimex() for auxiliary clocks
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
` (6 preceding siblings ...)
2025-06-25 18:38 ` [patch V3 07/11] timekeeping: Make do_adjtimex() reusable Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 5:00 ` John Stultz
2025-06-25 18:38 ` [patch V3 09/11] timekeeping: Provide adjtimex() " Thomas Gleixner
` (2 subsequent siblings)
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Exclude ADJ_TAI, leap seconds and PPS functionality as they make no sense
in the context of auxiliary clocks and provide a time stamp based on the
actual clock.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/timekeeping.c | 39 ++++++++++++++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
---
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -58,6 +58,17 @@ static struct tk_data timekeeper_data[TI
/* The core timekeeper */
#define tk_core (timekeeper_data[TIMEKEEPER_CORE])
+#ifdef CONFIG_POSIX_AUX_CLOCKS
+static inline bool tk_get_aux_ts64(unsigned int tkid, struct timespec64 *ts)
+{
+ return ktime_get_aux_ts64(CLOCK_AUX + tkid - TIMEKEEPER_AUX_FIRST, ts);
+}
+#else
+static inline bool tk_get_aux_ts64(unsigned int tkid, struct timespec64 *ts)
+{
+ return false;
+}
+#endif
/* flag for if timekeeping is suspended */
int __read_mostly timekeeping_suspended;
@@ -2503,7 +2514,7 @@ ktime_t ktime_get_update_offsets_now(uns
/*
* timekeeping_validate_timex - Ensures the timex is ok for use in do_adjtimex
*/
-static int timekeeping_validate_timex(const struct __kernel_timex *txc)
+static int timekeeping_validate_timex(const struct __kernel_timex *txc, bool aux_clock)
{
if (txc->modes & ADJ_ADJTIME) {
/* singleshot must not be used with any other mode bits */
@@ -2562,6 +2573,21 @@ static int timekeeping_validate_timex(co
return -EINVAL;
}
+ if (!aux_clock)
+ return 0;
+
+ /* Auxiliary clocks are similar to TAI and do not have leap seconds */
+ if (txc->status & (STA_INS | STA_DEL))
+ return -EINVAL;
+
+ /* No TAI offset setting */
+ if (txc->modes & ADJ_TAI)
+ return -EINVAL;
+
+ /* No PPS support either */
+ if (txc->status & (STA_PPSFREQ | STA_PPSTIME))
+ return -EINVAL;
+
return 0;
}
@@ -2592,15 +2618,22 @@ static int __do_adjtimex(struct tk_data
struct timekeeper *tks = &tkd->shadow_timekeeper;
struct timespec64 ts;
s32 orig_tai, tai;
+ bool aux_clock;
int ret;
+ aux_clock = IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS) && tkd->timekeeper.id != TIMEKEEPER_CORE;
+
/* Validate the data before disabling interrupts */
- ret = timekeeping_validate_timex(txc);
+ ret = timekeeping_validate_timex(txc, aux_clock);
if (ret)
return ret;
add_device_randomness(txc, sizeof(*txc));
- ktime_get_real_ts64(&ts);
+ if (!aux_clock)
+ ktime_get_real_ts64(&ts);
+ else
+ tk_get_aux_ts64(tkd->timekeeper.id, &ts);
+
add_device_randomness(&ts, sizeof(ts));
guard(raw_spinlock_irqsave)(&tkd->lock);
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 09/11] timekeeping: Provide adjtimex() for auxiliary clocks
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
` (7 preceding siblings ...)
2025-06-25 18:38 ` [patch V3 08/11] timekeeping: Prepare do_adtimex() for auxiliary clocks Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 5:01 ` John Stultz
2025-06-25 18:38 ` [patch V3 10/11] timekeeping: Provide update for auxiliary timekeepers Thomas Gleixner
2025-06-25 18:38 ` [patch V3 11/11] timekeeping: Provide interface to control auxiliary clocks Thomas Gleixner
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
The behaviour is close to clock_adtime(CLOCK_REALTIME) with the
following differences:
1) ADJ_SETOFFSET adjusts the auxiliary clock offset
2) ADJ_TAI is not supported
3) Leap seconds are not supported
4) PPS is not supported
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/timekeeping.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
---
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -2860,10 +2860,26 @@ static int aux_clock_set(const clockid_t
return 0;
}
+static int aux_clock_adj(const clockid_t id, struct __kernel_timex *txc)
+{
+ struct tk_data *tkd = aux_get_tk_data(id);
+ struct adjtimex_result result = { };
+
+ if (!tkd)
+ return -ENODEV;
+
+ /*
+ * @result is ignored for now as there are neither hrtimers nor a
+ * RTC related to auxiliary clocks for now.
+ */
+ return __do_adjtimex(tkd, txc, &result);
+}
+
const struct k_clock clock_aux = {
.clock_getres = aux_get_res,
.clock_get_timespec = aux_get_timespec,
.clock_set = aux_clock_set,
+ .clock_adj = aux_clock_adj,
};
static __init void tk_aux_setup(void)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 10/11] timekeeping: Provide update for auxiliary timekeepers
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
` (8 preceding siblings ...)
2025-06-25 18:38 ` [patch V3 09/11] timekeeping: Provide adjtimex() " Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 5:05 ` John Stultz
2025-06-25 18:38 ` [patch V3 11/11] timekeeping: Provide interface to control auxiliary clocks Thomas Gleixner
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Update the auxiliary timekeepers periodically. For now this is tied to the system
timekeeper update from the tick. This might be revisited and moved out of the tick.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
kernel/time/timekeeping.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
---
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -131,9 +131,11 @@ static struct tk_fast tk_fast_raw ____c
#ifdef CONFIG_POSIX_AUX_CLOCKS
static __init void tk_aux_setup(void);
static void tk_aux_update_clocksource(void);
+static void tk_aux_advance(void);
#else
static inline void tk_aux_setup(void) { }
static inline void tk_aux_update_clocksource(void) { }
+static inline void tk_aux_advance(void) { }
#endif
unsigned long timekeeper_lock_irqsave(void)
@@ -2312,11 +2314,13 @@ static bool timekeeping_advance(enum tim
/**
* update_wall_time - Uses the current clocksource to increment the wall time
*
+ * It also updates the enabled auxiliary clock timekeepers
*/
void update_wall_time(void)
{
if (timekeeping_advance(TK_ADV_TICK))
clock_was_set_delayed();
+ tk_aux_advance();
}
/**
@@ -2762,6 +2766,20 @@ static void tk_aux_update_clocksource(vo
}
}
+static void tk_aux_advance(void)
+{
+ unsigned long active = READ_ONCE(aux_timekeepers);
+ unsigned int id;
+
+ for_each_set_bit(id, &active, BITS_PER_LONG) {
+ struct tk_data *tkd = &timekeeper_data[id + TIMEKEEPER_AUX_FIRST];
+
+ guard(raw_spinlock)(&tkd->lock);
+ if (tkd->shadow_timekeeper.clock_valid)
+ __timekeeping_advance(tkd, TK_ADV_TICK);
+ }
+}
+
/**
* ktime_get_aux - Get time for a AUX clock
* @id: ID of the clock to read (CLOCK_AUX...)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [patch V3 11/11] timekeeping: Provide interface to control auxiliary clocks
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
` (9 preceding siblings ...)
2025-06-25 18:38 ` [patch V3 10/11] timekeeping: Provide update for auxiliary timekeepers Thomas Gleixner
@ 2025-06-25 18:38 ` Thomas Gleixner
2025-06-27 5:07 ` John Stultz
10 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-25 18:38 UTC (permalink / raw)
To: LKML
Cc: netdev, Richard Cochran, Christopher Hall, John Stultz,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
Auxiliary clocks are disabled by default and attempts to access them
fail.
Provide an interface to enable/disable them at run-time.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V3: Use kobject.h, clockid_t and cleanup the sysfs init - Thomas W.
Use aux_tkd, aux_tks for clarity - John
---
Documentation/ABI/stable/sysfs-kernel-time-aux-clocks | 5
kernel/time/timekeeping.c | 116 ++++++++++++++++++
2 files changed, 121 insertions(+)
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-kernel-time-aux-clocks
@@ -0,0 +1,5 @@
+What: /sys/kernel/time/aux_clocks/<ID>/enable
+Date: May 2025
+Contact: Thomas Gleixner <tglx@linutronix.de>
+Description:
+ Controls the enablement of auxiliary clock timekeepers.
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -6,6 +6,7 @@
#include <linux/timekeeper_internal.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/kobject.h>
#include <linux/percpu.h>
#include <linux/init.h>
#include <linux/mm.h>
@@ -2903,6 +2904,121 @@ const struct k_clock clock_aux = {
.clock_adj = aux_clock_adj,
};
+static void aux_clock_enable(clockid_t id)
+{
+ struct tk_read_base *tkr_raw = &tk_core.timekeeper.tkr_raw;
+ struct tk_data *aux_tkd = aux_get_tk_data(id);
+ struct timekeeper *aux_tks = &aux_tkd->shadow_timekeeper;
+
+ /* Prevent the core timekeeper from changing. */
+ guard(raw_spinlock_irq)(&tk_core.lock);
+
+ /*
+ * Setup the auxiliary clock assuming that the raw core timekeeper
+ * clock frequency conversion is close enough. Userspace has to
+ * adjust for the deviation via clock_adjtime(2).
+ */
+ guard(raw_spinlock_nested)(&aux_tkd->lock);
+
+ /* Remove leftovers of a previous registration */
+ memset(aux_tks, 0, sizeof(*aux_tks));
+ /* Restore the timekeeper id */
+ aux_tks->id = aux_tkd->timekeeper.id;
+ /* Setup the timekeeper based on the current system clocksource */
+ tk_setup_internals(aux_tks, tkr_raw->clock);
+
+ /* Mark it valid and set it live */
+ aux_tks->clock_valid = true;
+ timekeeping_update_from_shadow(aux_tkd, TK_UPDATE_ALL);
+}
+
+static void aux_clock_disable(clockid_t id)
+{
+ struct tk_data *aux_tkd = aux_get_tk_data(id);
+
+ guard(raw_spinlock_irq)(&aux_tkd->lock);
+ aux_tkd->shadow_timekeeper.clock_valid = false;
+ timekeeping_update_from_shadow(aux_tkd, TK_UPDATE_ALL);
+}
+
+static DEFINE_MUTEX(aux_clock_mutex);
+
+static ssize_t aux_clock_enable_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ /* Lazy atoi() as name is "0..7" */
+ int id = kobj->name[0] & 0x7;
+ bool enable;
+
+ if (!capable(CAP_SYS_TIME))
+ return -EPERM;
+
+ if (kstrtobool(buf, &enable) < 0)
+ return -EINVAL;
+
+ guard(mutex)(&aux_clock_mutex);
+ if (enable == test_bit(id, &aux_timekeepers))
+ return count;
+
+ if (enable) {
+ aux_clock_enable(CLOCK_AUX + id);
+ set_bit(id, &aux_timekeepers);
+ } else {
+ aux_clock_disable(CLOCK_AUX + id);
+ clear_bit(id, &aux_timekeepers);
+ }
+ return count;
+}
+
+static ssize_t aux_clock_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ unsigned long active = READ_ONCE(aux_timekeepers);
+ /* Lazy atoi() as name is "0..7" */
+ int id = kobj->name[0] & 0x7;
+
+ return sysfs_emit(buf, "%d\n", test_bit(id, &active));
+}
+
+static struct kobj_attribute aux_clock_enable_attr = __ATTR_RW(aux_clock_enable);
+
+static struct attribute *aux_clock_enable_attrs[] = {
+ &aux_clock_enable_attr.attr,
+ NULL
+};
+
+static const struct attribute_group aux_clock_enable_attr_group = {
+ .attrs = aux_clock_enable_attrs,
+};
+
+static int __init tk_aux_sysfs_init(void)
+{
+ struct kobject *auxo, *tko = kobject_create_and_add("time", kernel_kobj);
+
+ if (!tko)
+ return -ENOMEM;
+
+ auxo = kobject_create_and_add("aux_clocks", tko);
+ if (!auxo) {
+ kobject_put(tko);
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i <= MAX_AUX_CLOCKS; i++) {
+ char id[2] = { [0] = '0' + i, };
+ struct kobject *clk = kobject_create_and_add(id, auxo);
+
+ if (!clk)
+ return -ENOMEM;
+
+ int ret = sysfs_create_group(clk, &aux_clock_enable_attr_group);
+
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+late_initcall(tk_aux_sysfs_init);
+
static __init void tk_aux_setup(void)
{
for (int i = TIMEKEEPER_AUX_FIRST; i <= TIMEKEEPER_AUX_LAST; i++)
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 02/11] timekeeping: Provide time getters for auxiliary clocks
2025-06-25 18:38 ` [patch V3 02/11] timekeeping: Provide time getters for auxiliary clocks Thomas Gleixner
@ 2025-06-27 4:18 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 4:18 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Provide interfaces similar to the ktime_get*() family which provide access
> to the auxiliary clocks.
>
> These interfaces have a boolean return value, which indicates whether the
> accessed clock is valid or not.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> V3: Remove misleading TAI comment and use aux_tkd* for clarity - John
> ---
> include/linux/posix-timers.h | 5 +++
> include/linux/timekeeping.h | 11 +++++++
> kernel/time/timekeeping.c | 65 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 81 insertions(+)
> ---
Acked-by: John Stultz <jstultz@google.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 03/11] timekeeping: Add minimal posix-timers support for auxiliary clocks
2025-06-25 18:38 ` [patch V3 03/11] timekeeping: Add minimal posix-timers support " Thomas Gleixner
@ 2025-06-27 4:19 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 4:19 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Provide clock_getres(2) and clock_gettime(2) for auxiliary clocks.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
Acked-by: John Stultz <jstultz@google.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 04/11] timekeeping: Provide time setter for auxiliary clocks
2025-06-25 18:38 ` [patch V3 04/11] timekeeping: Provide time setter " Thomas Gleixner
@ 2025-06-27 4:23 ` John Stultz
2025-06-27 14:18 ` Thomas Gleixner
0 siblings, 1 reply; 26+ messages in thread
From: John Stultz @ 2025-06-27 4:23 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
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>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 05/11] timekeeping: Make timekeeping_inject_offset() reusable
2025-06-25 18:38 ` [patch V3 05/11] timekeeping: Make timekeeping_inject_offset() reusable Thomas Gleixner
@ 2025-06-27 4:26 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 4:26 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Split out the inner workings for auxiliary clock support and feed the core time
> keeper into it.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Looks ok to me.
Acked-by: John Stultz <jstultz@google.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 01/11] timekeeping: Update auxiliary timekeepers on clocksource change
2025-06-25 18:38 ` [patch V3 01/11] timekeeping: Update auxiliary timekeepers on clocksource change Thomas Gleixner
@ 2025-06-27 4:43 ` John Stultz
2025-06-27 14:04 ` Thomas Gleixner
0 siblings, 1 reply; 26+ messages in thread
From: John Stultz @ 2025-06-27 4:43 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Propagate a system clocksource change to the auxiliary timekeepers so that
> they can pick up the new clocksource.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> kernel/time/timekeeping.c | 28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
> ---
>
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -119,8 +119,10 @@ static struct tk_fast tk_fast_raw ____c
>
> #ifdef CONFIG_POSIX_AUX_CLOCKS
> static __init void tk_aux_setup(void);
> +static void tk_aux_update_clocksource(void);
> #else
> static inline void tk_aux_setup(void) { }
> +static inline void tk_aux_update_clocksource(void) { }
> #endif
>
> unsigned long timekeeper_lock_irqsave(void)
> @@ -1548,6 +1550,8 @@ static int change_clocksource(void *data
> timekeeping_update_from_shadow(&tk_core, TK_UPDATE_ALL);
> }
>
> + tk_aux_update_clocksource();
> +
> if (old) {
> if (old->disable)
> old->disable(old);
> @@ -2651,6 +2655,30 @@ EXPORT_SYMBOL(hardpps);
> #endif /* CONFIG_NTP_PPS */
>
> #ifdef CONFIG_POSIX_AUX_CLOCKS
> +
> +/* Bitmap for the activated auxiliary timekeepers */
> +static unsigned long aux_timekeepers;
> +
Nit: Would it be useful to clarify this is accessed without locks, and
the related tks->clock_valid *must* be checked while holding the lock
before using a timekeeper that is considered activated in the
aux_timekeepers bitmap?
Otherwise,
Acked-by: John Stultz <jstultz@google.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 06/11] timekeeping: Add auxiliary clock support to __timekeeping_inject_offset()
2025-06-25 18:38 ` [patch V3 06/11] timekeeping: Add auxiliary clock support to __timekeeping_inject_offset() Thomas Gleixner
@ 2025-06-27 4:54 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 4:54 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Redirect the relative offset adjustment to the auxiliary clock offset
> instead of modifying CLOCK_REALTIME, which has no meaning in context of
> these clocks.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> kernel/time/timekeeping.c | 34 ++++++++++++++++++++++++++--------
> 1 file changed, 26 insertions(+), 8 deletions(-)
> ---
>
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -1448,16 +1448,34 @@ static int __timekeeping_inject_offset(s
>
> timekeeping_forward_now(tks);
>
> - /* Make sure the proposed value is valid */
> - tmp = timespec64_add(tk_xtime(tks), *ts);
> - if (timespec64_compare(&tks->wall_to_monotonic, ts) > 0 ||
> - !timespec64_valid_settod(&tmp)) {
> - timekeeping_restore_shadow(tkd);
> - return -EINVAL;
> + if (!IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS) || tks->id == TIMEKEEPER_CORE) {
I feel like this should be in something like:
static inline bool is_core_timekeeper(tsk)
> + /* Make sure the proposed value is valid */
> + tmp = timespec64_add(tk_xtime(tks), *ts);
> + if (timespec64_compare(&tks->wall_to_monotonic, ts) > 0 ||
> + !timespec64_valid_settod(&tmp)) {
> + timekeeping_restore_shadow(tkd);
> + return -EINVAL;
> + }
> +
> + tk_xtime_add(tks, ts);
> + tk_set_wall_to_mono(tks, timespec64_sub(tks->wall_to_monotonic, *ts));
> + } else {
> + struct tk_read_base *tkr_mono = &tks->tkr_mono;
> + ktime_t now, offs;
> +
> + /* Get the current time */
> + now = ktime_add_ns(tkr_mono->base, timekeeping_get_ns(tkr_mono));
> + /* Add the relative offset change */
> + offs = ktime_add(tks->offs_aux, timespec64_to_ktime(*ts));
> +
> + /* Prevent that the resulting time becomes negative */
> + if (ktime_add(now, offs) < 0) {
> + timekeeping_restore_shadow(tkd);
> + return -EINVAL;
> + }
> + tks->offs_aux = offs;
I'd also consider moving this else into a aux helper function as well,
but I'm not 100% on that.
Other than the is_core_timekeeper (or timekeeper_is_core() maybe?)
suggestion above:
Acked-by: John Stultz <jstultz@google.com>
thanks
-john
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 07/11] timekeeping: Make do_adjtimex() reusable
2025-06-25 18:38 ` [patch V3 07/11] timekeeping: Make do_adjtimex() reusable Thomas Gleixner
@ 2025-06-27 4:56 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 4:56 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Split out the actual functionality of adjtimex() and make do_adjtimex() a
> wrapper which feeds the core timekeeper into it and handles the result
> including audit at the call site.
>
> This allows to reuse the actual functionality for auxiliary clocks.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: John Stultz <jstultz@google.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 08/11] timekeeping: Prepare do_adtimex() for auxiliary clocks
2025-06-25 18:38 ` [patch V3 08/11] timekeeping: Prepare do_adtimex() for auxiliary clocks Thomas Gleixner
@ 2025-06-27 5:00 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 5:00 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Exclude ADJ_TAI, leap seconds and PPS functionality as they make no sense
> in the context of auxiliary clocks and provide a time stamp based on the
> actual clock.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> kernel/time/timekeeping.c | 39 ++++++++++++++++++++++++++++++++++++---
> 1 file changed, 36 insertions(+), 3 deletions(-)
> ---
>
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -2562,6 +2573,21 @@ static int timekeeping_validate_timex(co
> return -EINVAL;
> }
>
> + if (!aux_clock)
> + return 0;
> +
> + /* Auxiliary clocks are similar to TAI and do not have leap seconds */
> + if (txc->status & (STA_INS | STA_DEL))
> + return -EINVAL;
> +
> + /* No TAI offset setting */
> + if (txc->modes & ADJ_TAI)
> + return -EINVAL;
> +
> + /* No PPS support either */
> + if (txc->status & (STA_PPSFREQ | STA_PPSTIME))
> + return -EINVAL;
> +
Just a taste issue, but I think it would be more clear if these checks
were nested under the
if (aux_clock) {
...
}
As otherwise if you read-over and miss the !aux_clock early return it
seems like you're erroring out on normally valid cases.
But it's a minor thing.
> @@ -2592,15 +2618,22 @@ static int __do_adjtimex(struct tk_data
> struct timekeeper *tks = &tkd->shadow_timekeeper;
> struct timespec64 ts;
> s32 orig_tai, tai;
> + bool aux_clock;
> int ret;
>
> + aux_clock = IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS) && tkd->timekeeper.id != TIMEKEEPER_CORE;
> +
Again, the is_core_timekeeper() check would be helpful here (or
alternatively is_aux_timekeeper())
Otherwise:
Acked-by: John Stultz <jstultz@google.com>
thanks
-john
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 09/11] timekeeping: Provide adjtimex() for auxiliary clocks
2025-06-25 18:38 ` [patch V3 09/11] timekeeping: Provide adjtimex() " Thomas Gleixner
@ 2025-06-27 5:01 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 5:01 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> The behaviour is close to clock_adtime(CLOCK_REALTIME) with the
> following differences:
>
> 1) ADJ_SETOFFSET adjusts the auxiliary clock offset
>
> 2) ADJ_TAI is not supported
>
> 3) Leap seconds are not supported
>
> 4) PPS is not supported
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: John Stultz <jstultz@google.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 10/11] timekeeping: Provide update for auxiliary timekeepers
2025-06-25 18:38 ` [patch V3 10/11] timekeeping: Provide update for auxiliary timekeepers Thomas Gleixner
@ 2025-06-27 5:05 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 5:05 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Update the auxiliary timekeepers periodically. For now this is tied to the system
> timekeeper update from the tick. This might be revisited and moved out of the tick.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> kernel/time/timekeeping.c | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
> ---
>
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -2762,6 +2766,20 @@ static void tk_aux_update_clocksource(vo
> }
> }
>
> +static void tk_aux_advance(void)
> +{
> + unsigned long active = READ_ONCE(aux_timekeepers);
> + unsigned int id;
> +
> + for_each_set_bit(id, &active, BITS_PER_LONG) {
> + struct tk_data *tkd = &timekeeper_data[id + TIMEKEEPER_AUX_FIRST];
Again, a nit, but I'd use aux_tkd or something just to be super clear
we're using aux ones here.
> +
> + guard(raw_spinlock)(&tkd->lock);
> + if (tkd->shadow_timekeeper.clock_valid)
> + __timekeeping_advance(tkd, TK_ADV_TICK);
> + }
> +}
Otherwise,
Acked-by: John Stultz <jstultz@google.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 11/11] timekeeping: Provide interface to control auxiliary clocks
2025-06-25 18:38 ` [patch V3 11/11] timekeeping: Provide interface to control auxiliary clocks Thomas Gleixner
@ 2025-06-27 5:07 ` John Stultz
0 siblings, 0 replies; 26+ messages in thread
From: John Stultz @ 2025-06-27 5:07 UTC (permalink / raw)
To: Thomas Gleixner
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Wed, Jun 25, 2025 at 11:38 AM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> Auxiliary clocks are disabled by default and attempts to access them
> fail.
>
> Provide an interface to enable/disable them at run-time.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> V3: Use kobject.h, clockid_t and cleanup the sysfs init - Thomas W.
> Use aux_tkd, aux_tks for clarity - John
> ---
Acked-by: John Stultz <jstultz@google.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 01/11] timekeeping: Update auxiliary timekeepers on clocksource change
2025-06-27 4:43 ` John Stultz
@ 2025-06-27 14:04 ` Thomas Gleixner
0 siblings, 0 replies; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-27 14:04 UTC (permalink / raw)
To: John Stultz
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
On Thu, Jun 26 2025 at 21:43, John Stultz wrote:
>> +/* Bitmap for the activated auxiliary timekeepers */
>> +static unsigned long aux_timekeepers;
>> +
>
> Nit: Would it be useful to clarify this is accessed without locks, and
> the related tks->clock_valid *must* be checked while holding the lock
> before using a timekeeper that is considered activated in the
> aux_timekeepers bitmap?
I'll amend all your nits when applying the pile.
Thanks,
tglx
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 04/11] timekeeping: Provide time setter for auxiliary clocks
2025-06-27 4:23 ` John Stultz
@ 2025-06-27 14:18 ` Thomas Gleixner
2025-06-27 14:57 ` Thomas Gleixner
0 siblings, 1 reply; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-27 14:18 UTC (permalink / raw)
To: John Stultz
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
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.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [patch V3 04/11] timekeeping: Provide time setter for auxiliary clocks
2025-06-27 14:18 ` Thomas Gleixner
@ 2025-06-27 14:57 ` Thomas Gleixner
0 siblings, 0 replies; 26+ messages in thread
From: Thomas Gleixner @ 2025-06-27 14:57 UTC (permalink / raw)
To: John Stultz
Cc: LKML, netdev, Richard Cochran, Christopher Hall,
Frederic Weisbecker, Anna-Maria Behnsen, Miroslav Lichvar,
Werner Abt, David Woodhouse, Stephen Boyd, Thomas Weißschuh,
Kurt Kanzenbach, Nam Cao, Antoine Tenart
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
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2025-06-27 14:57 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-25 18:38 [patch V3 00/11] timekeeping: Provide support for auxiliary clocks - Remaining series Thomas Gleixner
2025-06-25 18:38 ` [patch V3 01/11] timekeeping: Update auxiliary timekeepers on clocksource change Thomas Gleixner
2025-06-27 4:43 ` John Stultz
2025-06-27 14:04 ` Thomas Gleixner
2025-06-25 18:38 ` [patch V3 02/11] timekeeping: Provide time getters for auxiliary clocks Thomas Gleixner
2025-06-27 4:18 ` John Stultz
2025-06-25 18:38 ` [patch V3 03/11] timekeeping: Add minimal posix-timers support " Thomas Gleixner
2025-06-27 4:19 ` John Stultz
2025-06-25 18:38 ` [patch V3 04/11] timekeeping: Provide time setter " Thomas Gleixner
2025-06-27 4:23 ` John Stultz
2025-06-27 14:18 ` Thomas Gleixner
2025-06-27 14:57 ` Thomas Gleixner
2025-06-25 18:38 ` [patch V3 05/11] timekeeping: Make timekeeping_inject_offset() reusable Thomas Gleixner
2025-06-27 4:26 ` John Stultz
2025-06-25 18:38 ` [patch V3 06/11] timekeeping: Add auxiliary clock support to __timekeeping_inject_offset() Thomas Gleixner
2025-06-27 4:54 ` John Stultz
2025-06-25 18:38 ` [patch V3 07/11] timekeeping: Make do_adjtimex() reusable Thomas Gleixner
2025-06-27 4:56 ` John Stultz
2025-06-25 18:38 ` [patch V3 08/11] timekeeping: Prepare do_adtimex() for auxiliary clocks Thomas Gleixner
2025-06-27 5:00 ` John Stultz
2025-06-25 18:38 ` [patch V3 09/11] timekeeping: Provide adjtimex() " Thomas Gleixner
2025-06-27 5:01 ` John Stultz
2025-06-25 18:38 ` [patch V3 10/11] timekeeping: Provide update for auxiliary timekeepers Thomas Gleixner
2025-06-27 5:05 ` John Stultz
2025-06-25 18:38 ` [patch V3 11/11] timekeeping: Provide interface to control auxiliary clocks Thomas Gleixner
2025-06-27 5:07 ` John Stultz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).