blob: 815f4f26f52c5d9c9370744224bb903ae89f87c1 [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
#include <bits.h>
#include <lib/unittest/unittest.h>
#include <zircon/types.h>
#include <arch/x86/cpuid.h>
#include <arch/x86/cpuid_test_data.h>
#include <arch/x86/fake_msr_access.h>
#include <arch/x86/hwp.h>
#include <ktl/optional.h>
#include <ktl/enforce.h>
namespace x86 {
namespace {
uint64_t MakeHwpRequest(uint8_t min_perf, uint8_t max_perf, uint8_t desired_perf, uint8_t epp) {
return static_cast<uint64_t>(min_perf) | (static_cast<uint64_t>(max_perf) << 8ull) |
(static_cast<uint64_t>(desired_perf) << 16ull) | (static_cast<uint64_t>(epp) << 24ull);
}
bool TestParsePolicy() {
BEGIN_TEST;
// Valid parse.
auto parsed_policy = IntelHwpParsePolicy("bios-specified");
ASSERT_TRUE(parsed_policy.has_value());
EXPECT_EQ(parsed_policy.value(), IntelHwpPolicy::kBiosSpecified);
// Invalid parses.
EXPECT_TRUE(!IntelHwpParsePolicy(nullptr).has_value());
EXPECT_TRUE(!IntelHwpParsePolicy("").has_value());
EXPECT_TRUE(!IntelHwpParsePolicy("invalid").has_value());
EXPECT_TRUE(!IntelHwpParsePolicy("\n").has_value());
END_TEST;
}
bool TestIntelHwpSupported() {
BEGIN_TEST;
// AMD processors that don't support Intel HWP.
ASSERT_FALSE(IntelHwpSupported(&cpu_id::kCpuIdAmdA49120C));
ASSERT_FALSE(IntelHwpSupported(&cpu_id::kCpuIdThreadRipper2970wx));
// Intel processors supporting HWP.
ASSERT_TRUE(IntelHwpSupported(&cpu_id::kCpuIdCorei5_6260U));
// Older Intel processors not supporting HWP.
ASSERT_FALSE(IntelHwpSupported(&cpu_id::kCpuIdXeon2690v4));
ASSERT_FALSE(IntelHwpSupported(&cpu_id::kCpuIdCeleronJ3455));
END_TEST;
}
bool TestNoCpuSupport() {
BEGIN_TEST;
// HWP_PREF not supported, expect no MSR writes.
FakeMsrAccess fake_msrs = {};
IntelHwpInit(&cpu_id::kCpuIdXeon2690v4, &fake_msrs, IntelHwpPolicy::kBalanced);
// An empty FakeMsrAccess will panic if you attempt to write to any uninitialized MSRs.
END_TEST;
}
static bool TestUseBiosValues() {
BEGIN_TEST;
// Skylake-U has HWP_PREF and EPB
FakeMsrAccess fake_msrs = {};
fake_msrs.msrs_[0] = {X86_MSR_IA32_ENERGY_PERF_BIAS, 0x5};
fake_msrs.msrs_[1] = {X86_MSR_IA32_PM_ENABLE, 0x0};
// min = 0x11, max=0xfe, efficient=0x22, guaranteed=0x33.
fake_msrs.msrs_[2] = {X86_MSR_IA32_HWP_CAPABILITIES, 0x11'22'33'FEull};
fake_msrs.msrs_[3] = {X86_MSR_IA32_HWP_REQUEST, 0x0ull};
IntelHwpInit(&cpu_id::kCpuIdCorei5_6260U, &fake_msrs, IntelHwpPolicy::kBiosSpecified);
// Ensure HWP was enabled.
EXPECT_EQ(fake_msrs.read_msr(X86_MSR_IA32_PM_ENABLE), 1u); // HWP enabled.
// Check the generated HWP request is correct.
//
// We expect IA32_ENERGY_PERF_BIAS = 0x5 mapped to 0x40 EPP, min/max copied
// from HWP capabilities, and desired set to 0 (auto).
EXPECT_EQ(
fake_msrs.read_msr(X86_MSR_IA32_HWP_REQUEST),
MakeHwpRequest(/*min_perf=*/0x11, /*max_perf=*/0xfe, /*desired_perf=*/0x0, /*epp=*/0x40));
END_TEST;
}
static bool TestUsePerformancePolicy() {
BEGIN_TEST;
FakeMsrAccess fake_msrs = {};
fake_msrs.msrs_[1] = {X86_MSR_IA32_PM_ENABLE, 0x0};
// min = 0x11, max=0xfe, guaranteed=0x33, efficient=0x22
fake_msrs.msrs_[2] = {X86_MSR_IA32_HWP_CAPABILITIES, 0x11'22'33'FEull};
fake_msrs.msrs_[3] = {X86_MSR_IA32_HWP_REQUEST, 0x0ull};
// Skylake-U has HWP_PREF.
IntelHwpInit(&cpu_id::kCpuIdCorei5_6260U, &fake_msrs, IntelHwpPolicy::kPerformance);
// Ensure HWP was enabled.
EXPECT_EQ(fake_msrs.read_msr(X86_MSR_IA32_PM_ENABLE), 1u); // HWP enabled.
// Check the generated HWP request is correct.
//
// We expect perf preference set to max performance (0x0), min/max copied
// from the HWP capabilitiy, and desired set to 0 (auto).
EXPECT_EQ(
fake_msrs.read_msr(X86_MSR_IA32_HWP_REQUEST),
MakeHwpRequest(/*min_perf=*/0x11, /*max_perf=*/0xfe, /*desired_perf=*/0x0, /*epp=*/0x0));
END_TEST;
}
static bool TestUseStablePerformancePolicy() {
BEGIN_TEST;
FakeMsrAccess fake_msrs = {};
fake_msrs.msrs_[1] = {X86_MSR_IA32_PM_ENABLE, 0x0};
// min = 0x11, max=0xfe, guaranteed=0x33, efficient=0x22
fake_msrs.msrs_[2] = {X86_MSR_IA32_HWP_CAPABILITIES, 0x11'22'33'FEull};
fake_msrs.msrs_[3] = {X86_MSR_IA32_HWP_REQUEST, 0x0ull};
// Skylake-U has HWP_PREF.
IntelHwpInit(&cpu_id::kCpuIdCorei5_6260U, &fake_msrs, IntelHwpPolicy::kStablePerformance);
// Ensure HWP was enabled.
EXPECT_EQ(fake_msrs.read_msr(X86_MSR_IA32_PM_ENABLE), 1u); // HWP enabled.
// Check the generated HWP request is correct.
//
// We expect perf preference set to max performance (0x0), min/max/desired
// all set to the guaranteed performance value.
EXPECT_EQ(
fake_msrs.read_msr(X86_MSR_IA32_HWP_REQUEST),
MakeHwpRequest(/*min_perf=*/0x33, /*max_perf=*/0x33, /*desired_perf=*/0x33, /*epp=*/0x0));
END_TEST;
}
} // namespace
} // namespace x86
UNITTEST_START_TESTCASE(x86_hwp_tests)
UNITTEST("TestParsePolicy", x86::TestParsePolicy)
UNITTEST("TestIntelHwpSupported", x86::TestIntelHwpSupported)
UNITTEST("TestNoCpuSupport", x86::TestNoCpuSupport)
UNITTEST("TestUseBiosValues", x86::TestUseBiosValues)
UNITTEST("TestPerformancePolicy", x86::TestUsePerformancePolicy)
UNITTEST("TestStablePerformancePolicy", x86::TestUseStablePerformancePolicy)
UNITTEST_END_TESTCASE(x86_hwp_tests, "x86_hwp", "x86 Intel HWP tests")