blob: 57b571272178ad15027b263fdcb1d572e34649fd [file] [log] [blame]
// Copyright 2020 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
#ifndef ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_POWER_H_
#define ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_POWER_H_
#include <lib/arch/x86/cpuid.h>
#include <lib/arch/x86/feature.h>
namespace arch {
// Sets the "Turbo" state, which allows the processor to dynamically adjust and
// control its operating frequency. Turbo here collectively refers to the
// analogous technologies of "Intel Turbo Boost" and "AMD Turbo Core". Returns
// false if Turbo is unsupported; else returns true.
//
// For more detail, see:
// [intel/vol3]: 14.3.3 IntelĀ® Turbo Boost Technology.
// [amd/vol2]: 17.2 Core Performance Boost.
template <typename CpuidIoProvider, typename MsrIoProvider>
inline bool SetX86CpuTurboState(CpuidIoProvider&& cpuid, MsrIoProvider&& msr, bool enable) {
// [intel/vol3]: 14.3.2.1 Discover Hardware Support and Enabling of Opportunistic Processor
// Performance Operation.
//
// The Intel way, which Intel makes rather convoluted. Initially, when
// powered on, IA32_MISC_ENABLE enumerates whether Turbo is supported: if
// IDA_DISABLE is set, then Turbo is supported and is disabled by default;
// else it is not supported. Moreover, unlike every other CPUID feature, leaf
// 0x6 EAX does not enumerate whether Turbo is supported, but instead
// dynamically reflects the actual Turbo state. Accordingly, to determine
// whether Turbo is supported we must cross-reference both CPUID and MSR
// state.
//
// IDA stands for "Intel Dynamic Acceleration", an earlier name/iteration of
// Intel Turbo Boost.
if (MiscFeaturesMsr::IsSupported(cpuid) &&
CpuidSupports<CpuidThermalAndPowerFeatureFlagsA>(cpuid)) {
const auto intel_features = cpuid.template Read<CpuidThermalAndPowerFeatureFlagsA>();
auto misc_enable = MiscFeaturesMsr::Get().ReadFrom(&msr);
const bool intel_supported_and_on = intel_features.turbo() || intel_features.turbo_max();
const bool intel_supported_and_off = misc_enable.ida_disable();
const bool intel_supported = intel_supported_and_on || intel_supported_and_off;
if (intel_supported) {
misc_enable.set_ida_disable(!enable).WriteTo(&msr);
return true;
}
}
// The AMD way.
// CPB stands for "Core Performance Boost", an earlier name/iteration of AMD
// Turbo Core.
if (CpuidSupports<CpuidAdvancedPowerFeatureFlags>(cpuid) &&
cpuid.template Read<CpuidAdvancedPowerFeatureFlags>().cpb()) {
AmdHardwareConfigurationMsr::Get().ReadFrom(&msr).set_cpb_dis(!enable).WriteTo(&msr);
return true;
}
// Unsupported.
return false;
}
} // namespace arch
#endif // ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_POWER_H_