kernel/x86: init the tsc frequency and clock speed from CPUID when available
only for Intel newer CPUs. Change-Id: Icd83f3b643796bfb3725b5c8877b9e7828bc71d9 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5688 Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk> Reviewed-by: Fredrik Holmqvist <fredrik.holmqvist@gmail.com> Reviewed-by: Alex von Gluck IV <kallisti5@unixzen.com> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
parent
84bd9b4ad5
commit
2e69f2b076
@ -1403,12 +1403,85 @@ detect_amdc1e_noarat()
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_tsc_with_cpuid(kernel_args* args, uint32* conversionFactor)
|
||||
{
|
||||
cpu_ent* cpu = get_cpu_struct();
|
||||
if (cpu->arch.vendor != VENDOR_INTEL)
|
||||
return;
|
||||
uint32 model = (cpu->arch.extended_model << 4) | cpu->arch.model;
|
||||
cpuid_info cpuid;
|
||||
get_current_cpuid(&cpuid, 0, 0);
|
||||
uint32 maxBasicLeaf = cpuid.eax_0.max_eax;
|
||||
if (maxBasicLeaf < 0x15)
|
||||
return;
|
||||
|
||||
get_current_cpuid(&cpuid, 0x15, 0);
|
||||
if (cpuid.regs.eax == 0 || cpuid.regs.ebx == 0)
|
||||
return;
|
||||
uint32 khz = cpuid.regs.ecx / 1000;
|
||||
uint32 denominator = cpuid.regs.eax;
|
||||
uint32 numerator = cpuid.regs.ebx;
|
||||
if (khz == 0 && model == 0x5f) {
|
||||
// CPUID 0x16 isn't supported, hardcoding
|
||||
khz = 25000;
|
||||
}
|
||||
|
||||
if (khz == 0 && maxBasicLeaf >= 0x16) {
|
||||
// for these CPUs the base frequency is also the tsc frequency
|
||||
get_current_cpuid(&cpuid, 0x16, 0);
|
||||
khz = cpuid.regs.eax * 1000 * denominator / numerator;
|
||||
}
|
||||
if (khz == 0)
|
||||
return;
|
||||
dprintf("CPU: using TSC frequency from CPUID\n");
|
||||
// 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)
|
||||
{
|
||||
// init the TSC -> system_time() conversion factors
|
||||
|
||||
// try to find the TSC frequency with CPUID
|
||||
uint32 conversionFactor = args->arch_args.system_time_cv_factor;
|
||||
init_tsc_with_cpuid(args, &conversionFactor);
|
||||
uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000;
|
||||
|
||||
|
||||
#ifdef __x86_64__
|
||||
// The x86_64 system_time() implementation uses 64-bit multiplication and
|
||||
// therefore shifting is not necessary for low frequencies (it's also not
|
||||
// too likely that there'll be any x86_64 CPUs clocked under 1GHz).
|
||||
__x86_setup_system_time((uint64)conversionFactor << 32,
|
||||
conversionFactorNsecs);
|
||||
#else
|
||||
if (conversionFactorNsecs >> 32 != 0) {
|
||||
// the TSC frequency is < 1 GHz, which forces us to shift the factor
|
||||
__x86_setup_system_time(conversionFactor, conversionFactorNsecs >> 16,
|
||||
true);
|
||||
} else {
|
||||
// the TSC frequency is >= 1 GHz
|
||||
__x86_setup_system_time(conversionFactor, conversionFactorNsecs, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_cpu_init_percpu(kernel_args* args, int cpu)
|
||||
{
|
||||
load_microcode(cpu);
|
||||
detect_cpu(cpu);
|
||||
|
||||
if (cpu == 0)
|
||||
init_tsc(args);
|
||||
|
||||
if (!gCpuIdleFunc) {
|
||||
if (detect_amdc1e_noarat())
|
||||
gCpuIdleFunc = amdc1e_noarat_idle;
|
||||
@ -1446,28 +1519,6 @@ arch_cpu_init(kernel_args* args)
|
||||
dprintf("CPU: no microcode provided\n");
|
||||
}
|
||||
|
||||
// init the TSC -> system_time() conversion factors
|
||||
|
||||
uint32 conversionFactor = args->arch_args.system_time_cv_factor;
|
||||
uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000;
|
||||
|
||||
#ifdef __x86_64__
|
||||
// The x86_64 system_time() implementation uses 64-bit multiplication and
|
||||
// therefore shifting is not necessary for low frequencies (it's also not
|
||||
// too likely that there'll be any x86_64 CPUs clocked under 1GHz).
|
||||
__x86_setup_system_time((uint64)conversionFactor << 32,
|
||||
conversionFactorNsecs);
|
||||
#else
|
||||
if (conversionFactorNsecs >> 32 != 0) {
|
||||
// the TSC frequency is < 1 GHz, which forces us to shift the factor
|
||||
__x86_setup_system_time(conversionFactor, conversionFactorNsecs >> 16,
|
||||
true);
|
||||
} else {
|
||||
// the TSC frequency is >= 1 GHz
|
||||
__x86_setup_system_time(conversionFactor, conversionFactorNsecs, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize descriptor tables.
|
||||
x86_descriptors_init(args);
|
||||
|
||||
|
@ -100,6 +100,18 @@ arch_system_info_init(struct kernel_args *args)
|
||||
| (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping;
|
||||
|
||||
sCPUClockSpeed = args->arch_args.cpu_clock_speed;
|
||||
if (cpu->arch.vendor == VENDOR_INTEL) {
|
||||
cpuid_info cpuid;
|
||||
get_current_cpuid(&cpuid, 0, 0);
|
||||
uint32 maxBasicLeaf = cpuid.eax_0.max_eax;
|
||||
if (maxBasicLeaf >= 0x16) {
|
||||
get_current_cpuid(&cpuid, 0x16, 0);
|
||||
if (cpuid.regs.eax != 0) {
|
||||
sCPUClockSpeed = cpuid.regs.eax * 1000000LL;
|
||||
dprintf("found clock speed with CPUID.16h\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user