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