1dd8e74efSMingtao Huang use crate::{ 2dd8e74efSMingtao Huang alloc::string::ToString, 3dd8e74efSMingtao Huang arch::{io::PortIOArch, CurrentPortIOArch}, 4dd8e74efSMingtao Huang driver::acpi::{ 5dd8e74efSMingtao Huang acpi_manager, 6dd8e74efSMingtao Huang pmtmr::{ACPI_PM_MASK, PMTMR_TICKS_PER_SEC}, 7dd8e74efSMingtao Huang }, 8dd8e74efSMingtao Huang libs::spinlock::SpinLock, 9dd8e74efSMingtao Huang time::{ 10dd8e74efSMingtao Huang clocksource::{Clocksource, ClocksourceData, ClocksourceFlags, ClocksourceMask, CycleNum}, 11dd8e74efSMingtao Huang PIT_TICK_RATE, 12dd8e74efSMingtao Huang }, 13dd8e74efSMingtao Huang }; 14dd8e74efSMingtao Huang use acpi::fadt::Fadt; 15dd8e74efSMingtao Huang use alloc::sync::{Arc, Weak}; 16dd8e74efSMingtao Huang use core::intrinsics::unlikely; 17dd8e74efSMingtao Huang use core::sync::atomic::{AtomicU32, Ordering}; 18*2eab6dd7S曾俊 use log::info; 19dd8e74efSMingtao Huang use system_error::SystemError; 20dd8e74efSMingtao Huang 21dd8e74efSMingtao Huang // 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/clocksource/acpi_pm.c 22dd8e74efSMingtao Huang 23dd8e74efSMingtao Huang /// acpi_pmtmr所在的I/O端口 2492deae63SLoGin pub static PMTMR_IO_PORT: AtomicU32 = AtomicU32::new(0); 25dd8e74efSMingtao Huang 26dd8e74efSMingtao Huang /// # 读取acpi_pmtmr当前值,并对齐进行掩码操作 27dd8e74efSMingtao Huang #[inline(always)] 28dd8e74efSMingtao Huang fn read_pmtmr() -> u32 { 29dd8e74efSMingtao Huang return unsafe { CurrentPortIOArch::in32(PMTMR_IO_PORT.load(Ordering::SeqCst) as u16) } 30dd8e74efSMingtao Huang & ACPI_PM_MASK as u32; 31dd8e74efSMingtao Huang } 32dd8e74efSMingtao Huang 33dd8e74efSMingtao Huang //参考: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/clocksource/acpi_pm.c#41 34dd8e74efSMingtao Huang /// # 读取acpi_pmtmr的值,并进行多次读取以保证获取正确的值 35dd8e74efSMingtao Huang /// 36dd8e74efSMingtao Huang /// ## 返回值 37dd8e74efSMingtao Huang /// - u32: 读取到的acpi_pmtmr值 38942cf26bSLoGin #[allow(dead_code)] 39dd8e74efSMingtao Huang pub fn acpi_pm_read_verified() -> u32 { 40dd8e74efSMingtao Huang let mut v2: u32; 41dd8e74efSMingtao Huang 42dd8e74efSMingtao Huang // 因为某些损坏芯片组(如ICH4、PIIX4和PIIX4E)可能导致APCI PM时钟源未锁存 43dd8e74efSMingtao Huang // 因此需要多次读取以保证获取正确的值 44dd8e74efSMingtao Huang loop { 45dd8e74efSMingtao Huang let v1 = read_pmtmr(); 46dd8e74efSMingtao Huang v2 = read_pmtmr(); 47dd8e74efSMingtao Huang let v3 = read_pmtmr(); 48dd8e74efSMingtao Huang 49dd8e74efSMingtao Huang if !(unlikely((v2 > v3 || v1 < v3) && v1 > v2 || v1 < v3 && v2 > v3)) { 50dd8e74efSMingtao Huang break; 51dd8e74efSMingtao Huang } 52dd8e74efSMingtao Huang } 53dd8e74efSMingtao Huang 54dd8e74efSMingtao Huang return v2; 55dd8e74efSMingtao Huang } 56dd8e74efSMingtao Huang 57dd8e74efSMingtao Huang /// # 作为时钟源的读取函数 58dd8e74efSMingtao Huang /// 59dd8e74efSMingtao Huang /// ## 返回值 60dd8e74efSMingtao Huang /// - u64: acpi_pmtmr的当前值 61dd8e74efSMingtao Huang fn acpi_pm_read() -> u64 { 62dd8e74efSMingtao Huang return read_pmtmr() as u64; 63dd8e74efSMingtao Huang } 64dd8e74efSMingtao Huang 65dd8e74efSMingtao Huang pub static mut CLOCKSOURCE_ACPI_PM: Option<Arc<Acpipm>> = None; 66dd8e74efSMingtao Huang 67dd8e74efSMingtao Huang pub fn clocksource_acpi_pm() -> Arc<Acpipm> { 68dd8e74efSMingtao Huang return unsafe { CLOCKSOURCE_ACPI_PM.as_ref().unwrap().clone() }; 69dd8e74efSMingtao Huang } 70dd8e74efSMingtao Huang 71dd8e74efSMingtao Huang #[derive(Debug)] 72dd8e74efSMingtao Huang pub struct Acpipm(SpinLock<InnerAcpipm>); 73dd8e74efSMingtao Huang 74dd8e74efSMingtao Huang #[derive(Debug)] 75dd8e74efSMingtao Huang struct InnerAcpipm { 76dd8e74efSMingtao Huang data: ClocksourceData, 77dd8e74efSMingtao Huang self_reaf: Weak<Acpipm>, 78dd8e74efSMingtao Huang } 79dd8e74efSMingtao Huang 80dd8e74efSMingtao Huang impl Acpipm { 81dd8e74efSMingtao Huang pub fn new() -> Arc<Self> { 82dd8e74efSMingtao Huang let data = ClocksourceData { 83dd8e74efSMingtao Huang name: "acpi_pm".to_string(), 84dd8e74efSMingtao Huang rating: 200, 85dd8e74efSMingtao Huang mask: ClocksourceMask::new(ACPI_PM_MASK), 86dd8e74efSMingtao Huang mult: 0, 87dd8e74efSMingtao Huang shift: 0, 88dd8e74efSMingtao Huang max_idle_ns: Default::default(), 89dd8e74efSMingtao Huang flags: ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS, 90dd8e74efSMingtao Huang watchdog_last: CycleNum::new(0), 91dd8e74efSMingtao Huang uncertainty_margin: 0, 92dd8e74efSMingtao Huang maxadj: 0, 93dd8e74efSMingtao Huang }; 94dd8e74efSMingtao Huang let acpi_pm = Arc::new(Acpipm(SpinLock::new(InnerAcpipm { 95dd8e74efSMingtao Huang data, 96dd8e74efSMingtao Huang self_reaf: Default::default(), 97dd8e74efSMingtao Huang }))); 98dd8e74efSMingtao Huang acpi_pm.0.lock().self_reaf = Arc::downgrade(&acpi_pm); 99dd8e74efSMingtao Huang 100dd8e74efSMingtao Huang return acpi_pm; 101dd8e74efSMingtao Huang } 102dd8e74efSMingtao Huang } 103dd8e74efSMingtao Huang 104dd8e74efSMingtao Huang impl Clocksource for Acpipm { 105dd8e74efSMingtao Huang fn read(&self) -> CycleNum { 106dd8e74efSMingtao Huang return CycleNum::new(acpi_pm_read()); 107dd8e74efSMingtao Huang } 108dd8e74efSMingtao Huang 109dd8e74efSMingtao Huang fn clocksource_data(&self) -> ClocksourceData { 110dd8e74efSMingtao Huang let inner = self.0.lock_irqsave(); 111dd8e74efSMingtao Huang return inner.data.clone(); 112dd8e74efSMingtao Huang } 113dd8e74efSMingtao Huang 114dd8e74efSMingtao Huang fn clocksource(&self) -> Arc<dyn Clocksource> { 115dd8e74efSMingtao Huang return self.0.lock_irqsave().self_reaf.upgrade().unwrap(); 116dd8e74efSMingtao Huang } 117dd8e74efSMingtao Huang 118dd8e74efSMingtao Huang fn update_clocksource_data(&self, data: ClocksourceData) -> Result<(), SystemError> { 119dd8e74efSMingtao Huang let d = &mut self.0.lock_irqsave().data; 120dd8e74efSMingtao Huang d.set_flags(data.flags); 121dd8e74efSMingtao Huang d.set_mask(data.mask); 122dd8e74efSMingtao Huang d.set_max_idle_ns(data.max_idle_ns); 123dd8e74efSMingtao Huang d.set_mult(data.mult); 124dd8e74efSMingtao Huang d.set_name(data.name); 125dd8e74efSMingtao Huang d.set_rating(data.rating); 126dd8e74efSMingtao Huang d.set_shift(data.shift); 127dd8e74efSMingtao Huang d.watchdog_last = data.watchdog_last; 128dd8e74efSMingtao Huang return Ok(()); 129dd8e74efSMingtao Huang } 130dd8e74efSMingtao Huang } 131dd8e74efSMingtao Huang 132dd8e74efSMingtao Huang // 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/mach_timer.h?fi=mach_prepare_counter 133dd8e74efSMingtao Huang #[allow(dead_code)] 134dd8e74efSMingtao Huang pub const CALIBRATE_TIME_MSEC: u64 = 30; 135dd8e74efSMingtao Huang pub const CALIBRATE_LATCH: u64 = (PIT_TICK_RATE * CALIBRATE_TIME_MSEC + 1000 / 2) / 1000; 136dd8e74efSMingtao Huang 137dd8e74efSMingtao Huang #[inline(always)] 138dd8e74efSMingtao Huang #[allow(dead_code)] 139dd8e74efSMingtao Huang pub fn mach_prepare_counter() { 140dd8e74efSMingtao Huang unsafe { 141dd8e74efSMingtao Huang // 将Gate位设置为高电平,从而禁用扬声器 142dd8e74efSMingtao Huang CurrentPortIOArch::out8(0x61, (CurrentPortIOArch::in8(0x61) & !0x02) | 0x01); 143dd8e74efSMingtao Huang 144dd8e74efSMingtao Huang // 针对计数器/定时器控制器的通道2进行配置,设置为模式0,二进制计数 145dd8e74efSMingtao Huang CurrentPortIOArch::out8(0x43, 0xb0); 146dd8e74efSMingtao Huang CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH & 0xff) as u8); 147dd8e74efSMingtao Huang CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH >> 8) as u8); 148dd8e74efSMingtao Huang } 149dd8e74efSMingtao Huang } 150dd8e74efSMingtao Huang 151dd8e74efSMingtao Huang #[allow(dead_code)] 152dd8e74efSMingtao Huang pub fn mach_countup(count: &mut u32) { 153dd8e74efSMingtao Huang let mut tmp: u32 = 0; 154dd8e74efSMingtao Huang loop { 155dd8e74efSMingtao Huang tmp += 1; 156dd8e74efSMingtao Huang if (unsafe { CurrentPortIOArch::in8(0x61) } & 0x20) != 0 { 157dd8e74efSMingtao Huang break; 158dd8e74efSMingtao Huang } 159dd8e74efSMingtao Huang } 160dd8e74efSMingtao Huang *count = tmp; 161dd8e74efSMingtao Huang } 162dd8e74efSMingtao Huang 163dd8e74efSMingtao Huang #[allow(dead_code)] 164dd8e74efSMingtao Huang const PMTMR_EXPECTED_RATE: u64 = 165dd8e74efSMingtao Huang (CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (PIT_TICK_RATE >> 10); 166dd8e74efSMingtao Huang 167dd8e74efSMingtao Huang /// # 验证ACPI PM Timer的运行速率是否在预期范围内(在x86_64架构以外的情况下验证) 168dd8e74efSMingtao Huang /// 169dd8e74efSMingtao Huang /// ## 返回值 170dd8e74efSMingtao Huang /// - i32:如果为0则表示在预期范围内,否则不在 171dd8e74efSMingtao Huang #[cfg(not(target_arch = "x86_64"))] 172942cf26bSLoGin #[allow(dead_code)] 173dd8e74efSMingtao Huang fn verify_pmtmr_rate() -> bool { 174*2eab6dd7S曾俊 use log::info; 175*2eab6dd7S曾俊 176dd8e74efSMingtao Huang let mut count: u32 = 0; 177dd8e74efSMingtao Huang 178dd8e74efSMingtao Huang mach_prepare_counter(); 179dd8e74efSMingtao Huang let value1 = clocksource_acpi_pm().read().data(); 180dd8e74efSMingtao Huang mach_countup(&mut count); 181dd8e74efSMingtao Huang let value2 = clocksource_acpi_pm().read().data(); 182dd8e74efSMingtao Huang let delta = (value2 - value1) & ACPI_PM_MASK; 183dd8e74efSMingtao Huang 184dd8e74efSMingtao Huang if (delta < (PMTMR_EXPECTED_RATE * 19) / 20) || (delta > (PMTMR_EXPECTED_RATE * 21) / 20) { 185*2eab6dd7S曾俊 info!( 186dd8e74efSMingtao Huang "PM Timer running at invalid rate: {}", 187dd8e74efSMingtao Huang 100 * delta / PMTMR_EXPECTED_RATE 188dd8e74efSMingtao Huang ); 189dd8e74efSMingtao Huang return false; 190dd8e74efSMingtao Huang } 191dd8e74efSMingtao Huang 192dd8e74efSMingtao Huang return true; 193dd8e74efSMingtao Huang } 194dd8e74efSMingtao Huang #[cfg(target_arch = "x86_64")] 195dd8e74efSMingtao Huang fn verify_pmtmr_rate() -> bool { 196dd8e74efSMingtao Huang return true; 197dd8e74efSMingtao Huang } 198dd8e74efSMingtao Huang 199dd8e74efSMingtao Huang const ACPI_PM_MONOTONIC_CHECKS: u32 = 10; 200dd8e74efSMingtao Huang const ACPI_PM_READ_CHECKS: u32 = 10000; 201dd8e74efSMingtao Huang 202dd8e74efSMingtao Huang /// # 解析fadt 203dd8e74efSMingtao Huang fn find_acpi_pm_clock() -> Result<(), SystemError> { 204dd8e74efSMingtao Huang let fadt = acpi_manager() 205dd8e74efSMingtao Huang .tables() 206dd8e74efSMingtao Huang .unwrap() 207dd8e74efSMingtao Huang .find_table::<Fadt>() 208dd8e74efSMingtao Huang .expect("failed to find FADT table"); 209dd8e74efSMingtao Huang let pm_timer_block = fadt.pm_timer_block().map_err(|_| SystemError::ENODEV)?; 210dd8e74efSMingtao Huang let pm_timer_block = pm_timer_block.ok_or(SystemError::ENODEV)?; 211dd8e74efSMingtao Huang let pmtmr_addr = pm_timer_block.address; 21292deae63SLoGin 213dd8e74efSMingtao Huang PMTMR_IO_PORT.store(pmtmr_addr as u32, Ordering::SeqCst); 21492deae63SLoGin 215*2eab6dd7S曾俊 info!( 21692deae63SLoGin "apic_pmtmr I/O port: {}", 217dd8e74efSMingtao Huang PMTMR_IO_PORT.load(Ordering::SeqCst) 21892deae63SLoGin ); 219dd8e74efSMingtao Huang 220dd8e74efSMingtao Huang return Ok(()); 221dd8e74efSMingtao Huang } 222dd8e74efSMingtao Huang 223dd8e74efSMingtao Huang /// # 初始化ACPI PM Timer作为系统时钟源 224dd8e74efSMingtao Huang // #[unified_init(INITCALL_FS)] 225942cf26bSLoGin #[inline(never)] 226942cf26bSLoGin #[allow(dead_code)] 227dd8e74efSMingtao Huang pub fn init_acpi_pm_clocksource() -> Result<(), SystemError> { 228dd8e74efSMingtao Huang let acpi_pm = Acpipm::new(); 229dd8e74efSMingtao Huang 230dd8e74efSMingtao Huang // 解析fadt 231dd8e74efSMingtao Huang find_acpi_pm_clock()?; 232dd8e74efSMingtao Huang 233dd8e74efSMingtao Huang // 检查pmtmr_io_port是否被设置 23492deae63SLoGin if PMTMR_IO_PORT.load(Ordering::SeqCst) == 0 { 235dd8e74efSMingtao Huang return Err(SystemError::ENODEV); 236dd8e74efSMingtao Huang } 237dd8e74efSMingtao Huang 23892deae63SLoGin unsafe { 23992deae63SLoGin CLOCKSOURCE_ACPI_PM = Some(acpi_pm); 24092deae63SLoGin } 24192deae63SLoGin 242dd8e74efSMingtao Huang // 验证ACPI PM Timer作为时钟源的稳定性和一致性 243dd8e74efSMingtao Huang for j in 0..ACPI_PM_MONOTONIC_CHECKS { 244dd8e74efSMingtao Huang let mut cnt = 100 * j; 245dd8e74efSMingtao Huang while cnt > 0 { 246dd8e74efSMingtao Huang cnt -= 1; 247dd8e74efSMingtao Huang } 248dd8e74efSMingtao Huang 249dd8e74efSMingtao Huang let value1 = clocksource_acpi_pm().read().data(); 250dd8e74efSMingtao Huang let mut i = 0; 251dd8e74efSMingtao Huang for _ in 0..ACPI_PM_READ_CHECKS { 252dd8e74efSMingtao Huang let value2 = clocksource_acpi_pm().read().data(); 253dd8e74efSMingtao Huang if value2 == value1 { 254dd8e74efSMingtao Huang i += 1; 255dd8e74efSMingtao Huang continue; 256dd8e74efSMingtao Huang } 257dd8e74efSMingtao Huang if value2 > value1 { 258dd8e74efSMingtao Huang break; 259dd8e74efSMingtao Huang } 260dd8e74efSMingtao Huang if (value2 < value1) && (value2 < 0xfff) { 261dd8e74efSMingtao Huang break; 262dd8e74efSMingtao Huang } 263*2eab6dd7S曾俊 info!("PM Timer had inconsistens results: {} {}", value1, value2); 26492deae63SLoGin 265dd8e74efSMingtao Huang PMTMR_IO_PORT.store(0, Ordering::SeqCst); 26692deae63SLoGin 267dd8e74efSMingtao Huang return Err(SystemError::EINVAL); 268dd8e74efSMingtao Huang } 269dd8e74efSMingtao Huang if i == ACPI_PM_READ_CHECKS { 270*2eab6dd7S曾俊 info!("PM Timer failed consistency check: {}", value1); 27192deae63SLoGin 272dd8e74efSMingtao Huang PMTMR_IO_PORT.store(0, Ordering::SeqCst); 27392deae63SLoGin 274dd8e74efSMingtao Huang return Err(SystemError::EINVAL); 275dd8e74efSMingtao Huang } 276dd8e74efSMingtao Huang } 277dd8e74efSMingtao Huang 278dd8e74efSMingtao Huang // 检查ACPI PM Timer的频率是否正确 279dd8e74efSMingtao Huang if !verify_pmtmr_rate() { 280dd8e74efSMingtao Huang PMTMR_IO_PORT.store(0, Ordering::SeqCst); 281dd8e74efSMingtao Huang } 282dd8e74efSMingtao Huang 283dd8e74efSMingtao Huang // 检查TSC时钟源的监视器是否被禁用,如果被禁用则将时钟源的标志设置为CLOCK_SOURCE_MUST_VERIFY 284dd8e74efSMingtao Huang // 没有实现clocksource_selecet_watchdog函数,所以这里设置为false 285dd8e74efSMingtao Huang let tsc_clocksource_watchdog_disabled = false; 286dd8e74efSMingtao Huang if tsc_clocksource_watchdog_disabled { 287dd8e74efSMingtao Huang clocksource_acpi_pm().0.lock_irqsave().data.flags |= 288dd8e74efSMingtao Huang ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY; 289dd8e74efSMingtao Huang } 290dd8e74efSMingtao Huang 291dd8e74efSMingtao Huang // 注册ACPI PM Timer 292dd8e74efSMingtao Huang let acpi_pmtmr = clocksource_acpi_pm() as Arc<dyn Clocksource>; 293dd8e74efSMingtao Huang match acpi_pmtmr.register(100, PMTMR_TICKS_PER_SEC as u32) { 294dd8e74efSMingtao Huang Ok(_) => { 295*2eab6dd7S曾俊 info!("ACPI PM Timer registered as clocksource sccessfully"); 296dd8e74efSMingtao Huang return Ok(()); 297dd8e74efSMingtao Huang } 298dd8e74efSMingtao Huang Err(_) => { 299*2eab6dd7S曾俊 info!("ACPI PM Timer init registered failed"); 300dd8e74efSMingtao Huang return Err(SystemError::ENOSYS); 301dd8e74efSMingtao Huang } 302dd8e74efSMingtao Huang }; 303dd8e74efSMingtao Huang } 304