blob: 94367ec7f3b092b0ee153a12e5216ea7c3e97fcd [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
// Copyright (c) 2016 Travis Geiselbrecht
//
// 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 <zircon/compiler.h>
#include <err.h>
#include <inttypes.h>
#include <string.h>
#include <arch/x86/feature.h>
#include <kernel/auto_lock.h>
#include <kernel/mp.h>
#include <lib/console.h>
static bool hwp_enabled = false;
static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE;
static void hwp_enable_sync_task(void* ctx)
{
// Enable HWP
write_msr(X86_MSR_IA32_PM_ENABLE, 1);
// 14.4.7 set minimum/maximum to values from capabilities for
// common case. hint=0x80 by default
uint64_t hwp_caps = read_msr(X86_MSR_IA32_HWP_CAPABILITIES);
uint64_t hwp_req = (0x80ull << 24) | ((hwp_caps & 0xff) << 8) | ((hwp_caps >> 24) & 0xff);
write_msr(X86_MSR_IA32_HWP_REQUEST, hwp_req);
}
static void hwp_enable(void)
{
AutoSpinLock guard(&lock);
if (hwp_enabled) {
return;
}
if (!x86_feature_test(X86_FEATURE_HWP)) {
printf("HWP not supported\n");
return;
}
mp_sync_exec(MP_IPI_TARGET_ALL, 0, hwp_enable_sync_task, NULL);
hwp_enabled = true;
}
static void hwp_set_hint_sync_task(void* ctx)
{
uint8_t hint = (unsigned long)ctx & 0xff;
uint64_t hwp_req = read_msr(X86_MSR_IA32_HWP_REQUEST) & ~(0xff << 24);
hwp_req |= (hint << 24);
hwp_req &= ~(0xffffffffull << 32);
write_msr(X86_MSR_IA32_HWP_REQUEST, hwp_req);
}
static void hwp_set_hint(unsigned long hint) {
AutoSpinLock guard(&lock);
if (!hwp_enabled) {
printf("Enable HWP first\n");
return;
}
if (!x86_feature_test(X86_FEATURE_HWP_PREF)) {
printf("HWP hint not supported\n");
return;
}
mp_sync_exec(MP_IPI_TARGET_ALL, 0, hwp_set_hint_sync_task, (void*)hint);
}
static int cmd_hwp(int argc, const cmd_args *argv, uint32_t flags)
{
if (argc < 2) {
notenoughargs:
printf("not enough arguments\n");
usage:
printf("usage:\n");
printf("%s enable\n", argv[0].str);
printf("%s hint <0-255>\n", argv[0].str);
return ZX_ERR_INTERNAL;
}
if (!strcmp(argv[1].str, "enable")) {
hwp_enable();
} else if (!strcmp(argv[1].str, "hint")) {
if (argc < 3) {
goto notenoughargs;
}
if (argv[2].u > 0xff) {
printf("hint must be between 0 (performance) and 255 (energy efficiency)!");
goto usage;
}
hwp_set_hint(argv[2].u);
} else {
printf("unknown command\n");
goto usage;
}
return ZX_OK;
}
STATIC_COMMAND_START
STATIC_COMMAND("hwp", "hardware controlled performance states\n", &cmd_hwp)
STATIC_COMMAND_END(hwp);