From cedd85556c28cc77929d3ed9476298fa68e89d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 5 Nov 2022 22:17:51 +0100 Subject: [PATCH] kernel/x86: init the tsc frequency and clock speed from MSR when available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit only for AMD newer CPUs. tested on R5300U Change-Id: I44be2efca37b1738a759a15140e5fd8d3b5ac7b0 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5804 Reviewed-by: Jérôme Duval --- headers/private/kernel/arch/x86/arch_cpu.h | 8 +++-- src/system/kernel/arch/x86/arch_cpu.cpp | 39 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 035cbeb301..70a8fc65e6 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -120,10 +120,14 @@ #define IA32_MSR_KERNEL_GS_BASE 0xc0000102 #define IA32_MSR_TSC_AUX 0xc0000103 -// K8 MSR registers +// AMD MSR registers +#define MSR_F10H_HWCR 0xc0010015 +#define HWCR_TSCFREQSEL (1 << 24) #define K8_MSR_IPM 0xc0010055 +#define MSR_F10H_PSTATEDEF(x) (0xc0010064 + (x)) +#define PSTATEDEF_EN (1ULL << 63) #define MSR_F10H_DE_CFG 0xc0011029 -#define DE_CFG_SERIALIZE_LFENCE (1 << 1) +#define DE_CFG_SERIALIZE_LFENCE (1 << 1) // Hardware P-States MSR registers §14.4.1 diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 87312d40cb..ec5665b661 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -1443,6 +1443,44 @@ init_tsc_with_cpuid(kernel_args* args, uint32* conversionFactor) } +static void +init_tsc_with_msr(kernel_args* args, uint32* conversionFactor) +{ + cpu_ent* cpuEnt = get_cpu_struct(); + if (cpuEnt->arch.vendor != VENDOR_AMD) + return; + uint32 family = cpuEnt->arch.family + cpuEnt->arch.extended_family; + if (family < 0x10) + return; + uint64 value = x86_read_msr(MSR_F10H_HWCR); + if ((value & HWCR_TSCFREQSEL) == 0) + return; + + value = x86_read_msr(MSR_F10H_PSTATEDEF(0)); + if ((value & PSTATEDEF_EN) == 0) + return; + if (family != 0x17 && family != 0x19) + return; + + uint64 khz = 200 * 1000; + uint32 denominator = (value >> 8) & 0x3f; + if (denominator < 0x8 || denominator > 0x2c) + return; + if (denominator > 0x1a && (denominator % 2) == 1) + return; + uint32 numerator = value & 0xff; + if (numerator < 0x10) + return; + + dprintf("CPU: using TSC frequency from MSR %" B_PRIu64 "\n", khz * numerator / denominator); + // compute for microseconds as follows (1000000 << 32) / (tsc freq in Hz), + // or (1000 << 32) / (tsc freq in kHz) + *conversionFactor = (1000ULL << 32) / (khz * numerator / denominator); + // overwrite the bootloader value + args->arch_args.system_time_cv_factor = *conversionFactor; +} + + static void init_tsc(kernel_args* args) { @@ -1451,6 +1489,7 @@ init_tsc(kernel_args* args) // try to find the TSC frequency with CPUID uint32 conversionFactor = args->arch_args.system_time_cv_factor; init_tsc_with_cpuid(args, &conversionFactor); + init_tsc_with_msr(args, &conversionFactor); uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000;