diff --git a/awkernel_lib/src/arch/x86_64/dvfs.rs b/awkernel_lib/src/arch/x86_64/dvfs.rs index 7352d1bc9..ed3251f52 100644 --- a/awkernel_lib/src/arch/x86_64/dvfs.rs +++ b/awkernel_lib/src/arch/x86_64/dvfs.rs @@ -13,14 +13,23 @@ use super::X86; mod hwpstate_intel; const MSR_PLATFORM_INFO: u32 = 0xCE; +const MSR_PLATFORM_INFO_MAX_OFFSET: u32 = 8; +const MSR_PLATFORM_INFO_MIN_OFFSET: u32 = 40; const IA32_PERF_MPERF: u32 = 0xE7; const IA32_PERF_APERF: u32 = 0xE8; const IA32_PERF_CTL: u32 = 0x199; const IA32_MISC_ENABLE: u32 = 0x1A0; +fn bus_freq_mhz() -> u64 { + match (__cpuid(0x16).ecx & 0xffff) as u64 { + 0 => 100, // Default to 100 MHz if bus frequency is not reported (old CPUs). + freq => freq, + } +} + impl Dvfs for X86 { /// Fix the frequency of the current CPU. - fn set_cpu_freq(freq_mhz: u64) -> Result<()> { + fn set_cpu_freq(freq: u64) -> Result<()> { unsafe { let mut misc_enable = Msr::new(IA32_MISC_ENABLE); let mut value = misc_enable.read(); @@ -31,9 +40,8 @@ impl Dvfs for X86 { misc_enable.write(value); } - let cpuid = __cpuid(0x16); - let bus_freq_mhz = (cpuid.ecx & 0xffff) as u64; - let target_pstate = ((freq_mhz / bus_freq_mhz) as u64) & 0xFFFF; + let bus_freq_mhz = bus_freq_mhz(); + let target_pstate = (freq / bus_freq_mhz / 1_000_000) & 0xFFFF; unsafe { let mut perf_ctl = Msr::new(IA32_PERF_CTL); let mut value = perf_ctl.read(); @@ -53,10 +61,21 @@ impl Dvfs for X86 { fn get_max_cpu_freq() -> Result { unsafe { let platform_info = Msr::new(MSR_PLATFORM_INFO); - let max_ratio = (platform_info.read() >> 8) & 0xFF; - let bus_freq_mhz = (__cpuid(0x16).ecx & 0xffff) as u64; + let max_ratio = (platform_info.read() >> MSR_PLATFORM_INFO_MAX_OFFSET) & 0xFF; + let bus_freq_mhz = bus_freq_mhz(); + + Ok(max_ratio * bus_freq_mhz * 1_000_000) + } + } + + /// Get the minimum frequency of the current CPU. + fn get_min_cpu_freq() -> Result { + unsafe { + let platform_info = Msr::new(MSR_PLATFORM_INFO); + let min_ratio = (platform_info.read() >> MSR_PLATFORM_INFO_MIN_OFFSET) & 0xFF; + let bus_freq_mhz = bus_freq_mhz(); - Ok(max_ratio * bus_freq_mhz) + Ok(min_ratio * bus_freq_mhz * 1_000_000) } } @@ -80,7 +99,9 @@ impl Dvfs for X86 { let mperf_delta = mperf.read(); let aperf_delta = aperf.read(); - Ok(aperf_delta * Self::get_max_cpu_freq().unwrap() / mperf_delta) + let max_cpu_freq_mhz = Self::get_max_cpu_freq()? / 1_000_000; + + Ok(aperf_delta * max_cpu_freq_mhz / mperf_delta * 1_000_000) } } }