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