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