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};
182eab6dd7S曾俊 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)]
read_pmtmr() -> u3228dd8e74efSMingtao 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)]
acpi_pm_read_verified() -> u3239dd8e74efSMingtao 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的当前值
acpi_pm_read() -> u6461dd8e74efSMingtao 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
clocksource_acpi_pm() -> Arc<Acpipm>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 {
new() -> Arc<Self>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),
91*af097f9fS黄铭涛 cs_last: CycleNum::new(0),
92dd8e74efSMingtao Huang uncertainty_margin: 0,
93dd8e74efSMingtao Huang maxadj: 0,
94*af097f9fS黄铭涛 cycle_last: CycleNum::new(0),
95dd8e74efSMingtao Huang };
96dd8e74efSMingtao Huang let acpi_pm = Arc::new(Acpipm(SpinLock::new(InnerAcpipm {
97dd8e74efSMingtao Huang data,
98dd8e74efSMingtao Huang self_reaf: Default::default(),
99dd8e74efSMingtao Huang })));
100dd8e74efSMingtao Huang acpi_pm.0.lock().self_reaf = Arc::downgrade(&acpi_pm);
101dd8e74efSMingtao Huang
102dd8e74efSMingtao Huang return acpi_pm;
103dd8e74efSMingtao Huang }
104dd8e74efSMingtao Huang }
105dd8e74efSMingtao Huang
106dd8e74efSMingtao Huang impl Clocksource for Acpipm {
read(&self) -> CycleNum107dd8e74efSMingtao Huang fn read(&self) -> CycleNum {
108dd8e74efSMingtao Huang return CycleNum::new(acpi_pm_read());
109dd8e74efSMingtao Huang }
110dd8e74efSMingtao Huang
clocksource_data(&self) -> ClocksourceData111dd8e74efSMingtao Huang fn clocksource_data(&self) -> ClocksourceData {
112dd8e74efSMingtao Huang let inner = self.0.lock_irqsave();
113dd8e74efSMingtao Huang return inner.data.clone();
114dd8e74efSMingtao Huang }
115dd8e74efSMingtao Huang
clocksource(&self) -> Arc<dyn Clocksource>116dd8e74efSMingtao Huang fn clocksource(&self) -> Arc<dyn Clocksource> {
117dd8e74efSMingtao Huang return self.0.lock_irqsave().self_reaf.upgrade().unwrap();
118dd8e74efSMingtao Huang }
119dd8e74efSMingtao Huang
update_clocksource_data(&self, data: ClocksourceData) -> Result<(), SystemError>120dd8e74efSMingtao Huang fn update_clocksource_data(&self, data: ClocksourceData) -> Result<(), SystemError> {
121dd8e74efSMingtao Huang let d = &mut self.0.lock_irqsave().data;
122dd8e74efSMingtao Huang d.set_name(data.name);
123dd8e74efSMingtao Huang d.set_rating(data.rating);
124*af097f9fS黄铭涛 d.set_mask(data.mask);
125*af097f9fS黄铭涛 d.set_mult(data.mult);
126dd8e74efSMingtao Huang d.set_shift(data.shift);
127*af097f9fS黄铭涛 d.set_max_idle_ns(data.max_idle_ns);
128*af097f9fS黄铭涛 d.set_flags(data.flags);
129dd8e74efSMingtao Huang d.watchdog_last = data.watchdog_last;
130*af097f9fS黄铭涛 d.cs_last = data.cs_last;
131*af097f9fS黄铭涛 d.set_uncertainty_margin(data.uncertainty_margin);
132*af097f9fS黄铭涛 d.set_maxadj(data.maxadj);
133*af097f9fS黄铭涛 d.cycle_last = data.cycle_last;
134dd8e74efSMingtao Huang return Ok(());
135dd8e74efSMingtao Huang }
136dd8e74efSMingtao Huang }
137dd8e74efSMingtao Huang
138dd8e74efSMingtao Huang // 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/include/asm/mach_timer.h?fi=mach_prepare_counter
139dd8e74efSMingtao Huang #[allow(dead_code)]
140dd8e74efSMingtao Huang pub const CALIBRATE_TIME_MSEC: u64 = 30;
141dd8e74efSMingtao Huang pub const CALIBRATE_LATCH: u64 = (PIT_TICK_RATE * CALIBRATE_TIME_MSEC + 1000 / 2) / 1000;
142dd8e74efSMingtao Huang
143dd8e74efSMingtao Huang #[inline(always)]
144dd8e74efSMingtao Huang #[allow(dead_code)]
mach_prepare_counter()145dd8e74efSMingtao Huang pub fn mach_prepare_counter() {
146dd8e74efSMingtao Huang unsafe {
147dd8e74efSMingtao Huang // 将Gate位设置为高电平,从而禁用扬声器
148dd8e74efSMingtao Huang CurrentPortIOArch::out8(0x61, (CurrentPortIOArch::in8(0x61) & !0x02) | 0x01);
149dd8e74efSMingtao Huang
150dd8e74efSMingtao Huang // 针对计数器/定时器控制器的通道2进行配置,设置为模式0,二进制计数
151dd8e74efSMingtao Huang CurrentPortIOArch::out8(0x43, 0xb0);
152dd8e74efSMingtao Huang CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH & 0xff) as u8);
153dd8e74efSMingtao Huang CurrentPortIOArch::out8(0x42, (CALIBRATE_LATCH >> 8) as u8);
154dd8e74efSMingtao Huang }
155dd8e74efSMingtao Huang }
156dd8e74efSMingtao Huang
157dd8e74efSMingtao Huang #[allow(dead_code)]
mach_countup(count: &mut u32)158dd8e74efSMingtao Huang pub fn mach_countup(count: &mut u32) {
159dd8e74efSMingtao Huang let mut tmp: u32 = 0;
160dd8e74efSMingtao Huang loop {
161dd8e74efSMingtao Huang tmp += 1;
162dd8e74efSMingtao Huang if (unsafe { CurrentPortIOArch::in8(0x61) } & 0x20) != 0 {
163dd8e74efSMingtao Huang break;
164dd8e74efSMingtao Huang }
165dd8e74efSMingtao Huang }
166dd8e74efSMingtao Huang *count = tmp;
167dd8e74efSMingtao Huang }
168dd8e74efSMingtao Huang
169dd8e74efSMingtao Huang #[allow(dead_code)]
170dd8e74efSMingtao Huang const PMTMR_EXPECTED_RATE: u64 =
171dd8e74efSMingtao Huang (CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (PIT_TICK_RATE >> 10);
172dd8e74efSMingtao Huang
173dd8e74efSMingtao Huang /// # 验证ACPI PM Timer的运行速率是否在预期范围内(在x86_64架构以外的情况下验证)
174dd8e74efSMingtao Huang ///
175dd8e74efSMingtao Huang /// ## 返回值
176dd8e74efSMingtao Huang /// - i32:如果为0则表示在预期范围内,否则不在
177dd8e74efSMingtao Huang #[cfg(not(target_arch = "x86_64"))]
178942cf26bSLoGin #[allow(dead_code)]
verify_pmtmr_rate() -> bool179dd8e74efSMingtao Huang fn verify_pmtmr_rate() -> bool {
1802eab6dd7S曾俊 use log::info;
1812eab6dd7S曾俊
182dd8e74efSMingtao Huang let mut count: u32 = 0;
183dd8e74efSMingtao Huang
184dd8e74efSMingtao Huang mach_prepare_counter();
185dd8e74efSMingtao Huang let value1 = clocksource_acpi_pm().read().data();
186dd8e74efSMingtao Huang mach_countup(&mut count);
187dd8e74efSMingtao Huang let value2 = clocksource_acpi_pm().read().data();
188dd8e74efSMingtao Huang let delta = (value2 - value1) & ACPI_PM_MASK;
189dd8e74efSMingtao Huang
190dd8e74efSMingtao Huang if (delta < (PMTMR_EXPECTED_RATE * 19) / 20) || (delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
1912eab6dd7S曾俊 info!(
192dd8e74efSMingtao Huang "PM Timer running at invalid rate: {}",
193dd8e74efSMingtao Huang 100 * delta / PMTMR_EXPECTED_RATE
194dd8e74efSMingtao Huang );
195dd8e74efSMingtao Huang return false;
196dd8e74efSMingtao Huang }
197dd8e74efSMingtao Huang
198dd8e74efSMingtao Huang return true;
199dd8e74efSMingtao Huang }
200dd8e74efSMingtao Huang #[cfg(target_arch = "x86_64")]
verify_pmtmr_rate() -> bool201dd8e74efSMingtao Huang fn verify_pmtmr_rate() -> bool {
202dd8e74efSMingtao Huang return true;
203dd8e74efSMingtao Huang }
204dd8e74efSMingtao Huang
205dd8e74efSMingtao Huang const ACPI_PM_MONOTONIC_CHECKS: u32 = 10;
206dd8e74efSMingtao Huang const ACPI_PM_READ_CHECKS: u32 = 10000;
207dd8e74efSMingtao Huang
208dd8e74efSMingtao Huang /// # 解析fadt
find_acpi_pm_clock() -> Result<(), SystemError>209dd8e74efSMingtao Huang fn find_acpi_pm_clock() -> Result<(), SystemError> {
210dd8e74efSMingtao Huang let fadt = acpi_manager()
211dd8e74efSMingtao Huang .tables()
212dd8e74efSMingtao Huang .unwrap()
213dd8e74efSMingtao Huang .find_table::<Fadt>()
214dd8e74efSMingtao Huang .expect("failed to find FADT table");
215dd8e74efSMingtao Huang let pm_timer_block = fadt.pm_timer_block().map_err(|_| SystemError::ENODEV)?;
216dd8e74efSMingtao Huang let pm_timer_block = pm_timer_block.ok_or(SystemError::ENODEV)?;
217dd8e74efSMingtao Huang let pmtmr_addr = pm_timer_block.address;
21892deae63SLoGin
219dd8e74efSMingtao Huang PMTMR_IO_PORT.store(pmtmr_addr as u32, Ordering::SeqCst);
22092deae63SLoGin
2212eab6dd7S曾俊 info!(
22292deae63SLoGin "apic_pmtmr I/O port: {}",
223dd8e74efSMingtao Huang PMTMR_IO_PORT.load(Ordering::SeqCst)
22492deae63SLoGin );
225dd8e74efSMingtao Huang
226dd8e74efSMingtao Huang return Ok(());
227dd8e74efSMingtao Huang }
228dd8e74efSMingtao Huang
229dd8e74efSMingtao Huang /// # 初始化ACPI PM Timer作为系统时钟源
230dd8e74efSMingtao Huang // #[unified_init(INITCALL_FS)]
231942cf26bSLoGin #[inline(never)]
232942cf26bSLoGin #[allow(dead_code)]
init_acpi_pm_clocksource() -> Result<(), SystemError>233dd8e74efSMingtao Huang pub fn init_acpi_pm_clocksource() -> Result<(), SystemError> {
234dd8e74efSMingtao Huang let acpi_pm = Acpipm::new();
235dd8e74efSMingtao Huang
236dd8e74efSMingtao Huang // 解析fadt
237dd8e74efSMingtao Huang find_acpi_pm_clock()?;
238dd8e74efSMingtao Huang
239dd8e74efSMingtao Huang // 检查pmtmr_io_port是否被设置
24092deae63SLoGin if PMTMR_IO_PORT.load(Ordering::SeqCst) == 0 {
241dd8e74efSMingtao Huang return Err(SystemError::ENODEV);
242dd8e74efSMingtao Huang }
243dd8e74efSMingtao Huang
24492deae63SLoGin unsafe {
24592deae63SLoGin CLOCKSOURCE_ACPI_PM = Some(acpi_pm);
24692deae63SLoGin }
24792deae63SLoGin
248dd8e74efSMingtao Huang // 验证ACPI PM Timer作为时钟源的稳定性和一致性
249dd8e74efSMingtao Huang for j in 0..ACPI_PM_MONOTONIC_CHECKS {
250dd8e74efSMingtao Huang let mut cnt = 100 * j;
251dd8e74efSMingtao Huang while cnt > 0 {
252dd8e74efSMingtao Huang cnt -= 1;
253dd8e74efSMingtao Huang }
254dd8e74efSMingtao Huang
255dd8e74efSMingtao Huang let value1 = clocksource_acpi_pm().read().data();
256dd8e74efSMingtao Huang let mut i = 0;
257dd8e74efSMingtao Huang for _ in 0..ACPI_PM_READ_CHECKS {
258dd8e74efSMingtao Huang let value2 = clocksource_acpi_pm().read().data();
259dd8e74efSMingtao Huang if value2 == value1 {
260dd8e74efSMingtao Huang i += 1;
261dd8e74efSMingtao Huang continue;
262dd8e74efSMingtao Huang }
263dd8e74efSMingtao Huang if value2 > value1 {
264dd8e74efSMingtao Huang break;
265dd8e74efSMingtao Huang }
266dd8e74efSMingtao Huang if (value2 < value1) && (value2 < 0xfff) {
267dd8e74efSMingtao Huang break;
268dd8e74efSMingtao Huang }
2692eab6dd7S曾俊 info!("PM Timer had inconsistens results: {} {}", value1, value2);
27092deae63SLoGin
271dd8e74efSMingtao Huang PMTMR_IO_PORT.store(0, Ordering::SeqCst);
27292deae63SLoGin
273dd8e74efSMingtao Huang return Err(SystemError::EINVAL);
274dd8e74efSMingtao Huang }
275dd8e74efSMingtao Huang if i == ACPI_PM_READ_CHECKS {
2762eab6dd7S曾俊 info!("PM Timer failed consistency check: {}", value1);
27792deae63SLoGin
278dd8e74efSMingtao Huang PMTMR_IO_PORT.store(0, Ordering::SeqCst);
27992deae63SLoGin
280dd8e74efSMingtao Huang return Err(SystemError::EINVAL);
281dd8e74efSMingtao Huang }
282dd8e74efSMingtao Huang }
283dd8e74efSMingtao Huang
284dd8e74efSMingtao Huang // 检查ACPI PM Timer的频率是否正确
285dd8e74efSMingtao Huang if !verify_pmtmr_rate() {
286dd8e74efSMingtao Huang PMTMR_IO_PORT.store(0, Ordering::SeqCst);
287dd8e74efSMingtao Huang }
288dd8e74efSMingtao Huang
289dd8e74efSMingtao Huang // 检查TSC时钟源的监视器是否被禁用,如果被禁用则将时钟源的标志设置为CLOCK_SOURCE_MUST_VERIFY
290*af097f9fS黄铭涛 // 是因为jiffies精度小于acpi pm,所以不需要被jiffies监视
291dd8e74efSMingtao Huang let tsc_clocksource_watchdog_disabled = false;
292dd8e74efSMingtao Huang if tsc_clocksource_watchdog_disabled {
293dd8e74efSMingtao Huang clocksource_acpi_pm().0.lock_irqsave().data.flags |=
294dd8e74efSMingtao Huang ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY;
295dd8e74efSMingtao Huang }
296dd8e74efSMingtao Huang
297dd8e74efSMingtao Huang // 注册ACPI PM Timer
298dd8e74efSMingtao Huang let acpi_pmtmr = clocksource_acpi_pm() as Arc<dyn Clocksource>;
299*af097f9fS黄铭涛 match acpi_pmtmr.register(1, PMTMR_TICKS_PER_SEC as u32) {
300dd8e74efSMingtao Huang Ok(_) => {
3012eab6dd7S曾俊 info!("ACPI PM Timer registered as clocksource sccessfully");
302dd8e74efSMingtao Huang return Ok(());
303dd8e74efSMingtao Huang }
304dd8e74efSMingtao Huang Err(_) => {
3052eab6dd7S曾俊 info!("ACPI PM Timer init registered failed");
306dd8e74efSMingtao Huang return Err(SystemError::ENOSYS);
307dd8e74efSMingtao Huang }
308dd8e74efSMingtao Huang };
309dd8e74efSMingtao Huang }
310