mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
feat(driver/acpi_pm): Implement ACPI PM Timer (#772)
* feat: Implement ACPI PM Timer
This commit is contained in:
parent
f75cb0f8ed
commit
dd8e74ef0d
@ -1,8 +1,6 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{driver::acpi::acpi_manager, kinfo, mm::percpu::PerCpu, smp::cpu::ProcessorId};
|
||||
|
||||
use super::smp::SMP_BOOT_DATA;
|
||||
use crate::{driver::acpi::acpi_manager, kinfo, mm::percpu::PerCpu, smp::cpu::ProcessorId};
|
||||
use system_error::SystemError;
|
||||
|
||||
pub(super) fn early_acpi_boot_init() -> Result<(), SystemError> {
|
||||
// 在这里解析madt,初始化smp boot data
|
||||
|
@ -44,6 +44,14 @@ pub fn hpet_instance() -> &'static Hpet {
|
||||
unsafe { HPET_INSTANCE.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_hpet_enabled() -> bool {
|
||||
if unsafe { HPET_INSTANCE.as_ref().is_some() } {
|
||||
return unsafe { HPET_INSTANCE.as_ref().unwrap().enabled() };
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub struct Hpet {
|
||||
info: HpetInfo,
|
||||
_mmio_guard: MMIOSpaceGuard,
|
||||
@ -254,10 +262,8 @@ impl Hpet {
|
||||
}
|
||||
|
||||
pub fn hpet_init() -> Result<(), SystemError> {
|
||||
let hpet_info = HpetInfo::new(acpi_manager().tables().unwrap()).map_err(|e| {
|
||||
kerror!("Failed to get HPET info: {:?}", e);
|
||||
SystemError::ENODEV
|
||||
})?;
|
||||
let hpet_info =
|
||||
HpetInfo::new(acpi_manager().tables().unwrap()).map_err(|_| SystemError::ENODEV)?;
|
||||
|
||||
let hpet_instance = Hpet::new(hpet_info)?;
|
||||
unsafe {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
arch::{io::PortIOArch, CurrentIrqArch, CurrentPortIOArch, CurrentTimeArch},
|
||||
driver::acpi::pmtmr::{ACPI_PM_OVERRUN, PMTMR_TICKS_PER_SEC},
|
||||
driver::acpi::pmtmr::{acpi_pm_read_early, ACPI_PM_OVERRUN, PMTMR_TICKS_PER_SEC},
|
||||
exception::InterruptArch,
|
||||
kdebug, kerror, kinfo, kwarn,
|
||||
time::TimeArch,
|
||||
time::{TimeArch, PIT_TICK_RATE},
|
||||
};
|
||||
use core::{
|
||||
cmp::{max, min},
|
||||
@ -11,10 +11,7 @@ use core::{
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::hpet::hpet_instance;
|
||||
|
||||
/// The clock frequency of the i8253/i8254 PIT
|
||||
const PIT_TICK_RATE: u64 = 1193182;
|
||||
use super::hpet::{hpet_instance, is_hpet_enabled};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TSCManager;
|
||||
@ -104,7 +101,7 @@ impl TSCManager {
|
||||
///
|
||||
/// 使用pit、hpet、ptimer来测量CPU总线的频率
|
||||
fn calibrate_cpu_by_pit_hpet_ptimer() -> Result<u64, SystemError> {
|
||||
let hpet = hpet_instance().enabled();
|
||||
let hpet = is_hpet_enabled();
|
||||
kdebug!(
|
||||
"Calibrating TSC with {}",
|
||||
if hpet { "HPET" } else { "PMTIMER" }
|
||||
@ -321,7 +318,7 @@ impl TSCManager {
|
||||
if hpet_enabled {
|
||||
ref_ret = hpet_instance().main_counter_value();
|
||||
} else {
|
||||
todo!("read pmtimer")
|
||||
ref_ret = acpi_pm_read_early() as u64;
|
||||
}
|
||||
let t2 = CurrentTimeArch::get_cycles() as u64;
|
||||
if (t2 - t1) < thresh {
|
||||
|
@ -5,6 +5,7 @@ use x86::dtables::DescriptorTablePointer;
|
||||
|
||||
use crate::{
|
||||
arch::{interrupt::trap::arch_trap_init, process::table::TSSManager},
|
||||
driver::clocksource::acpi_pm::init_acpi_pm_clocksource,
|
||||
init::init::start_kernel,
|
||||
kdebug,
|
||||
mm::{MemoryManagementArch, PhysAddr},
|
||||
@ -93,8 +94,12 @@ pub fn setup_arch() -> Result<(), SystemError> {
|
||||
/// 架构相关的初始化(在IDLE的最后一个阶段)
|
||||
#[inline(never)]
|
||||
pub fn setup_arch_post() -> Result<(), SystemError> {
|
||||
hpet_init().expect("hpet init failed");
|
||||
hpet_instance().hpet_enable().expect("hpet enable failed");
|
||||
let ret = hpet_init();
|
||||
if ret.is_ok() {
|
||||
hpet_instance().hpet_enable().expect("hpet enable failed");
|
||||
} else {
|
||||
init_acpi_pm_clocksource().expect("acpi_pm_timer inits failed");
|
||||
}
|
||||
TSCManager::init().expect("tsc init failed");
|
||||
|
||||
return Ok(());
|
||||
|
@ -1,4 +1,30 @@
|
||||
use crate::driver::clocksource::acpi_pm::{acpi_pm_read_verified, PMTMR_IO_PORT};
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
pub const ACPI_PM_OVERRUN: u64 = 1 << 24;
|
||||
|
||||
/// Number of PMTMR ticks expected during calibration run
|
||||
pub const PMTMR_TICKS_PER_SEC: u64 = 3579545;
|
||||
|
||||
/// 用于掩码ACPI_PM_READ_ERALY返回值的前24位
|
||||
pub const ACPI_PM_MASK: u64 = 0xffffff;
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn acpi_pm_read_early() -> u32 {
|
||||
let port = unsafe { PMTMR_IO_PORT.load(Ordering::SeqCst) };
|
||||
|
||||
// 如果端口为零直接返回
|
||||
if port == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 对读取的pmtmr值进行验证并进行掩码处理
|
||||
return acpi_pm_read_verified() & ACPI_PM_MASK as u32;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
pub fn acpi_pm_read_early() -> u32 {
|
||||
return 0;
|
||||
}
|
||||
|
296
kernel/src/driver/clocksource/acpi_pm.rs
Normal file
296
kernel/src/driver/clocksource/acpi_pm.rs
Normal file
@ -0,0 +1,296 @@
|
||||
use crate::{
|
||||
alloc::string::ToString,
|
||||
arch::{io::PortIOArch, CurrentPortIOArch},
|
||||
driver::acpi::{
|
||||
acpi_manager,
|
||||
pmtmr::{ACPI_PM_MASK, PMTMR_TICKS_PER_SEC},
|
||||
},
|
||||
libs::spinlock::SpinLock,
|
||||
time::{
|
||||
clocksource::{Clocksource, ClocksourceData, ClocksourceFlags, ClocksourceMask, CycleNum},
|
||||
PIT_TICK_RATE,
|
||||
},
|
||||
};
|
||||
use acpi::fadt::Fadt;
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use core::intrinsics::unlikely;
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
use system_error::SystemError;
|
||||
|
||||
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/clocksource/acpi_pm.c
|
||||
|
||||
/// acpi_pmtmr所在的I/O端口
|
||||
pub static mut PMTMR_IO_PORT: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
/// # 读取acpi_pmtmr当前值,并对齐进行掩码操作
|
||||
#[inline(always)]
|
||||
fn read_pmtmr() -> u32 {
|
||||
return unsafe { CurrentPortIOArch::in32(PMTMR_IO_PORT.load(Ordering::SeqCst) as u16) }
|
||||
& ACPI_PM_MASK as u32;
|
||||
}
|
||||
|
||||
//参考: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/clocksource/acpi_pm.c#41
|
||||
/// # 读取acpi_pmtmr的值,并进行多次读取以保证获取正确的值
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - u32: 读取到的acpi_pmtmr值
|
||||
pub fn acpi_pm_read_verified() -> u32 {
|
||||
let mut v2: u32;
|
||||
|
||||
// 因为某些损坏芯片组(如ICH4、PIIX4和PIIX4E)可能导致APCI PM时钟源未锁存
|
||||
// 因此需要多次读取以保证获取正确的值
|
||||
loop {
|
||||
let v1 = read_pmtmr();
|
||||
v2 = read_pmtmr();
|
||||
let v3 = read_pmtmr();
|
||||
|
||||
if !(unlikely((v2 > v3 || v1 < v3) && v1 > v2 || v1 < v3 && v2 > v3)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return v2;
|
||||
}
|
||||
|
||||
/// # 作为时钟源的读取函数
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - u64: acpi_pmtmr的当前值
|
||||
fn acpi_pm_read() -> u64 {
|
||||
return read_pmtmr() as u64;
|
||||
}
|
||||
|
||||
pub static mut CLOCKSOURCE_ACPI_PM: Option<Arc<Acpipm>> = None;
|
||||
|
||||
pub fn clocksource_acpi_pm() -> Arc<Acpipm> {
|
||||
return unsafe { CLOCKSOURCE_ACPI_PM.as_ref().unwrap().clone() };
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Acpipm(SpinLock<InnerAcpipm>);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerAcpipm {
|
||||
data: ClocksourceData,
|
||||
self_reaf: Weak<Acpipm>,
|
||||
}
|
||||
|
||||
impl Acpipm {
|
||||
pub fn new() -> Arc<Self> {
|
||||
let data = ClocksourceData {
|
||||
name: "acpi_pm".to_string(),
|
||||
rating: 200,
|
||||
mask: ClocksourceMask::new(ACPI_PM_MASK),
|
||||
mult: 0,
|
||||
shift: 0,
|
||||
max_idle_ns: Default::default(),
|
||||
flags: ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS,
|
||||
watchdog_last: CycleNum::new(0),
|
||||
uncertainty_margin: 0,
|
||||
maxadj: 0,
|
||||
};
|
||||
let acpi_pm = Arc::new(Acpipm(SpinLock::new(InnerAcpipm {
|
||||
data,
|
||||
self_reaf: Default::default(),
|
||||
})));
|
||||
acpi_pm.0.lock().self_reaf = Arc::downgrade(&acpi_pm);
|
||||
|
||||
return acpi_pm;
|
||||
}
|
||||
}
|
||||
|
||||
impl Clocksource for Acpipm {
|
||||
fn read(&self) -> CycleNum {
|
||||
return CycleNum::new(acpi_pm_read());
|
||||
}
|
||||
|
||||
fn clocksource_data(&self) -> ClocksourceData {
|
||||
let inner = self.0.lock_irqsave();
|
||||
return inner.data.clone();
|
||||
}
|
||||
|
||||
fn clocksource(&self) -> Arc<dyn Clocksource> {
|
||||
return self.0.lock_irqsave().self_reaf.upgrade().unwrap();
|
||||
}
|
||||
|
||||
fn update_clocksource_data(&self, data: ClocksourceData) -> Result<(), SystemError> {
|
||||
let d = &mut self.0.lock_irqsave().data;
|
||||
d.set_flags(data.flags);
|
||||
d.set_mask(data.mask);
|
||||
d.set_max_idle_ns(data.max_idle_ns);
|
||||
d.set_mult(data.mult);
|
||||
d.set_name(data.name);
|
||||
d.set_rating(data.rating);
|
||||
d.set_shift(data.shift);
|
||||
d.watchdog_last = data.watchdog_last;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/mach_timer.h?fi=mach_prepare_counter
|
||||
#[allow(dead_code)]
|
||||
pub const CALIBRATE_TIME_MSEC: u64 = 30;
|
||||
pub const CALIBRATE_LATCH: u64 = (PIT_TICK_RATE * CALIBRATE_TIME_MSEC + 1000 / 2) / 1000;
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn mach_prepare_counter() {
|
||||
unsafe {
|
||||
// 将Gate位设置为高电平,从而禁用扬声器
|
||||
CurrentPortIOArch::out8(0x61, (CurrentPortIOArch::in8(0x61) & !0x02) | 0x01);
|
||||
|
||||
// 针对计数器/定时器控制器的通道2进行配置,设置为模式0,二进制计数
|
||||
CurrentPortIOArch::out8(0x43, 0xb0);
|
||||
CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH & 0xff) as u8);
|
||||
CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH >> 8) as u8);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn mach_countup(count: &mut u32) {
|
||||
let mut tmp: u32 = 0;
|
||||
loop {
|
||||
tmp += 1;
|
||||
if (unsafe { CurrentPortIOArch::in8(0x61) } & 0x20) != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*count = tmp;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
const PMTMR_EXPECTED_RATE: u64 =
|
||||
(CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (PIT_TICK_RATE >> 10);
|
||||
|
||||
/// # 验证ACPI PM Timer的运行速率是否在预期范围内(在x86_64架构以外的情况下验证)
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - i32:如果为0则表示在预期范围内,否则不在
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
fn verify_pmtmr_rate() -> bool {
|
||||
let mut count: u32 = 0;
|
||||
|
||||
mach_prepare_counter();
|
||||
let value1 = clocksource_acpi_pm().read().data();
|
||||
mach_countup(&mut count);
|
||||
let value2 = clocksource_acpi_pm().read().data();
|
||||
let delta = (value2 - value1) & ACPI_PM_MASK;
|
||||
|
||||
if (delta < (PMTMR_EXPECTED_RATE * 19) / 20) || (delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
|
||||
kinfo!(
|
||||
"PM Timer running at invalid rate: {}",
|
||||
100 * delta / PMTMR_EXPECTED_RATE
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn verify_pmtmr_rate() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
const ACPI_PM_MONOTONIC_CHECKS: u32 = 10;
|
||||
const ACPI_PM_READ_CHECKS: u32 = 10000;
|
||||
|
||||
/// # 解析fadt
|
||||
fn find_acpi_pm_clock() -> Result<(), SystemError> {
|
||||
let fadt = acpi_manager()
|
||||
.tables()
|
||||
.unwrap()
|
||||
.find_table::<Fadt>()
|
||||
.expect("failed to find FADT table");
|
||||
let pm_timer_block = fadt.pm_timer_block().map_err(|_| SystemError::ENODEV)?;
|
||||
let pm_timer_block = pm_timer_block.ok_or(SystemError::ENODEV)?;
|
||||
let pmtmr_addr = pm_timer_block.address;
|
||||
unsafe {
|
||||
PMTMR_IO_PORT.store(pmtmr_addr as u32, Ordering::SeqCst);
|
||||
}
|
||||
kinfo!("apic_pmtmr I/O port: {}", unsafe {
|
||||
PMTMR_IO_PORT.load(Ordering::SeqCst)
|
||||
});
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// # 初始化ACPI PM Timer作为系统时钟源
|
||||
// #[unified_init(INITCALL_FS)]
|
||||
pub fn init_acpi_pm_clocksource() -> Result<(), SystemError> {
|
||||
let acpi_pm = Acpipm::new();
|
||||
unsafe {
|
||||
CLOCKSOURCE_ACPI_PM = Some(acpi_pm);
|
||||
}
|
||||
|
||||
// 解析fadt
|
||||
find_acpi_pm_clock()?;
|
||||
|
||||
// 检查pmtmr_io_port是否被设置
|
||||
if unsafe { PMTMR_IO_PORT.load(Ordering::SeqCst) } == 0 {
|
||||
return Err(SystemError::ENODEV);
|
||||
}
|
||||
|
||||
// 验证ACPI PM Timer作为时钟源的稳定性和一致性
|
||||
for j in 0..ACPI_PM_MONOTONIC_CHECKS {
|
||||
let mut cnt = 100 * j;
|
||||
while cnt > 0 {
|
||||
cnt -= 1;
|
||||
}
|
||||
|
||||
let value1 = clocksource_acpi_pm().read().data();
|
||||
let mut i = 0;
|
||||
for _ in 0..ACPI_PM_READ_CHECKS {
|
||||
let value2 = clocksource_acpi_pm().read().data();
|
||||
if value2 == value1 {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if value2 > value1 {
|
||||
break;
|
||||
}
|
||||
if (value2 < value1) && (value2 < 0xfff) {
|
||||
break;
|
||||
}
|
||||
kinfo!("PM Timer had inconsistens results: {} {}", value1, value2);
|
||||
unsafe {
|
||||
PMTMR_IO_PORT.store(0, Ordering::SeqCst);
|
||||
}
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
if i == ACPI_PM_READ_CHECKS {
|
||||
kinfo!("PM Timer failed consistency check: {}", value1);
|
||||
unsafe {
|
||||
PMTMR_IO_PORT.store(0, Ordering::SeqCst);
|
||||
}
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查ACPI PM Timer的频率是否正确
|
||||
if !verify_pmtmr_rate() {
|
||||
unsafe {
|
||||
PMTMR_IO_PORT.store(0, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查TSC时钟源的监视器是否被禁用,如果被禁用则将时钟源的标志设置为CLOCK_SOURCE_MUST_VERIFY
|
||||
// 没有实现clocksource_selecet_watchdog函数,所以这里设置为false
|
||||
let tsc_clocksource_watchdog_disabled = false;
|
||||
if tsc_clocksource_watchdog_disabled {
|
||||
clocksource_acpi_pm().0.lock_irqsave().data.flags |=
|
||||
ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY;
|
||||
}
|
||||
|
||||
// 注册ACPI PM Timer
|
||||
let acpi_pmtmr = clocksource_acpi_pm() as Arc<dyn Clocksource>;
|
||||
match acpi_pmtmr.register(100, PMTMR_TICKS_PER_SEC as u32) {
|
||||
Ok(_) => {
|
||||
kinfo!("ACPI PM Timer registered as clocksource sccessfully");
|
||||
return Ok(());
|
||||
}
|
||||
Err(_) => {
|
||||
kinfo!("ACPI PM Timer init registered failed");
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,2 +1,4 @@
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub mod timer_riscv;
|
||||
|
||||
pub mod acpi_pm;
|
||||
|
@ -1069,7 +1069,7 @@ pub fn pci_init() {
|
||||
);
|
||||
}
|
||||
HeaderType::PciPciBridge if common_header.status & 0x10 != 0 => {
|
||||
kinfo!("Found pci-to-pci bridge device with class code ={} subclass={} status={:#x} cap_pointer={:#x}", common_header.class_code, common_header.subclass, common_header.status, box_pci_device.as_standard_device().unwrap().capabilities_pointer);
|
||||
kinfo!("Found pci-to-pci bridge device with class code ={} subclass={} status={:#x} cap_pointer={:#x}", common_header.class_code, common_header.subclass, common_header.status, box_pci_device.as_pci_to_pci_bridge_device().unwrap().capability_pointer);
|
||||
}
|
||||
HeaderType::PciPciBridge => {
|
||||
kinfo!(
|
||||
|
@ -433,7 +433,7 @@ impl CpuRunQueue {
|
||||
SchedPolicy::CFS => CompletelyFairScheduler::dequeue(self, pcb, flags),
|
||||
SchedPolicy::FIFO => todo!(),
|
||||
SchedPolicy::RT => todo!(),
|
||||
SchedPolicy::IDLE => todo!(),
|
||||
SchedPolicy::IDLE => IdleScheduler::dequeue(self, pcb, flags),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ use crate::{
|
||||
use super::{
|
||||
jiffies::clocksource_default_clock,
|
||||
timer::{clock, Timer, TimerFunction},
|
||||
NSEC_PER_SEC,
|
||||
NSEC_PER_SEC, NSEC_PER_USEC,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
@ -58,11 +58,16 @@ pub static mut FINISHED_BOOTING: AtomicBool = AtomicBool::new(false);
|
||||
/// Interval: 0.5sec Threshold: 0.0625s
|
||||
/// 系统节拍率
|
||||
pub const HZ: u64 = 250;
|
||||
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/clocksource.c#101
|
||||
/// watchdog检查间隔
|
||||
pub const WATCHDOG_INTERVAL: u64 = HZ >> 1;
|
||||
// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/clocksource.c#108
|
||||
/// 最大能接受的误差大小
|
||||
pub const WATCHDOG_THRESHOLD: u32 = NSEC_PER_SEC >> 4;
|
||||
|
||||
pub const MAX_SKEW_USEC: u64 = 125 * WATCHDOG_INTERVAL / HZ;
|
||||
pub const WATCHDOG_MAX_SKEW: u32 = MAX_SKEW_USEC as u32 * NSEC_PER_USEC;
|
||||
|
||||
// 时钟周期数
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct CycleNum(u64);
|
||||
@ -266,6 +271,7 @@ impl dyn Clocksource {
|
||||
let cs_data_guard = self.clocksource_data();
|
||||
|
||||
let mut max_cycles: u64;
|
||||
// 这里我有问题,不知道要不要修改,暂时不修改它
|
||||
max_cycles = (1 << (63 - (log2(cs_data_guard.mult) + 1))) as u64;
|
||||
max_cycles = max_cycles.min(cs_data_guard.mask.bits);
|
||||
let max_nsecs = clocksource_cyc2ns(
|
||||
@ -276,17 +282,95 @@ impl dyn Clocksource {
|
||||
return max_nsecs - (max_nsecs >> 5);
|
||||
}
|
||||
|
||||
/// # 计算时钟源的mult和shift,以便将一个时钟源的频率转换为另一个时钟源的频率
|
||||
fn clocks_calc_mult_shift(&self, from: u32, to: u32, maxsec: u32) -> (u32, u32) {
|
||||
let mut sftacc: u32 = 32;
|
||||
let mut sft = 1;
|
||||
|
||||
// 计算限制转换范围的shift
|
||||
let mut mult = (maxsec as u64 * from as u64) >> 32;
|
||||
while mult != 0 {
|
||||
mult >>= 1;
|
||||
sftacc -= 1;
|
||||
}
|
||||
|
||||
// 找到最佳的mult和shift
|
||||
for i in (1..=32).rev() {
|
||||
sft = i;
|
||||
mult = (to as u64) << sft;
|
||||
mult += from as u64 / 2;
|
||||
mult /= from as u64;
|
||||
if (mult >> sftacc) == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (mult as u32, sft);
|
||||
}
|
||||
|
||||
/// # 计算时钟源可以进行的最大调整量
|
||||
fn clocksource_max_adjustment(&self) -> u32 {
|
||||
let cs_data = self.clocksource_data();
|
||||
let ret = cs_data.mult as u64 * 11 / 100;
|
||||
|
||||
return ret as u32;
|
||||
}
|
||||
|
||||
/// # 更新时钟源频率,初始化mult/shift 和 max_idle_ns
|
||||
fn clocksource_update_freq_scale(&self, scale: u32, freq: u32) -> Result<(), SystemError> {
|
||||
let mut cs_data = self.clocksource_data();
|
||||
|
||||
if freq != 0 {
|
||||
let mut sec: u64 = cs_data.mask.bits();
|
||||
|
||||
sec /= freq as u64;
|
||||
sec /= scale as u64;
|
||||
if sec == 0 {
|
||||
sec = 1;
|
||||
} else if sec > 600 && cs_data.mask.bits() > u32::MAX as u64 {
|
||||
sec = 600;
|
||||
}
|
||||
|
||||
let (mult, shift) =
|
||||
self.clocks_calc_mult_shift(freq, NSEC_PER_SEC / scale, sec as u32 * scale);
|
||||
cs_data.set_mult(mult);
|
||||
cs_data.set_shift(shift);
|
||||
}
|
||||
|
||||
if scale != 0 && freq != 0 && cs_data.uncertainty_margin == 0 {
|
||||
cs_data.set_uncertainty_margin(NSEC_PER_SEC / (scale * freq));
|
||||
if cs_data.uncertainty_margin < 2 * WATCHDOG_MAX_SKEW {
|
||||
cs_data.set_uncertainty_margin(2 * WATCHDOG_MAX_SKEW);
|
||||
}
|
||||
} else if cs_data.uncertainty_margin == 0 {
|
||||
cs_data.set_uncertainty_margin(WATCHDOG_THRESHOLD);
|
||||
}
|
||||
|
||||
// 确保时钟源没有太大的mult值造成溢出
|
||||
cs_data.set_maxadj(self.clocksource_max_adjustment());
|
||||
|
||||
let ns = self.clocksource_max_deferment();
|
||||
cs_data.set_max_idle_ns(ns as u32);
|
||||
|
||||
self.update_clocksource_data(cs_data)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// # 注册时钟源
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - scale: 如果freq单位为0或hz,此值为1,如果为khz,此值为1000
|
||||
/// - freq: 时钟源的频率,jiffies注册时此值为0
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// * `Ok(0)` - 时钟源注册成功。
|
||||
/// * `Err(SystemError)` - 时钟源注册失败。
|
||||
pub fn register(&self) -> Result<i32, SystemError> {
|
||||
let ns = self.clocksource_max_deferment();
|
||||
let mut cs_data = self.clocksource_data();
|
||||
cs_data.max_idle_ns = ns as u32;
|
||||
self.update_clocksource_data(cs_data)?;
|
||||
pub fn register(&self, scale: u32, freq: u32) -> Result<(), SystemError> {
|
||||
self.clocksource_update_freq_scale(scale, freq)?;
|
||||
|
||||
// 将时钟源加入到时钟源队列中
|
||||
self.clocksource_enqueue();
|
||||
// 将时钟源加入到监视队列中
|
||||
@ -295,7 +379,7 @@ impl dyn Clocksource {
|
||||
// 选择一个最好的时钟源
|
||||
clocksource_select();
|
||||
kdebug!("clocksource_register successfully");
|
||||
return Ok(0);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// # 将时钟源插入时钟源队列
|
||||
@ -569,10 +653,15 @@ pub struct ClocksourceData {
|
||||
pub max_idle_ns: u32,
|
||||
pub flags: ClocksourceFlags,
|
||||
pub watchdog_last: CycleNum,
|
||||
// 用于描述时钟源的不确定性边界,时钟源读取的时间可能存在的不确定性和误差范围
|
||||
pub uncertainty_margin: u32,
|
||||
// 最大的时间调整量
|
||||
pub maxadj: u32,
|
||||
}
|
||||
|
||||
impl ClocksourceData {
|
||||
#[allow(dead_code)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
name: String,
|
||||
rating: i32,
|
||||
@ -581,6 +670,8 @@ impl ClocksourceData {
|
||||
shift: u32,
|
||||
max_idle_ns: u32,
|
||||
flags: ClocksourceFlags,
|
||||
uncertainty_margin: u32,
|
||||
maxadj: u32,
|
||||
) -> Self {
|
||||
let csd = ClocksourceData {
|
||||
name,
|
||||
@ -591,6 +682,8 @@ impl ClocksourceData {
|
||||
max_idle_ns,
|
||||
flags,
|
||||
watchdog_last: CycleNum(0),
|
||||
uncertainty_margin,
|
||||
maxadj,
|
||||
};
|
||||
return csd;
|
||||
}
|
||||
@ -624,6 +717,12 @@ impl ClocksourceData {
|
||||
pub fn insert_flags(&mut self, flags: ClocksourceFlags) {
|
||||
self.flags.insert(flags)
|
||||
}
|
||||
pub fn set_uncertainty_margin(&mut self, uncertainty_margin: u32) {
|
||||
self.uncertainty_margin = uncertainty_margin;
|
||||
}
|
||||
pub fn set_maxadj(&mut self, maxadj: u32) {
|
||||
self.maxadj = maxadj;
|
||||
}
|
||||
}
|
||||
|
||||
/// converts clocksource cycles to nanoseconds
|
||||
@ -733,6 +832,8 @@ pub fn clocksource_watchdog() -> Result<(), SystemError> {
|
||||
if cs_dev_nsec.abs_diff(wd_dev_nsec) > WATCHDOG_THRESHOLD.into() {
|
||||
// kdebug!("set_unstable");
|
||||
// 误差过大,标记为unstable
|
||||
kinfo!("cs_dev_nsec = {}", cs_dev_nsec);
|
||||
kinfo!("wd_dev_nsec = {}", wd_dev_nsec);
|
||||
cs.set_unstable((cs_dev_nsec - wd_dev_nsec).try_into().unwrap())?;
|
||||
continue;
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ impl ClocksourceJiffies {
|
||||
max_idle_ns: Default::default(),
|
||||
flags: ClocksourceFlags::new(0),
|
||||
watchdog_last: CycleNum::new(0),
|
||||
uncertainty_margin: 0,
|
||||
maxadj: 0,
|
||||
};
|
||||
let jiffies = Arc::new(ClocksourceJiffies(SpinLock::new(InnerJiffies {
|
||||
data,
|
||||
@ -92,7 +94,7 @@ pub fn clocksource_default_clock() -> Arc<ClocksourceJiffies> {
|
||||
pub fn jiffies_init() {
|
||||
//注册jiffies
|
||||
let jiffies = clocksource_default_clock() as Arc<dyn Clocksource>;
|
||||
match jiffies.register() {
|
||||
match jiffies.register(1, 0) {
|
||||
Ok(_) => {
|
||||
kinfo!("jiffies_init sccessfully");
|
||||
}
|
||||
|
@ -43,6 +43,9 @@ pub const NSEC_PER_SEC: u32 = 1000000000;
|
||||
#[allow(dead_code)]
|
||||
pub const FSEC_PER_SEC: u64 = 1000000000000000;
|
||||
|
||||
/// The clock frequency of the i8253/i8254 PIT
|
||||
pub const PIT_TICK_RATE: u64 = 1193182;
|
||||
|
||||
/// 表示时间的结构体,符合POSIX标准。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
#[repr(C)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user