From 739d4da07be874b48cf9b1b89da9e979a05edc06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Tue, 22 Nov 2022 19:29:05 +0100 Subject: [PATCH] amd_pstates: introduce a AMD P-states driver for Ryzen with the CPPC feature tested on Zen2 (Ryzen 3 5300U) This support was submitted in October for inclusion in Linux. Haiku supports only two profiles. We could probably add some more, and let the driver says which it supports. Change-Id: Id7754b445bc32a691d58a1e4af630351562abc22 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5826 Reviewed-by: waddlesplash Tested-by: Commit checker robot --- build/jam/packages/Haiku | 2 +- headers/private/kernel/arch/x86/arch_cpu.h | 19 +++ src/add-ons/kernel/power/cpufreq/Jamfile | 1 + .../kernel/power/cpufreq/amd_pstates/Jamfile | 8 + .../power/cpufreq/amd_pstates/amd_pstates.cpp | 152 ++++++++++++++++++ 5 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 src/add-ons/kernel/power/cpufreq/amd_pstates/Jamfile create mode 100644 src/add-ons/kernel/power/cpufreq/amd_pstates/amd_pstates.cpp diff --git a/build/jam/packages/Haiku b/build/jam/packages/Haiku index 113644f303..4aaf992b3a 100644 --- a/build/jam/packages/Haiku +++ b/build/jam/packages/Haiku @@ -48,7 +48,7 @@ AddFilesToPackage add-ons kernel generic AddFilesToPackage add-ons kernel partitioning_systems : amiga_rdb@m68k apple@ppc sun@sparc efi_gpt intel session ; AddFilesToPackage add-ons kernel interrupt_controllers : openpic@ppc ; -AddFilesToPackage add-ons kernel power cpufreq : intel_pstates@x86,x86_64 ; +AddFilesToPackage add-ons kernel power cpufreq : amd_pstates@x86,x86_64 intel_pstates@x86,x86_64 ; AddFilesToPackage add-ons kernel power cpuidle : intel_cstates@x86,x86_64 ; if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 { diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 70a8fc65e6..be3541bbfc 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -129,6 +129,24 @@ #define MSR_F10H_DE_CFG 0xc0011029 #define DE_CFG_SERIALIZE_LFENCE (1 << 1) +#define MSR_AMD_CPPC_CAP1 0xc00102b0 +#define AMD_CPPC_LOWEST_PERF(x) ((x) & 0xff) +#define AMD_CPPC_LOWNONLIN_PERF(x) ((x >> 8) & 0xff) +#define AMD_CPPC_NOMINAL_PERF(x) ((x >> 16) & 0xff) +#define AMD_CPPC_HIGHEST_PERF(x) ((x >> 24) & 0xff) +#define MSR_AMD_CPPC_ENABLE 0xc00102b1 +#define MSR_AMD_CPPC_REQ 0xc00102b3 +#define AMD_CPPC_MAX_PERF(x) ((x) & 0xff) +#define AMD_CPPC_MIN_PERF(x) (((x) & 0xff) << 8) +#define AMD_CPPC_DES_PERF(x) (((x) & 0xff) << 16) +#define AMD_CPPC_EPP_PERF(x) (((x) & 0xff) << 24) + +#define AMD_CPPC_EPP_PERFORMANCE 0x00 +#define AMD_CPPC_EPP_BALANCE_PERFORMANCE 0x80 +#define AMD_CPPC_EPP_BALANCE_POWERSAVE 0xbf +#define AMD_CPPC_EPP_POWERSAVE 0xff +#define MSR_AMD_CPPC_STATUS 0xc00102b4 + // Hardware P-States MSR registers §14.4.1 // reference https://software.intel.com/content/dam/develop/public/us/en/documents/253669-sdm-vol-3b.pdf @@ -359,6 +377,7 @@ #define IA32_FEATURE_AMD_SSBD (1 << 24) // Speculative Store Bypass Disable #define IA32_FEATURE_VIRT_SSBD (1 << 25) // Virtualized Speculative Store Bypass Disable #define IA32_FEATURE_AMD_SSB_NO (1 << 26) // Speculative Store Bypass is fixed in hardware +#define IA32_FEATURE_CPPC (1 << 27) // Collaborative Processor Performance Control // Memory type ranges diff --git a/src/add-ons/kernel/power/cpufreq/Jamfile b/src/add-ons/kernel/power/cpufreq/Jamfile index 163027559b..81306a7e6b 100644 --- a/src/add-ons/kernel/power/cpufreq/Jamfile +++ b/src/add-ons/kernel/power/cpufreq/Jamfile @@ -1,4 +1,5 @@ SubDir HAIKU_TOP src add-ons kernel power cpufreq ; +SubInclude HAIKU_TOP src add-ons kernel power cpufreq amd_pstates ; SubInclude HAIKU_TOP src add-ons kernel power cpufreq intel_pstates ; diff --git a/src/add-ons/kernel/power/cpufreq/amd_pstates/Jamfile b/src/add-ons/kernel/power/cpufreq/amd_pstates/Jamfile new file mode 100644 index 0000000000..4bae76b51a --- /dev/null +++ b/src/add-ons/kernel/power/cpufreq/amd_pstates/Jamfile @@ -0,0 +1,8 @@ +SubDir HAIKU_TOP src add-ons kernel power cpufreq amd_pstates ; + +UsePrivateKernelHeaders ; + +KernelAddon amd_pstates : + amd_pstates.cpp + ; + diff --git a/src/add-ons/kernel/power/cpufreq/amd_pstates/amd_pstates.cpp b/src/add-ons/kernel/power/cpufreq/amd_pstates/amd_pstates.cpp new file mode 100644 index 0000000000..bd2a1ba0cd --- /dev/null +++ b/src/add-ons/kernel/power/cpufreq/amd_pstates/amd_pstates.cpp @@ -0,0 +1,152 @@ +/* + * Copyright 2020-2022, Jérôme Duval, jerome.duval@gmail.com. + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, + */ + + +#include +#include + +#include +#include +#include +#include + + +#define AMD_PSTATES_MODULE_NAME CPUFREQ_MODULES_PREFIX "/amd_pstates/v1" + + +static uint32 sHWPLowest; +static uint32 sHWPGuaranteed; +static uint32 sHWPEfficient; +static uint32 sHWPHighest; + +static bool sAvoidBoost = true; + + +static void set_normal_pstate(void* /* dummy */, int cpu); + + +static void +pstates_set_scheduler_mode(scheduler_mode mode) +{ + sAvoidBoost = mode == SCHEDULER_MODE_POWER_SAVING; + call_all_cpus(set_normal_pstate, NULL); +} + + +static status_t +pstates_increase_performance(int delta) +{ + return B_NOT_SUPPORTED; +} + + +static status_t +pstates_decrease_performance(int delta) +{ + return B_NOT_SUPPORTED; +} + + +static bool +is_cpu_model_supported(cpu_ent* cpu) +{ + if (cpu->arch.vendor != VENDOR_AMD) + return false; + + return true; +} + + +static void +set_normal_pstate(void* /* dummy */, int cpu) +{ + x86_write_msr(MSR_AMD_CPPC_ENABLE, 1); + + uint64 cap1 = x86_read_msr(MSR_AMD_CPPC_CAP1); + sHWPLowest = AMD_CPPC_LOWEST_PERF(cap1); + sHWPEfficient = AMD_CPPC_LOWNONLIN_PERF(cap1); + sHWPGuaranteed = AMD_CPPC_NOMINAL_PERF(cap1); + sHWPHighest = AMD_CPPC_HIGHEST_PERF(cap1); + + uint64 request = AMD_CPPC_MIN_PERF(sHWPEfficient); + request |= AMD_CPPC_MAX_PERF(sAvoidBoost ? sHWPGuaranteed : sHWPHighest); + request |= AMD_CPPC_EPP_PERF( + sAvoidBoost ? AMD_CPPC_EPP_BALANCE_PERFORMANCE : AMD_CPPC_EPP_PERFORMANCE); + x86_write_msr(MSR_AMD_CPPC_REQ, request & 0xffffffff); +} + + +static status_t +init_pstates() +{ + if (!x86_check_feature(IA32_FEATURE_CPPC, FEATURE_EXT_8_EBX)) + return B_ERROR; + + int32 cpuCount = smp_get_num_cpus(); + for (int32 i = 0; i < cpuCount; i++) { + if (!is_cpu_model_supported(&gCPU[i])) + return B_ERROR; + } + + dprintf("using AMD P-States (capabilities: 0x%08" B_PRIx64 "\n", + x86_read_msr(MSR_AMD_CPPC_CAP1)); + + pstates_set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY); + + call_all_cpus_sync(set_normal_pstate, NULL); + return B_OK; +} + + +static status_t +uninit_pstates() +{ + call_all_cpus_sync(set_normal_pstate, NULL); + + return B_OK; +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return init_pstates(); + + case B_MODULE_UNINIT: + uninit_pstates(); + return B_OK; + } + + return B_ERROR; +} + + +static cpufreq_module_info sAMDPStates = { + { + AMD_PSTATES_MODULE_NAME, + 0, + std_ops, + }, + + 1.0f, + + pstates_set_scheduler_mode, + + pstates_increase_performance, + pstates_decrease_performance, +}; + + +module_info* modules[] = { + (module_info*)&sAMDPStates, + NULL +}; +