[PATCH] sched_clock: Add option to use absolute time against hardware clock reset

From: Feng Tang

Date: Wed Sep 02 2026 - 04:27:51 EST


Currently sched_clock shows the relative time to the boot starting of
kernel, while there could be long firmware start time before it and
after the hardware reset.

On modern server platforms, there could be several software running in
parallel. Like for arm64, it could have SCP (System Control Processor)
firmware running on SCP processor, and ATF (Arm Trusted Firmware) and
Linux OS on the main processor.

Debugging some nasty issues on these platform may need to cross-check
the logs from these firmwares and Linux kernel for specific events,
where a unified reference timeline is critical. All these software can
read the hardware timer, which is also the base of sched_clock for
Linux kernel. Using the absolute counter since hardware timer reset
makes it possible for all kinds of software to have a same time base.

Add 'abs_sched_clock' parameter to provide an option for using absolute
counter, and users should make sure their sched_clock (hardware timer)
is capable of supporting absolute counter before enabling the option.

Locally, it did help on chasing some RAS issues which needed cooperation
between kernel, SCP firmware and ATF, by mapping the actions from each
players into one timeline based on the timestamps in their logs.

Signed-off-by: Feng Tang <feng.tang@xxxxxxxxxxxxxxxxx>
---
kernel/time/sched_clock.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index f3aaef695b8c..321c580d6799 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -49,6 +49,10 @@ static int irqtime = -1;

core_param(irqtime, irqtime, int, 0400);

+/* Whether to use the absolute counter since the clock hardware reset */
+static bool abs_sched_clock;
+core_param(abs_sched_clock, abs_sched_clock, bool, 0400);
+
static u64 notrace jiffy_sched_clock_read(void)
{
/*
@@ -200,10 +204,14 @@ void sched_clock_register(u64 (*read)(void), int bits, unsigned long rate)

rd = cd.read_data[0];

- /* Update epoch for new counter and update 'epoch_ns' from old counter*/
+ /* Update epoch for new counter and update 'epoch_ns' */
new_epoch = read();
- cyc = cd.actual_read_sched_clock();
- ns = rd.epoch_ns + cyc_to_ns((cyc - rd.epoch_cyc) & rd.sched_clock_mask, rd.mult, rd.shift);
+ if (abs_sched_clock) {
+ ns = cyc_to_ns(new_epoch & new_mask, new_mult, new_shift);
+ } else {
+ cyc = cd.actual_read_sched_clock();
+ ns = rd.epoch_ns + cyc_to_ns((cyc - rd.epoch_cyc) & rd.sched_clock_mask, rd.mult, rd.shift);
+ }
cd.actual_read_sched_clock = read;

rd.read_sched_clock = read;
--
2.39.5 (Apple Git-154)