blob: 886f97957bb8f5492fbd8939135591e7e0ed98e7 [file]
/*
* Copyright (c) 2026 BayLibre SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Generic tickless system-timer core
*
* This header carries the tick accounting that every tickless system-timer
* driver would otherwise reimplement by hand: the cycle-to-tick conversion, the
* announce baseline (last_cycle / last_tick / last_elapsed), the deadline
* computation and the range clamp. A driver reduces to a few cycle-domain
* primitives; the tick contract the kernel calls (sys_clock_set_timeout(),
* sys_clock_elapsed(), sys_clock_cycle_get_32/64()) is emitted here.
*
* The file is an implementation header, not a normal declaration header: it
* *defines* the global sys_clock_* entry points. Any number of drivers can be
* built on it; each includes it once, after providing its own constants and
* primitives. A build compiles a single system-timer driver, so those
* definitions land once.
*
* A driver, before the include, provides:
*
* - Exactly one backend feature macro:
* TIMER_CORE_BACKEND_COMPARE_ORDERED free-running counter plus an absolute
* compare register whose match is an ordered
* comparison: the interrupt fires once the counter
* reaches or has passed the value, so a target
* already in the past fires at once (arm_arch,
* riscv_machine, ...). The usable range is half
* the counter width, which is what
* TIMER_CORE_ALARM_MAX_CYCLES bounds.
* TIMER_CORE_BACKEND_COMPARE_EXACT the same hardware shape, but the match
* is on equality only: a target written after the
* counter has passed it is missed for a whole
* counter period (hpet, mips_cp0, ...). The core
* writes such a comparator through a verify loop
* (see timer_core_set_compare()), so the
* driver needs no minimum-delay floor of its own.
* TIMER_CORE_BACKEND_RELOAD a counter that fires after a relative
* delay (down-counters, compare-match-reset
* periodics). Assumed to auto-reload: on a
* non-tickless kernel it free-runs from the LOAD
* set at init and is not reprogrammed per tick.
*
* If arming requires the timer interrupt to be enabled, enable it inside the
* arming primitive rather than tracking it separately. The core does not model
* interrupt masking.
*
* - static uint32_t/uint64_t timer_driver_cycle_get(void): the hardware cycle
* count. Its rate is TIMER_CORE_CYCLES_PER_SEC (see the knobs below), by default the
* kernel system clock rate. Return the raw counter, even a narrow one that wraps:
* declare its width with TIMER_CORE_COUNTER_WIDTH and the core masks every delta to
* that width, so the driver never has to widen the count in software. The return
* width is the driver's, as with the arming primitives above: uint32_t for a counter
* of TIMER_CORE_COUNTER_WIDTH 32 or less, uint64_t for a wider one. The core narrows
* what it reads to the declared width anyway, so returning the register's own type
* spares a 32-bit target the widening.
*
* - the arming primitive for the chosen backend:
* COMPARE: static void timer_driver_set_compare(uint32_t/uint64_t cycles)
* Write the comparator so an interrupt fires when the counter
* reaches @p cycles, a full-width cycle count. The argument width
* is the driver's: a 64-bit comparator takes uint64_t; a 32-bit
* one may take uint32_t (or mask a uint64_t argument) to drop the
* value to its comparator width. A plain register write is all
* that is wanted here: with COMPARE_ORDERED the hardware handles a
* past target itself, and with COMPARE_EXACT the core wraps this
* in the verify loop that deals with it.
* RELOAD: static void timer_driver_set_reload(uint32_t/uint64_t cycles)
* Fire an interrupt after @p cycles more cycles. The core has
* already clamped @p cycles to [TIMER_CORE_ALARM_MIN_CYCLES,
* TIMER_CORE_ALARM_MAX_CYCLES]. The argument width is the driver's:
* uint32_t suits a counter whose TIMER_CORE_ALARM_MAX_CYCLES fits 32
* bits (the usual case); a wider counter may take uint64_t and
* raise TIMER_CORE_ALARM_MAX_CYCLES to match. The core does not narrow
* the value, so the two must be kept coherent.
*
* Optional knobs (sensible defaults provided):
*
* - TIMER_CORE_CYCLES_PER_SEC: rate, in Hz, of the counter timer_driver_cycle_get() reads,
* from which the core derives the cycles per tick. Defaults to the kernel
* system clock rate; a driver whose counter runs at another rate (prescaled,
* or a fixed frequency) overrides it. With a build-time-constant rate the
* derived cycles-per-tick is a constant (the tick math divides by it on the
* announce path); with a run-time rate
* (CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) the core precomputes it once
* in timer_core_init(), so that path never divides the rate twice.
* The core derives TIMER_CORE_CYC_PER_TICK from it, which a driver may read
* for its own hardware setup but never defines itself.
* - TIMER_CORE_CYCLES_PER_SEC_RUNTIME: define when the override above is a
* variable rather than a build-time constant, a rate read from the clock
* controller at init say. The core then precomputes the cycles per tick the
* same way it does for CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME. The
* variable must hold its final value before timer_core_init() is called.
* - TIMER_CORE_COUNTER_WIDTH: width, in bits, of the count timer_driver_cycle_get()
* returns, up to 64. Defaults to the native register width, which suits any
* counter at least that wide; a counter of another width, including a 64-bit one
* on a 32-bit CPU, states its own. The core masks every delta to this width,
* which is what lets a narrow counter be returned raw.
* - TIMER_CORE_COUNTER_NONMONOTONIC: define if the counter may momentarily read
* behind a value already observed (e.g. a global timer under QEMU SMP); the
* core then treats a backwards read as no elapse instead of a huge jump.
* - TIMER_CORE_COUNTER_NONATOMIC: define when timer_driver_cycle_get() is not a
* single atomic read but a synthesized count (built from a shared software
* accumulator the ISR and reprogram paths also touch). The core then reads
* it under the clock lock in sys_clock_cycle_get_32/64() instead of raw.
* - TIMER_CORE_HAVE_CYCLE_GET_32 / _64: define (and provide your own
* sys_clock_cycle_get_32 / _64) to suppress the core's, e.g. when the raw counter
* needs scaling. timer_core_cycle_get(), available after the include, gives the
* full-width count in the counter's own domain to scale from. The 32-bit one is
* required of a driver that sets TIMER_CORE_CYCLES_PER_SEC, since a counter
* running at a rate of its own is one the kernel cannot read raw. The core then
* emits no 64-bit getter either, that being in the domain the driver just
* declared foreign; supply one as well to have it.
* - TIMER_CORE_ALARM_MAX_CYCLES: largest value the arming primitive can express,
* nothing more. Defaults to the whole span of TIMER_CORE_COUNTER_WIDTH, the alarm and
* the counter usually being the same hardware. Set it where the arming range is
* decided by something else: a compare or reload register narrower than the counter,
* or a separate device. It is a statement about the hardware, so it carries no
* safety margin; the core derives its own from TIMER_CORE_COUNTER_WIDTH.
* - TIMER_CORE_ALARM_MIN_CYCLES (RELOAD): reload floor, in cycles.
* - TIMER_CORE_ALARM_LEAD_CYCLES (COMPARE_EXACT): cycles a compare must be ahead of
* the counter for the match to be caught. Defaults to 1. Raise it for hardware
* that carries the write into the counter's clock domain first.
* The driver completes with its IRQ handler (a hardware acknowledge, then
* timer_core_announce()), its init (connect the IRQ, then timer_core_init()) and,
* on SMP, an smp_timer_init() that primes the per-CPU timer via
* timer_core_smp_prime().
*/
#ifndef ZEPHYR_DRIVERS_TIMER_SYSTEM_TIMER_GENERIC_H_
#define ZEPHYR_DRIVERS_TIMER_SYSTEM_TIMER_GENERIC_H_
#include <zephyr/drivers/timer/system_timer.h>
#include <zephyr/sys/clock.h>
#include <zephyr/sys/util.h>
#if (defined(TIMER_CORE_BACKEND_COMPARE_ORDERED) + \
defined(TIMER_CORE_BACKEND_COMPARE_EXACT) + \
defined(TIMER_CORE_BACKEND_RELOAD)) != 1
#error "define exactly one backend: TIMER_CORE_BACKEND_COMPARE_ORDERED, " \
"TIMER_CORE_BACKEND_COMPARE_EXACT or TIMER_CORE_BACKEND_RELOAD"
#endif
/*
* Cycles per second of the counter that timer_driver_cycle_get() reads. Defaults to
* the kernel system clock rate; a driver whose counter runs at another rate (a
* prescaled or fixed-frequency source) overrides it.
*/
#if defined(TIMER_CORE_CYCLES_PER_SEC)
/* The rate is the driver's own, which the cycle getter rule further down keys on. */
#define TIMER_CORE_DRIVER_CYCLES_PER_SEC
#endif
#if !defined(TIMER_CORE_CYCLES_PER_SEC)
#if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) || \
defined(CONFIG_SYSTEM_CLOCK_HW_CYCLES_PER_SEC_RUNTIME_UPDATE)
#define TIMER_CORE_CYCLES_PER_SEC sys_clock_hw_cycles_per_sec()
#else
/* The Kconfig symbol rather than sys_clock_hw_cycles_per_sec(), whose expansion
* carries a cast: both operands here are Kconfig integers, which keeps
* TIMER_CORE_CYC_PER_TICK usable in a preprocessor test.
*/
#define TIMER_CORE_CYCLES_PER_SEC CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC
#define TIMER_CORE_CYC_PER_TICK_IS_CONSTANT
#endif
#endif
/*
* Cycles per kernel tick, always derived here from the rate: a driver states the
* rate and reads this. With a build-time-constant rate the division folds, which
* matters because the tick math divides by it on the announce path. When the rate
* is only known at run time (CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME, or a
* driver rate flagged with TIMER_CORE_CYCLES_PER_SEC_RUNTIME) it is precomputed
* once in timer_core_init() into a variable, so that path never divides the rate
* twice.
*/
#if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) || \
defined(TIMER_CORE_CYCLES_PER_SEC_RUNTIME)
static uint32_t timer_core_cyc_per_tick;
#define TIMER_CORE_CYC_PER_TICK timer_core_cyc_per_tick
#define TIMER_CORE_PRECOMPUTE_CYC_PER_TICK
#else
#define TIMER_CORE_CYC_PER_TICK (TIMER_CORE_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
/*
* The whole tick math divides by this, so a counter rate below the tick rate
* (or a mis-set TIMER_CORE_CYCLES_PER_SEC) that rounds it to zero must be caught. When the
* default TIMER_CORE_CYCLES_PER_SEC is a build constant, catch it at build time. It is not
* a constant with CONFIG_SYSTEM_CLOCK_HW_CYCLES_PER_SEC_RUNTIME_UPDATE (a runtime
* variable that can even change later), so that case, like the runtime-frequency
* case above, is checked once in timer_core_init() where the value is known.
*/
#if defined(CONFIG_SYSTEM_CLOCK_HW_CYCLES_PER_SEC_RUNTIME_UPDATE)
#define TIMER_CORE_CHECK_CYC_PER_TICK_AT_INIT
#else
BUILD_ASSERT(TIMER_CORE_CYC_PER_TICK != 0, "timer counter rate is below the tick rate");
#endif
#endif
/*
* Default to the native register width: the masked delta then divides in a
* single register, and a counter at least this wide never wraps within the
* scheduling range. A counter of another width states its own, and must state it:
* a genuine 64-bit counter on a 32-bit CPU would otherwise inherit a 32-bit mask
* and silently lose any span past 2^32 cycles (a long debugger halt, a low-power
* sleep). It must never be forced wider than the counter really is either: a
* 64-bit mask on a 32-bit counter underflows once the baseline passes 2^32.
*/
#if !defined(TIMER_CORE_COUNTER_WIDTH)
#define TIMER_CORE_COUNTER_WIDTH __LONG_WIDTH__
#endif
/* Wrap mask for the counter. */
#define TIMER_CORE_COUNTER_MASK (UINT64_MAX >> (64 - TIMER_CORE_COUNTER_WIDTH))
/*
* Type holding a counter value, or a masked delta between two. A counter that
* fits a 32-bit register gets a 32-bit one, so the deltas and the division on
* the announce path stay single-register work on a 32-bit CPU. The announce
* baseline is 64-bit either way: it is what carries the count past the wrap
* this type is allowed to lose.
*/
#if TIMER_CORE_COUNTER_WIDTH <= 32
typedef uint32_t timer_core_cycles_t;
#else
typedef uint64_t timer_core_cycles_t;
#endif
/*
* Furthest deadline the arming hardware can express, in cycles.
*
* The counter's own width by default, because the counter and the alarm are
* usually one piece of hardware: a free-running counter matched by a comparator
* of the same width. Where the arming range is decided by something else, a
* compare or reload register narrower than the counter or a separate device,
* the driver overrides this with what that hardware holds.
*
* This states a hardware limit and nothing else. The margin the core keeps
* against a late announce is TIMER_CORE_COUNTER_SAFE_SPAN below, and what the
* arm path actually honours is the smaller of the two.
*/
#ifndef TIMER_CORE_ALARM_MAX_CYCLES
#define TIMER_CORE_ALARM_MAX_CYCLES TIMER_CORE_COUNTER_MASK
#endif
/* Reload floor, in cycles (RELOAD only). A driver whose hardware needs a larger
* minimum programmable delay overrides it.
*/
#ifndef TIMER_CORE_ALARM_MIN_CYCLES
#define TIMER_CORE_ALARM_MIN_CYCLES 1
#endif
/*
* Widest span since the last announce whose masked delta the core can still
* resolve, derived from the counter width alone.
*
* Half the span: the upper half is headroom, so a late announce (IRQ latency on
* a maximum-length wait) still yields an in-range delta rather than a wrapped
* one. With backwards-read detection (TIMER_CORE_COUNTER_NONMONOTONIC) the upper
* half is instead the range that flags a backwards read, so it can no longer
* double as headroom: the span drops to a quarter and the second quarter becomes
* the headroom.
*
* This is the core's business, not the driver's. A driver states how wide its
* counter is and how much its arming register holds; what margin those imply is
* worked out here.
*/
#ifdef TIMER_CORE_COUNTER_NONMONOTONIC
#define TIMER_CORE_COUNTER_SAFE_SPAN (TIMER_CORE_COUNTER_MASK >> 2)
#else
#define TIMER_CORE_COUNTER_SAFE_SPAN (TIMER_CORE_COUNTER_MASK >> 1)
#endif
/*
* Furthest ahead of the last announce that the core will arm: what the counter
* can still resolve, or what the alarm can express, whichever binds first.
*/
#define TIMER_CORE_MAX_UNANNOUNCED_CYCLES \
((timer_core_cycles_t)MIN((uint64_t)TIMER_CORE_COUNTER_SAFE_SPAN, \
(uint64_t)TIMER_CORE_ALARM_MAX_CYCLES))
/*
* Announce baseline, private to this translation unit.
*
* last_cycle is the cycle count of the most recent announce, held tick-aligned
* (an exact multiple of TIMER_CORE_CYC_PER_TICK above the init baseline). Its low
* TIMER_CORE_COUNTER_WIDTH bits track the hardware counter, so masking a delta against it is
* wrap-correct even for a counter narrower than 64 bits. last_elapsed is the
* tick count most recently reported to the kernel via sys_clock_elapsed().
*/
static uint64_t timer_core_last_cycle;
static uint64_t timer_core_last_tick;
/* Counter cycles from @p from to now, masked to the counter width so it stays
* correct across a wrap. Both terms narrow to the counter's own type first:
* what that drops from the baseline is the extension the mask discards anyway.
*/
static inline timer_core_cycles_t timer_core_cycles_since(uint64_t from)
{
return ((timer_core_cycles_t)timer_driver_cycle_get() - (timer_core_cycles_t)from) &
(timer_core_cycles_t)TIMER_CORE_COUNTER_MASK;
}
/* Largest tick count the span since an announce can reach.
*
* It is bounded by the divisor as much as by the counter width: a 48-bit
* counter at 100000 cycles per tick tops out near 2.8e9 ticks, which fits 32
* bits, where the width alone would say otherwise. Evaluating that needs cycles
* per tick as a preprocessor constant, and TIMER_CORE_CYC_PER_TICK is not one:
* both arms of TIMER_CORE_CYCLES_PER_SEC carry a cast, which #if rejects. So the
* division is only done when the counter runs at the kernel rate and that rate
* is a build constant. Otherwise the width alone decides, which errs towards
* the wider type.
*/
#if defined(TIMER_CORE_CYC_PER_TICK_IS_CONSTANT)
#define TIMER_CORE_MAX_TICKS (TIMER_CORE_COUNTER_MASK / TIMER_CORE_CYC_PER_TICK)
#else
#define TIMER_CORE_MAX_TICKS TIMER_CORE_COUNTER_MASK
#endif
/* Tick counts internal to the core. When the span above can outgrow the 32-bit
* kernel interface, they are held wider: nothing bounds that span while no
* timeout is pending, since the comparator sits as far out as it goes and no
* announce moves the baseline. Only the two places that hand a count to the
* kernel clamp, and they use timer_core_ticks_clamp().
*/
#if TIMER_CORE_MAX_TICKS > UINT32_MAX
typedef uint64_t timer_core_ticks_t;
static inline uint32_t timer_core_ticks_clamp(timer_core_ticks_t ticks)
{
return (uint32_t)MIN(ticks, (timer_core_ticks_t)UINT32_MAX);
}
#else
typedef uint32_t timer_core_ticks_t;
static inline uint32_t timer_core_ticks_clamp(timer_core_ticks_t ticks)
{
return ticks;
}
#endif
static timer_core_ticks_t timer_core_last_elapsed;
/*
* The arm span ceiling, in ticks: TIMER_CORE_MAX_UNANNOUNCED_CYCLES expressed in
* the tick domain so the arm path can clamp there and never form a product
* wider than the counter.
*
* The division folds where both terms are build constants, which is the common
* case. Where the rate is only known at run time it would be a real division on
* every arm, so precompute it once alongside the cycles per tick instead.
*/
#if defined(TIMER_CORE_PRECOMPUTE_CYC_PER_TICK)
static timer_core_ticks_t timer_core_max_span_ticks;
#define TIMER_CORE_MAX_SPAN_TICKS timer_core_max_span_ticks
#else
#define TIMER_CORE_MAX_SPAN_TICKS (TIMER_CORE_MAX_UNANNOUNCED_CYCLES / TIMER_CORE_CYC_PER_TICK)
#if !defined(TIMER_CORE_CHECK_CYC_PER_TICK_AT_INIT)
/* A tick wider than the counter can resolve leaves the masked delta ambiguous,
* which no amount of re-arming recovers, so catch it here rather than at run
* time. The alarm's reach is deliberately not part of this: a tick that only
* outruns the arming register still resolves, it just takes more than one arm
* to reach. This needs the rate to be a build constant, so the cases where it
* is not are checked in timer_core_init() instead.
*/
BUILD_ASSERT(TIMER_CORE_COUNTER_SAFE_SPAN >= TIMER_CORE_CYC_PER_TICK,
"a tick is longer than the counter can span: raise "
"CONFIG_SYS_CLOCK_TICKS_PER_SEC, or slow the counter");
#endif
#endif
#if defined(TIMER_CORE_BACKEND_RELOAD)
/* A catch-up reload (floored at TIMER_CORE_ALARM_MIN_CYCLES because the deadline is
* already due, or because the un-announced span is about to overrun
* TIMER_CORE_MAX_UNANNOUNCED_CYCLES) is in flight. Programming a reload restarts the
* counter, so a stream of set_timeout() calls arriving faster than the floor
* would rewrite the reload before it can expire and postpone the announce
* indefinitely; while this is set, timer_core_arm() leaves the hardware alone
* so the pending fire gets through. Cleared by the announce.
*/
static bool timer_core_catchup;
/* Tick-aligned deadline currently armed in the hardware, or UINT64_MAX when
* nothing is known to be armed (initially, and after each announce, which
* consumes the programmed deadline). timer_core_arm() reprograms only when the
* deadline actually moves. The kernel re-evaluates its earliest timeout on
* every add and abort, a timeslice reset being one of each, so back-to-back
* calls usually land on the same tick boundary. Rewriting a reload for those
* is not merely churn: it restarts the counter, so a sustained stream of
* rewrites keeps any period from ever completing and postpones the announce
* for the duration of the stream. A comparator needs none of this, since
* writing the same absolute value again changes nothing.
*/
static uint64_t timer_core_armed_deadline = UINT64_MAX;
#endif
/* Arm the comparator at an absolute cycle count, whatever the flavour of the
* hardware match, so the callers below never branch on it.
*/
#if defined(TIMER_CORE_BACKEND_COMPARE_ORDERED)
static inline void timer_core_set_compare(uint64_t target)
{
/* Ordered match: a target already behind the counter fires at once. */
timer_driver_set_compare(target);
}
#elif defined(TIMER_CORE_BACKEND_COMPARE_EXACT)
/* Cycles a compare must be ahead of the counter for the match to be caught.
* One by default: a comparator written while the counter is still below it
* fires. Hardware that has to carry the write into the counter's clock domain
* first misses a match that close, and states the lead that costs it.
*/
#ifndef TIMER_CORE_ALARM_LEAD_CYCLES
#define TIMER_CORE_ALARM_LEAD_CYCLES 1
#endif
/* True when @p target is no longer far enough ahead of @p now to be caught,
* evaluated in the counter's own width so a narrow counter wraps correctly.
*/
static inline bool timer_core_target_passed(uint64_t target, uint64_t now)
{
timer_core_cycles_t ahead = ((timer_core_cycles_t)target - (timer_core_cycles_t)now) &
(timer_core_cycles_t)TIMER_CORE_COUNTER_MASK;
/* "Is the target still ahead" is the signed comparison, so the split is
* at half the counter width and nothing else: a property of the counter,
* not of the arming range or of the announce cadence. The core never arms
* past TIMER_CORE_COUNTER_SAFE_SPAN, which is at most this, so a legitimate
* future target is never mistaken for a wrapped one.
*/
return (ahead < TIMER_CORE_ALARM_LEAD_CYCLES) ||
(ahead > (timer_core_cycles_t)(TIMER_CORE_COUNTER_MASK >> 1));
}
/* Arm an equality-match comparator so the interrupt cannot be lost.
*
* Such hardware fires only while the counter equals the comparator, so a value
* written after the counter has gone past it is missed until the counter comes
* all the way round. Write it, then read the counter back: if the target is no
* longer far enough ahead, push it out by TIMER_CORE_ALARM_LEAD_CYCLES and try
* again, doubling the push so a counter that keeps overtaking us still
* terminates. The bump costs accuracy only in the case where the deadline was
* already unmeetable.
*
* This is what lets an exact-match driver drop the minimum-delay floor it would
* otherwise need: the floor exists to keep the requested deadline far enough
* ahead to be caught, and the loop below establishes that directly, at the cost
* of one extra counter read on the deadlines that were already close.
*/
static inline void timer_core_set_compare(uint64_t target)
{
timer_driver_set_compare(target);
timer_core_cycles_t now = timer_driver_cycle_get();
if (unlikely(timer_core_target_passed(target, now))) {
uint32_t bump = TIMER_CORE_ALARM_LEAD_CYCLES;
do {
target = now + bump;
bump *= 2;
timer_driver_set_compare(target);
now = timer_driver_cycle_get();
} while (timer_core_target_passed(target, now));
}
}
#endif
/* Whole ticks elapsed since the last announce, from the current counter. */
static inline timer_core_ticks_t timer_core_delta_ticks(void)
{
timer_core_cycles_t delta = timer_core_cycles_since(timer_core_last_cycle);
#ifdef TIMER_CORE_COUNTER_NONMONOTONIC
/*
* A counter that can momentarily read behind a value already observed
* (e.g. a global timer seen from another CPU under QEMU SMP) produces a
* near-full-span masked delta. Arming is capped at TIMER_CORE_ALARM_MAX_CYCLES (a quarter
* span here), so a legitimate delta, even a late one, stays in the lower
* half; a delta in the upper half is therefore a backwards read and is
* reported as no elapse rather than a spurious huge jump.
*/
if (delta > (timer_core_cycles_t)(TIMER_CORE_COUNTER_MASK >> 1)) {
return 0;
}
#endif
return delta / TIMER_CORE_CYC_PER_TICK;
}
/* Program the timer for a tick-aligned deadline `ticks` out from the last
* reported elapsed. Called with the system clock lock held.
*/
static void timer_core_arm(uint32_t ticks)
{
#if defined(TIMER_CORE_BACKEND_RELOAD)
uint64_t deadline_tick = timer_core_last_tick + timer_core_last_elapsed + ticks;
if (deadline_tick == timer_core_armed_deadline) {
return;
}
timer_core_armed_deadline = deadline_tick;
/*
* Relative reload: the cycles from the last announce to the tick-aligned
* deadline, minus what has already elapsed since then. Both terms are in
* the counter's cycle domain (the elapsed part masked to TIMER_CORE_COUNTER_WIDTH),
* so this stays correct across a counter wrap.
*
* The span is clamped in the tick domain, before the multiply, so the
* product stays inside that width.
*
* Capping it is what keeps a stream of set_timeout() calls with no
* intervening announce from pushing the fire point out indefinitely:
* re-arming restarts the counter, `done` would grow past
* TIMER_CORE_COUNTER_MASK and the masked delta would wrap, silently losing
* the elapsed span. Once `done` reaches the span the subtraction below
* saturates and the ALARM_MIN_CYCLES floor forces a near-immediate fire,
* hence an announce that resets the baseline. The COMPARE path gets the same
* invariant from clamping its absolute deadline.
*/
timer_core_ticks_t span = TIMER_CORE_MAX_SPAN_TICKS;
if ((ticks <= span) && (timer_core_last_elapsed <= (span - ticks))) {
span = timer_core_last_elapsed + ticks;
}
timer_core_cycles_t want = (timer_core_cycles_t)span * TIMER_CORE_CYC_PER_TICK;
timer_core_cycles_t done = timer_core_cycles_since(timer_core_last_cycle);
/*
* Saturate rather than go signed: only the sign of want - done matters, and
* its magnitude when positive. A starved ISR, elapsed past the deadline,
* lands on the floor below whether the difference is zero or hugely
* negative, so zero stands in for every negative value.
*/
timer_core_cycles_t rel = (want > done) ? (want - done) : 0;
if (rel < TIMER_CORE_ALARM_MIN_CYCLES) {
/*
* The announce is due (or overdue): fire as soon as the floor
* allows. If a floored reload is already in flight, leave it
* to expire rather than restart the counter, or a set_timeout()
* stream arriving faster than the floor (e.g. timeslice resets
* from a syscall-heavy thread) would push the fire point out
* forever and freeze announced time for the storm's duration.
* No incoming deadline can need to fire sooner than the floor
* anyway.
*/
if (timer_core_catchup) {
return;
}
timer_core_catchup = true;
rel = TIMER_CORE_ALARM_MIN_CYCLES;
}
timer_driver_set_reload(rel);
#else /* compare backends */
/*
* Absolute, tick-aligned deadline, reached as the announce baseline plus a
* relative span. last_cycle is last_tick * TIMER_CORE_CYC_PER_TICK exactly,
* which timer_core_init() establishes and the announce and the rescale
* maintain, so the deadline is
*
* (last_tick + last_elapsed + ticks) * CYC = last_cycle + (last_elapsed + ticks) * CYC
*
* and the clamp, which subtracts last_cycle straight back off, is on that
* span alone. Forming it directly keeps the arithmetic in the counter's own
* width instead of the baseline's: on a 32-bit target with a 32-bit counter
* the multiply, the compare and the clamp are all single-register work.
*
* The span is clamped in the tick domain, before the multiply, so the
* product cannot overflow that width.
*/
#if TIMER_CORE_COUNTER_WIDTH <= 32
timer_core_ticks_t span = TIMER_CORE_MAX_SPAN_TICKS;
if ((ticks <= span) && (timer_core_last_elapsed <= (span - ticks))) {
span = timer_core_last_elapsed + ticks;
}
timer_core_set_compare(timer_core_last_cycle +
(timer_core_cycles_t)span * TIMER_CORE_CYC_PER_TICK);
#else
/* Nothing to narrow to: the span and the baseline are the same width, so
* form the deadline directly and let the clamp subtract the baseline off.
*/
uint64_t deadline =
(timer_core_last_tick + timer_core_last_elapsed + ticks) * TIMER_CORE_CYC_PER_TICK;
if ((deadline - timer_core_last_cycle) > TIMER_CORE_MAX_UNANNOUNCED_CYCLES) {
deadline = timer_core_last_cycle + TIMER_CORE_MAX_UNANNOUNCED_CYCLES;
}
timer_core_set_compare(deadline);
#endif
#endif
}
void sys_clock_set_timeout(uint32_t ticks, bool idle)
{
/* Deprecated; the idle-entry hint travels via sys_clock_idle_enter(). */
ARG_UNUSED(idle);
__ASSERT(sys_clock_is_locked(), "system clock lock not held");
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
return;
}
timer_core_arm(ticks);
}
uint32_t sys_clock_elapsed(void)
{
__ASSERT(sys_clock_is_locked(), "system clock lock not held");
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
return 0;
}
timer_core_last_elapsed = timer_core_delta_ticks();
return timer_core_ticks_clamp(timer_core_last_elapsed);
}
/* Account the whole ticks elapsed since the last announce, rearm (tickful only;
* tickless rearms from the kernel's reprogram after the announce) and announce,
* with the clock lock already held. @p key is the key returned by the driver's
* sys_clock_lock() and is consumed here. Use this when the driver must do work
* that has to be atomic with the announce (e.g. committing a wrap into its cycle
* counter) before handing off.
*/
static void timer_core_announce_from(k_spinlock_key_t key)
{
timer_core_ticks_t dticks = timer_core_delta_ticks();
timer_core_last_cycle += (timer_core_cycles_t)dticks * TIMER_CORE_CYC_PER_TICK;
timer_core_last_tick += dticks;
timer_core_last_elapsed = 0;
#if defined(TIMER_CORE_BACKEND_RELOAD)
/* The programmed deadline is consumed (or obsolete): the kernel decides
* the next one after the announce, and it must reach the hardware even
* if it lands on the same tick.
*/
timer_core_armed_deadline = UINT64_MAX;
timer_core_catchup = false;
#endif
#if !defined(TIMER_CORE_BACKEND_RELOAD)
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
/* Re-arm the comparator one tick out. A RELOAD counter reloads
* itself from the LOAD set at init, so it needs nothing here.
*/
timer_core_arm(1);
}
#endif
/* The baseline above moved by the whole delta, so it stays aligned with
* the counter. Only what the kernel is told is clamped to the width of
* its interface, and that difference is uptime drift, which is what
* sloppy idle allows in the first place.
*/
sys_clock_announce_locked(timer_core_ticks_clamp(dticks), key);
}
/* Announce a span of cycles the driver worked out for itself, rather than one
* read from the counter, with the clock lock already held. @p key is the key
* returned by the driver's sys_clock_lock() and is consumed here.
*
* For a driver recovering elapsed time from somewhere other than its counter,
* a low-power companion that kept time while the counter was stopped, where the
* span can outrun what the counter's width can express.
*
* The arithmetic here is 64-bit whatever the counter's width, since that span is
* exactly the case the width cannot cover. That is why this is separate from
* timer_core_announce_from(), which stays in the counter's own width: only the
* recovery path pays for the wider math.
*
* Only whole ticks are announced. The sub-tick remainder is left where the
* driver's own counter still holds it, for the next delta to pick up.
*
* inline so the drivers with no such recovery path do not trip
* -Wunused-function.
*/
static inline void timer_core_announce_cycles64_from(k_spinlock_key_t key, uint64_t cycles)
{
uint64_t dticks = cycles / TIMER_CORE_CYC_PER_TICK;
timer_core_last_cycle += dticks * TIMER_CORE_CYC_PER_TICK;
timer_core_last_tick += dticks;
timer_core_last_elapsed = 0;
#if defined(TIMER_CORE_BACKEND_RELOAD)
timer_core_armed_deadline = UINT64_MAX;
timer_core_catchup = false;
#endif
/*
* Not timer_core_ticks_clamp(): its argument is timer_core_ticks_t, the
* very width this span is allowed to outrun, so the value would be
* truncated on the way in rather than clamped. Clamp against the
* announce interface itself.
*/
sys_clock_announce_locked((uint32_t)MIN(dticks, (uint64_t)UINT32_MAX), key);
}
/* Read the counter, account the whole ticks elapsed since the last announce,
* rearm and announce. The driver ISR body reduces to a hardware acknowledge
* followed by this call. inline so a driver that instead uses
* timer_core_announce_from() directly does not trip -Wunused-function.
*/
static inline void timer_core_announce(void)
{
timer_core_announce_from(sys_clock_lock());
}
/*
* Full-width cycle count, in the counter's own domain: the announce baseline
* (which carries the extended upper bits) plus the masked forward delta. A
* driver scaling the count into another unit builds its own getters on this.
*
* The read is taken under the clock lock when it cannot be trusted atomically:
*
* - timer_driver_cycle_get() is a synthesized count, not a single register read
* (TIMER_CORE_COUNTER_NONATOMIC): the lock serialises it against the ISR and
* reprogram paths that update the same software state; or
* - the full 64-bit baseline is read on a narrower counter (the getter below
* needs all 64 bits, which is not a single load on a 32-bit CPU).
*
* A narrow counter feeding only the 32-bit getter does NOT need this: that path
* reconstructs from the baseline's low word, a single atomic load, so it stays
* lock-free (see sys_clock_cycle_get_32()). Keeping the lock out of the 32-bit
* getter matters because it is on the thread-usage timestamp hot path.
*/
static inline uint64_t timer_core_cycle_get(void)
{
#if defined(TIMER_CORE_COUNTER_NONATOMIC) || TIMER_CORE_COUNTER_WIDTH < 64
k_spinlock_key_t key = sys_clock_lock();
uint64_t ret = timer_core_last_cycle + timer_core_cycles_since(timer_core_last_cycle);
sys_clock_unlock(key);
return ret;
#else
/* A counter as wide as the count itself needs no extending. */
return timer_driver_cycle_get();
#endif
}
/*
* A driver that states its own TIMER_CORE_CYCLES_PER_SEC has a counter running at
* a rate the kernel does not know about, so what this core would emit, the raw
* count, is not what the kernel expects to read. The 32-bit getter is then the
* driver's, in whatever unit it settles on, and this core emits no 64-bit one
* either: that would be in the counter's own domain and disagree. A driver
* wanting a 64-bit getter in its unit supplies that too.
*/
#if defined(TIMER_CORE_DRIVER_CYCLES_PER_SEC)
#if !defined(TIMER_CORE_HAVE_CYCLE_GET_32)
#error "a driver setting TIMER_CORE_CYCLES_PER_SEC must define " \
"TIMER_CORE_HAVE_CYCLE_GET_32 and supply sys_clock_cycle_get_32()"
#endif
#ifndef TIMER_CORE_HAVE_CYCLE_GET_64
#define TIMER_CORE_HAVE_CYCLE_GET_64
#endif
#endif
#if !defined(TIMER_CORE_HAVE_CYCLE_GET_32)
uint32_t sys_clock_cycle_get_32(void)
{
#if defined(TIMER_CORE_COUNTER_NONATOMIC)
/* Synthesized read: serialise the get and baseline under the lock. */
return (uint32_t)timer_core_cycle_get();
#elif TIMER_CORE_COUNTER_WIDTH < 32
/* Narrow atomic counter: extend from the baseline's low word. Both reads
* are single loads, and pairing one baseline read with one counter read
* yields the true position regardless of an announce in between, so this
* needs no lock.
*/
uint32_t base = (uint32_t)timer_core_last_cycle;
uint32_t delta = ((uint32_t)timer_driver_cycle_get() - base) &
(uint32_t)TIMER_CORE_COUNTER_MASK;
return base + delta;
#else
return (uint32_t)timer_driver_cycle_get();
#endif
}
#endif
#if !defined(TIMER_CORE_HAVE_CYCLE_GET_64)
uint64_t sys_clock_cycle_get_64(void)
{
return timer_core_cycle_get();
}
#endif
/* Rescale the announce baseline from one cycle rate to another. A driver that
* changes the timer frequency at runtime calls this (after rescaling its own
* cycle counter) so the tick accounting stays continuous, without touching the
* core's private baseline directly. last_tick is a tick count and so is
* frequency-independent; only the cycle-domain baseline scales.
*/
static inline void timer_core_rescale(uint32_t to_hz, uint32_t from_hz)
{
ARG_UNUSED(from_hz);
#ifdef TIMER_CORE_PRECOMPUTE_CYC_PER_TICK
/* The rate just changed, so the precomputed cycles-per-tick is stale. */
timer_core_cyc_per_tick = to_hz / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
#else
ARG_UNUSED(to_hz);
#endif
/*
* Re-express the announce baseline in the new cycle domain. Deriving it
* from last_tick (a frequency-independent tick count) keeps it an exact
* multiple of TIMER_CORE_CYC_PER_TICK, the invariant the arm and announce paths rely
* on. Scaling the old cycle value directly would leave it a fraction of a
* tick off and, on the COMPARE arm, could make (deadline - last_cycle)
* underflow. The caller has already rescaled its own cycle counter.
*/
timer_core_last_cycle = timer_core_last_tick * TIMER_CORE_CYC_PER_TICK;
}
/* Prime the calling CPU's timer one tick ahead of the shared baseline. An SMP
* driver calls this from smp_timer_init() so it need not touch the core's
* private baseline.
*/
static inline void timer_core_smp_prime(void)
{
#if defined(TIMER_CORE_BACKEND_RELOAD)
timer_driver_set_reload(TIMER_CORE_CYC_PER_TICK);
#else
timer_core_set_compare(timer_core_last_cycle + TIMER_CORE_CYC_PER_TICK);
#endif
}
/* Seed the announce baseline from the current counter and arm the first tick.
* The driver calls this from its init after connecting the IRQ (and, for a
* runtime frequency, after setting TIMER_CORE_CYC_PER_TICK).
*/
static inline void timer_core_init(void)
{
#ifdef TIMER_CORE_PRECOMPUTE_CYC_PER_TICK
/* Rate is known only now (the driver has brought the counter up), so
* fix the cycles-per-tick the tick math will divide by.
*/
timer_core_cyc_per_tick = TIMER_CORE_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
timer_core_max_span_ticks = TIMER_CORE_MAX_UNANNOUNCED_CYCLES / TIMER_CORE_CYC_PER_TICK;
#endif
#if defined(TIMER_CORE_PRECOMPUTE_CYC_PER_TICK) || defined(TIMER_CORE_CHECK_CYC_PER_TICK_AT_INIT)
/* Runtime-rate cases: TIMER_CORE_CYC_PER_TICK is not a constant expression, so the
* non-zero check the constant case gets at build time happens here instead.
*/
__ASSERT(TIMER_CORE_CYC_PER_TICK != 0, "timer counter rate is below the tick rate");
__ASSERT(TIMER_CORE_COUNTER_SAFE_SPAN >= TIMER_CORE_CYC_PER_TICK,
"a tick is longer than the counter can span");
#endif
/* The counter read is inside the counter's width, so the tick count it
* divides down to and the cycle count that multiplies back up both are too.
*/
timer_core_cycles_t seed = timer_driver_cycle_get() / TIMER_CORE_CYC_PER_TICK;
timer_core_last_tick = seed;
timer_core_last_cycle = seed * TIMER_CORE_CYC_PER_TICK;
timer_core_last_elapsed = 0;
#if defined(TIMER_CORE_BACKEND_RELOAD)
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
/* A tickful RELOAD driver configures its hardware to auto-reload one
* tick and is never reprogrammed (see timer_core_announce_from()), so the
* driver owns the period. Arming here would instead program it to the
* sub-tick remainder left after seeding the baseline, and that short
* value would stick as the permanent period.
*/
return;
}
#endif
timer_core_arm(1);
}
#endif /* ZEPHYR_DRIVERS_TIMER_SYSTEM_TIMER_GENERIC_H_ */