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