kernel/x86: init the tsc frequency and clock speed from MSR when available

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 <[email protected]>
This commit is contained in:
Jérôme Duval
2022-11-07 09:03:52 +00:00
parent af136a21bd
commit cedd85556c
2 changed files with 45 additions and 2 deletions
+6 -2
View File
@@ -120,10 +120,14 @@
#define IA32_MSR_KERNEL_GS_BASE 0xc0000102 #define IA32_MSR_KERNEL_GS_BASE 0xc0000102
#define IA32_MSR_TSC_AUX 0xc0000103 #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 K8_MSR_IPM 0xc0010055
#define MSR_F10H_PSTATEDEF(x) (0xc0010064 + (x))
#define PSTATEDEF_EN (1ULL << 63)
#define MSR_F10H_DE_CFG 0xc0011029 #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 // Hardware P-States MSR registers §14.4.1
+39
View File
@@ -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 static void
init_tsc(kernel_args* args) init_tsc(kernel_args* args)
{ {
@@ -1451,6 +1489,7 @@ init_tsc(kernel_args* args)
// try to find the TSC frequency with CPUID // try to find the TSC frequency with CPUID
uint32 conversionFactor = args->arch_args.system_time_cv_factor; uint32 conversionFactor = args->arch_args.system_time_cv_factor;
init_tsc_with_cpuid(args, &conversionFactor); init_tsc_with_cpuid(args, &conversionFactor);
init_tsc_with_msr(args, &conversionFactor);
uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000; uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000;