1// Copyright 2017 The Fuchsia Authors 2// Copyright (c) 2016 Travis Geiselbrecht 3// 4// Use of this source code is governed by a MIT-style 5// license that can be found in the LICENSE file or at 6// https://opensource.org/licenses/MIT 7 8#include <arch/x86/feature.h> 9#include <err.h> 10#include <inttypes.h> 11#include <kernel/auto_lock.h> 12#include <kernel/mp.h> 13#include <kernel/spinlock.h> 14#include <lib/console.h> 15#include <string.h> 16#include <zircon/compiler.h> 17 18static bool hwp_enabled = false; 19 20static SpinLock lock; 21 22static void hwp_enable_sync_task(void* ctx) { 23 // Enable HWP 24 write_msr(X86_MSR_IA32_PM_ENABLE, 1); 25 26 // 14.4.7 set minimum/maximum to values from capabilities for 27 // common case. hint=0x80 by default 28 uint64_t hwp_caps = read_msr(X86_MSR_IA32_HWP_CAPABILITIES); 29 uint64_t hwp_req = (0x80ull << 24) | ((hwp_caps & 0xff) << 8) | ((hwp_caps >> 24) & 0xff); 30 write_msr(X86_MSR_IA32_HWP_REQUEST, hwp_req); 31} 32 33static void hwp_enable(void) { 34 AutoSpinLockNoIrqSave guard(&lock); 35 36 if (hwp_enabled) { 37 return; 38 } 39 40 if (!x86_feature_test(X86_FEATURE_HWP)) { 41 printf("HWP not supported\n"); 42 return; 43 } 44 45 mp_sync_exec(MP_IPI_TARGET_ALL, 0, hwp_enable_sync_task, nullptr); 46 47 hwp_enabled = true; 48} 49 50static void hwp_set_hint_sync_task(void* ctx) { 51 uint8_t hint = (unsigned long)ctx & 0xff; 52 uint64_t hwp_req = read_msr(X86_MSR_IA32_HWP_REQUEST) & ~(0xff << 24); 53 hwp_req |= (hint << 24); 54 hwp_req &= ~(0xffffffffull << 32); 55 write_msr(X86_MSR_IA32_HWP_REQUEST, hwp_req); 56} 57 58static void hwp_set_hint(unsigned long hint) { 59 AutoSpinLockNoIrqSave guard(&lock); 60 61 if (!hwp_enabled) { 62 printf("Enable HWP first\n"); 63 return; 64 } 65 if (!x86_feature_test(X86_FEATURE_HWP_PREF)) { 66 printf("HWP hint not supported\n"); 67 return; 68 } 69 mp_sync_exec(MP_IPI_TARGET_ALL, 0, hwp_set_hint_sync_task, (void*)hint); 70} 71 72static int cmd_hwp(int argc, const cmd_args* argv, uint32_t flags) { 73 if (argc < 2) { 74 notenoughargs: 75 printf("not enough arguments\n"); 76 usage: 77 printf("usage:\n"); 78 printf("%s enable\n", argv[0].str); 79 printf("%s hint <0-255>\n", argv[0].str); 80 return ZX_ERR_INTERNAL; 81 } 82 83 if (!strcmp(argv[1].str, "enable")) { 84 hwp_enable(); 85 } else if (!strcmp(argv[1].str, "hint")) { 86 if (argc < 3) { 87 goto notenoughargs; 88 } 89 if (argv[2].u > 0xff) { 90 printf("hint must be between 0 (performance) and 255 (energy efficiency)!"); 91 goto usage; 92 } 93 hwp_set_hint(argv[2].u); 94 } else { 95 printf("unknown command\n"); 96 goto usage; 97 } 98 99 return ZX_OK; 100} 101 102STATIC_COMMAND_START 103STATIC_COMMAND("hwp", "hardware controlled performance states\n", &cmd_hwp) 104STATIC_COMMAND_END(hwp); 105