xref: /DragonOS/kernel/src/driver/clocksource/acpi_pm.rs (revision 2eab6dd743e94a86a685f1f3c01e599adf86610a)
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