use core::ops::DivAssign;
use crate::{
println,
time::{NSEC_PER_SEC, sched_clock::sched_clock_register, timekeeping_init},
};
pub struct ClockSource {
read: fn() -> u64,
mask: u64,
mult: u32,
shift: u32,
max_idle_ns: u64,
max_cycles: u64,
maxadj: u32,
name: &'static str,
}
pub(crate) fn clocks_calc_mult_shift(
mult: &mut u32,
shift: &mut u32,
from: u32,
to: u32,
maxsec: u32,
) {
let mut sftacc = 32;
let mut tmp = (u64::from(maxsec) * u64::from(from)) >> 32;
while tmp != 0 {
tmp >>= 1;
sftacc -= 1;
}
let mut sft = 32;
while sft > 0 {
tmp = u64::from(to) << sft;
tmp += u64::from(from) / 2;
tmp.div_assign(u64::from(from));
if (tmp >> sftacc) == 0 {
break;
}
sft -= 1;
}
*mult = tmp as u32;
*shift = sft;
}
#[inline(always)]
fn clocksource_cyc2ns(cycles: u64, mult: u32, shift: u32) -> u64 {
(cycles * u64::from(mult)) >> shift
}
pub(crate) fn clocks_calc_max_nsecs(
mult: u32,
shift: u32,
maxadj: u32,
mask: u64,
max_cyc: &mut u64,
) -> u64 {
let mut max_cycles = u64::MAX;
max_cycles.div_assign(u64::from(mult) + u64::from(maxadj));
max_cycles = max_cycles.min(mask);
let mut max_nsecs = clocksource_cyc2ns(max_cycles, mult - maxadj, shift);
*max_cyc = max_cycles;
max_nsecs >>= 1;
max_nsecs
}
#[inline(always)]
fn dummy_read() -> u64 {
0
}
impl ClockSource {
pub(crate) const fn new() -> Self {
Self {
read: dummy_read,
mask: 0,
mult: 0,
shift: 0,
max_idle_ns: 0,
max_cycles: 0,
maxadj: 0,
name: "dummy clock",
}
}
pub fn create(read: fn() -> u64, mask: u64, name: &'static str) -> Self {
Self { read, mask, mult: 0, shift: 0, max_idle_ns: 0, max_cycles: 0, maxadj: 0, name }
}
#[inline]
fn clocksource_update_max_deferment(&mut self) {
self.max_idle_ns = clocks_calc_max_nsecs(
self.mult,
self.shift,
self.maxadj,
self.mask,
&mut self.max_cycles,
);
}
#[inline]
fn clocksource_max_adjustment(&self) -> u32 {
let mut ret = self.mult * 11;
ret.div_assign(100);
ret
}
#[allow(clippy::panicking_overflow_checks)]
fn __clocksource_update_freq_scale(&mut self, scale: u32, freq: u32) {
if freq != 0 {
let mut sec = self.mask;
sec.div_assign(u64::from(freq));
sec.div_assign(u64::from(scale));
if sec == 0 {
sec = 1;
} else if sec > 600 && self.mask > u64::from(u32::MAX) {
sec = 600;
}
clocks_calc_mult_shift(
&mut self.mult,
&mut self.shift,
freq,
NSEC_PER_SEC as u32 / scale,
sec as u32 * scale,
);
}
self.maxadj = self.clocksource_max_adjustment();
while freq != 0
&& ((self.mult + self.maxadj < self.mult) || (self.mult - self.maxadj > self.mult))
{
self.mult >>= 1;
self.shift -= 1;
self.maxadj = self.clocksource_max_adjustment();
}
debug_assert!((self.mult + self.maxadj >= self.mult));
self.clocksource_update_max_deferment();
println!(
"{}: mask: {:#x} max_cycles: {}, max_idle_ns {} ns",
self.name, self.mask, self.max_cycles, self.max_idle_ns
);
}
#[inline(always)]
fn clocksource_update_freq_hz(&mut self, hz: usize) {
self.__clocksource_update_freq_scale(1, hz as u32);
}
#[inline(always)]
pub(crate) fn read(&self) -> u64 {
(self.read)()
}
#[inline(always)]
pub(crate) fn mask(&self) -> u64 {
self.mask
}
#[inline(always)]
pub(crate) fn mult(&self) -> u32 {
self.mult
}
#[inline(always)]
pub(crate) fn shift(&self) -> u32 {
self.shift
}
}
#[allow(unused)]
pub(crate) fn clocksource_init(mut clocksource: ClockSource, rate: usize) {
let read = clocksource.read;
let mask = clocksource.mask;
sched_clock_register(read, mask, rate);
clocksource.clocksource_update_freq_hz(rate);
timekeeping_init(clocksource);
}