#![allow(static_mut_refs)]
use crate::{
processor::barrier,
sync::seqlock::SeqCount,
time::{NSEC_PER_SEC, clocksource::ClockSource},
};
struct TkReadBase {
clock: ClockSource,
mask: u64,
cycle_last: u64,
mult: u32,
shift: u32,
ktime_nsec: u64,
}
#[repr(align(64))]
struct TimeKeeper {
tkr_mono: TkReadBase,
ktime_sec: u64,
seqcount: SeqCount,
}
impl TimeKeeper {
#[inline(always)]
fn tk_clock_read(&self) -> u64 {
self.tkr_mono.clock.read()
}
fn tk_setup_internals(&mut self) {
self.tkr_mono.mask = self.tkr_mono.clock.mask();
self.tkr_mono.mult = self.tkr_mono.clock.mult();
self.tkr_mono.shift = self.tkr_mono.clock.shift();
self.tkr_mono.cycle_last = self.tk_clock_read();
self.tkr_mono.ktime_nsec = 0;
self.ktime_sec = 0;
}
#[inline(always)]
fn tk_normalize_xtime(&mut self) {
while self.tkr_mono.ktime_nsec >= NSEC_PER_SEC << self.tkr_mono.shift {
self.tkr_mono.ktime_nsec -= NSEC_PER_SEC << self.tkr_mono.shift;
self.ktime_sec += 1;
}
}
fn timekeeping_forward_now(&mut self) {
let cycle_now = self.tk_clock_read();
let delta = clocksource_delta(cycle_now, self.tkr_mono.cycle_last, self.tkr_mono.mask);
self.tkr_mono.cycle_last = cycle_now;
self.tkr_mono.ktime_nsec += delta * u64::from(self.tkr_mono.mult);
self.tk_normalize_xtime();
}
#[inline(always)]
fn timekeeping_get_delta(&self) -> u64 {
let cycle_last = self.tkr_mono.cycle_last;
barrier();
let cycle_now = self.tk_clock_read();
clocksource_delta(cycle_now, cycle_last, self.tkr_mono.mask)
}
#[inline(always)]
fn timekeeping_delta_to_ns(&self, delta: u64) -> u64 {
let mut nsec = delta * u64::from(self.tkr_mono.mult) + self.tkr_mono.ktime_nsec;
nsec >>= self.tkr_mono.shift;
nsec
}
#[inline(always)]
fn timekeeping_get_ns(&self) -> u64 {
let delta = self.timekeeping_get_delta();
self.timekeeping_delta_to_ns(delta)
}
}
#[inline(always)]
fn clocksource_delta(now: u64, last: u64, mask: u64) -> u64 {
(now - last) & mask
}
static mut TIMEKEEPER: TimeKeeper = TimeKeeper {
tkr_mono: TkReadBase {
clock: ClockSource::new(),
mask: 0,
cycle_last: 0,
mult: 0,
shift: 0,
ktime_nsec: 0,
},
ktime_sec: 0,
seqcount: SeqCount::new(),
};
pub(super) fn timekeeping_init(clocksource: ClockSource) {
let tk = unsafe { &mut TIMEKEEPER };
tk.seqcount.write_seqcount_begin();
tk.tkr_mono.clock = clocksource;
tk.tk_setup_internals();
tk.seqcount.write_seqcount_end();
}
pub(super) fn update_wall_time() {
let tk = unsafe { &mut TIMEKEEPER };
tk.seqcount.write_seqcount_begin();
tk.timekeeping_forward_now();
tk.seqcount.write_seqcount_end();
}
pub fn ktime_get_cycles() -> u64 {
unsafe { TIMEKEEPER.tk_clock_read() }
}
pub fn ktime_get_seconds() -> u64 {
unsafe { TIMEKEEPER.ktime_sec }
}
pub fn ktime_get() -> u64 {
let tk = unsafe { &TIMEKEEPER };
loop {
let seq = tk.seqcount.read_seqcount_begin();
let base = tk.ktime_sec;
let nsecs = tk.timekeeping_get_ns();
if !tk.seqcount.read_seqcount_retry(seq) {
return base * NSEC_PER_SEC + nsecs;
}
}
}
pub fn ktime_get_resolution_ns() -> u32 {
let tk = unsafe { &TIMEKEEPER };
tk.tkr_mono.mult >> tk.tkr_mono.shift
}