cppc.c (2397B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * cppc.c: CPPC Interface for x86 4 * Copyright (c) 2016, Intel Corporation. 5 */ 6 7#include <acpi/cppc_acpi.h> 8#include <asm/msr.h> 9#include <asm/processor.h> 10#include <asm/topology.h> 11 12/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */ 13 14bool cpc_supported_by_cpu(void) 15{ 16 switch (boot_cpu_data.x86_vendor) { 17 case X86_VENDOR_AMD: 18 case X86_VENDOR_HYGON: 19 return boot_cpu_has(X86_FEATURE_CPPC); 20 } 21 return false; 22} 23 24bool cpc_ffh_supported(void) 25{ 26 return true; 27} 28 29int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val) 30{ 31 int err; 32 33 err = rdmsrl_safe_on_cpu(cpunum, reg->address, val); 34 if (!err) { 35 u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1, 36 reg->bit_offset); 37 38 *val &= mask; 39 *val >>= reg->bit_offset; 40 } 41 return err; 42} 43 44int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val) 45{ 46 u64 rd_val; 47 int err; 48 49 err = rdmsrl_safe_on_cpu(cpunum, reg->address, &rd_val); 50 if (!err) { 51 u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1, 52 reg->bit_offset); 53 54 val <<= reg->bit_offset; 55 val &= mask; 56 rd_val &= ~mask; 57 rd_val |= val; 58 err = wrmsrl_safe_on_cpu(cpunum, reg->address, rd_val); 59 } 60 return err; 61} 62 63static void amd_set_max_freq_ratio(void) 64{ 65 struct cppc_perf_caps perf_caps; 66 u64 highest_perf, nominal_perf; 67 u64 perf_ratio; 68 int rc; 69 70 rc = cppc_get_perf_caps(0, &perf_caps); 71 if (rc) { 72 pr_debug("Could not retrieve perf counters (%d)\n", rc); 73 return; 74 } 75 76 highest_perf = amd_get_highest_perf(); 77 nominal_perf = perf_caps.nominal_perf; 78 79 if (!highest_perf || !nominal_perf) { 80 pr_debug("Could not retrieve highest or nominal performance\n"); 81 return; 82 } 83 84 perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf); 85 /* midpoint between max_boost and max_P */ 86 perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1; 87 if (!perf_ratio) { 88 pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n"); 89 return; 90 } 91 92 freq_invariance_set_perf_ratio(perf_ratio, false); 93} 94 95static DEFINE_MUTEX(freq_invariance_lock); 96 97void init_freq_invariance_cppc(void) 98{ 99 static bool init_done; 100 101 if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 102 return; 103 104 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 105 return; 106 107 mutex_lock(&freq_invariance_lock); 108 if (!init_done) 109 amd_set_max_freq_ratio(); 110 init_done = true; 111 mutex_unlock(&freq_invariance_lock); 112}