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