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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user