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