blob: 4f3b3f184213f9c825b3428fb4bce33c9cfcb398 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <arch/x86.h>
#include <arch/x86/feature.h>
#include <arch/x86/timer_freq.h>
#include <bits.h>
#include <zircon/errors.h>
#define MSR_PLATFORM_INFO 0xCE
static uint64_t compute_p_state_clock(uint64_t p_state_msr) {
// is it valid?
if (!BIT(p_state_msr, 63))
return 0;
// different AMD microarchitectures use slightly different formulas to compute
// the effective clock rate of a P state
uint64_t clock = 0;
switch (x86_microarch) {
case X86_MICROARCH_AMD_BULLDOZER:
case X86_MICROARCH_AMD_JAGUAR: {
uint64_t did = BITS_SHIFT(p_state_msr, 8, 6);
uint64_t fid = BITS(p_state_msr, 5, 0);
clock = (100 * (fid + 0x10) / (1 << did)) * 1000 * 1000;
break;
}
case X86_MICROARCH_AMD_ZEN: {
uint64_t fid = BITS(p_state_msr, 7, 0);
clock = (fid * 25) * 1000 * 1000;
break;
}
default:
break;
}
return clock;
}
uint64_t x86_lookup_core_crystal_freq() {
// The APIC frequency is the core crystal clock frequency if it is
// enumerated in the CPUID leaf 0x15, or the processor's bus clock
// frequency.
const struct cpuid_leaf *tsc_leaf = x86_get_cpuid_leaf(X86_CPUID_TSC);
if (tsc_leaf && tsc_leaf->c != 0) {
return tsc_leaf->c;
}
switch (x86_microarch) {
case X86_MICROARCH_INTEL_SKYLAKE:
case X86_MICROARCH_INTEL_KABYLAKE:
return 24u * 1000 * 1000;
case X86_MICROARCH_INTEL_SANDY_BRIDGE:
case X86_MICROARCH_INTEL_IVY_BRIDGE:
case X86_MICROARCH_INTEL_HASWELL:
case X86_MICROARCH_INTEL_BROADWELL: {
uint64_t platform_info;
if (read_msr_safe(MSR_PLATFORM_INFO, &platform_info) == ZX_OK) {
uint64_t bus_freq_mult = (platform_info >> 8) & 0xf;
return bus_freq_mult * 100 * 1000 * 1000;
}
break;
}
case X86_MICROARCH_AMD_BULLDOZER:
case X86_MICROARCH_AMD_JAGUAR:
case X86_MICROARCH_AMD_ZEN:
// 15h-17h BKDGs mention the APIC timer rate is 2xCLKIN,
// which experimentally appears to be 100Mhz always
return 100 * 1000 * 1000;
case X86_MICROARCH_UNKNOWN:
break;
}
return 0;
}
uint64_t x86_lookup_tsc_freq() {
if (x86_vendor == X86_VENDOR_INTEL) {
const uint64_t core_crystal_clock_freq = x86_lookup_core_crystal_freq();
// If this leaf is present, then 18.18.3 (Determining the Processor Base
// Frequency) documents this as the nominal TSC frequency.
const struct cpuid_leaf *tsc_leaf = x86_get_cpuid_leaf(X86_CPUID_TSC);
if (tsc_leaf && tsc_leaf->a) {
return (core_crystal_clock_freq * tsc_leaf->b) / tsc_leaf->a;
}
} else if (x86_vendor == X86_VENDOR_AMD) {
uint32_t p0_state_msr = 0xc0010064; // base P-state MSR
switch (x86_microarch) {
// TSC is invariant on these architectures and defined as running at
// P0 clock, so compute it
case X86_MICROARCH_AMD_ZEN: {
// According to the Family 17h PPR, the first P-state MSR is indeed
// P0 state and appears to be experimentally so
uint64_t p0_state;
if (read_msr_safe(p0_state_msr, &p0_state) != ZX_OK)
break;
return compute_p_state_clock(p0_state);
}
default:
break;
}
}
return 0;
}