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 <linux/bitfield.h> 8 #include <linux/limits.h> 9 10 #include <acpi/cppc_acpi.h> 11 #include <asm/msr.h> 12 #include <asm/processor.h> 13 #include <asm/topology.h> 14 #include <asm/cpu_device_id.h> 15 16 #define CPPC_HIGHEST_PERF_PERFORMANCE 196 17 #define CPPC_HIGHEST_PERF_PREFCORE 166 18 19 enum amd_pref_core { 20 AMD_PREF_CORE_UNKNOWN = 0, 21 AMD_PREF_CORE_SUPPORTED, 22 AMD_PREF_CORE_UNSUPPORTED, 23 }; 24 static enum amd_pref_core amd_pref_core_detected; 25 static u64 boost_numerator; 26 27 /* Refer to drivers/acpi/cppc_acpi.c for the description of functions */ 28 29 bool cpc_supported_by_cpu(void) 30 { 31 switch (boot_cpu_data.x86_vendor) { 32 case X86_VENDOR_AMD: 33 case X86_VENDOR_HYGON: 34 if (boot_cpu_data.x86 == 0x19 && ((boot_cpu_data.x86_model <= 0x0f) || 35 (boot_cpu_data.x86_model >= 0x20 && boot_cpu_data.x86_model <= 0x2f))) 36 return true; 37 else if (boot_cpu_data.x86 == 0x17 && 38 boot_cpu_data.x86_model >= 0x30 && boot_cpu_data.x86_model <= 0x7f) 39 return true; 40 return boot_cpu_has(X86_FEATURE_CPPC); 41 } 42 return false; 43 } 44 45 bool cpc_ffh_supported(void) 46 { 47 return true; 48 } 49 50 static bool cpc_ffh_reg_valid(const struct cpc_reg *reg) 51 { 52 return reg->address <= U32_MAX && reg->bit_width && 53 reg->bit_width <= 64 && 54 reg->bit_offset <= 64 - reg->bit_width; 55 } 56 57 int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val) 58 { 59 int err; 60 61 if (!cpc_ffh_reg_valid(reg)) 62 return -EINVAL; 63 64 err = rdmsrq_safe_on_cpu(cpunum, reg->address, val); 65 if (!err) { 66 u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1, 67 reg->bit_offset); 68 69 *val &= mask; 70 *val >>= reg->bit_offset; 71 } 72 return err; 73 } 74 75 int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val) 76 { 77 u64 rd_val; 78 int err; 79 80 if (!cpc_ffh_reg_valid(reg)) 81 return -EINVAL; 82 83 err = rdmsrq_safe_on_cpu(cpunum, reg->address, &rd_val); 84 if (!err) { 85 u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1, 86 reg->bit_offset); 87 88 val <<= reg->bit_offset; 89 val &= mask; 90 rd_val &= ~mask; 91 rd_val |= val; 92 err = wrmsrq_safe_on_cpu(cpunum, reg->address, rd_val); 93 } 94 return err; 95 } 96 97 static void amd_set_max_freq_ratio(void) 98 { 99 u64 numerator, denominator; 100 u64 perf_ratio; 101 int rc; 102 103 rc = amd_get_boost_ratio(0, &numerator, &denominator); 104 if (rc) { 105 pr_debug("Could not retrieve boost ratio (%d)\n", rc); 106 return; 107 } 108 109 /* midpoint between max_boost and max_P */ 110 perf_ratio = (div_u64(numerator * SCHED_CAPACITY_SCALE, denominator) + SCHED_CAPACITY_SCALE) >> 1; 111 112 freq_invariance_set_perf_ratio(perf_ratio, false); 113 } 114 115 static DEFINE_MUTEX(freq_invariance_lock); 116 117 static inline void init_freq_invariance_cppc(void) 118 { 119 static bool init_done; 120 121 if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 122 return; 123 124 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 125 return; 126 127 mutex_lock(&freq_invariance_lock); 128 if (!init_done) 129 amd_set_max_freq_ratio(); 130 init_done = true; 131 mutex_unlock(&freq_invariance_lock); 132 } 133 134 void acpi_processor_init_invariance_cppc(void) 135 { 136 init_freq_invariance_cppc(); 137 } 138 139 /* 140 * Get the highest performance register value. 141 * @cpu: CPU from which to get highest performance. 142 * @highest_perf: Return address for highest performance value. 143 * 144 * Return: 0 for success, negative error code otherwise. 145 */ 146 int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf) 147 { 148 u64 val; 149 int ret; 150 151 if (cpu_feature_enabled(X86_FEATURE_CPPC)) { 152 ret = rdmsrq_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &val); 153 if (ret) 154 goto out; 155 156 val = FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, val); 157 } else { 158 ret = cppc_get_highest_perf(cpu, &val); 159 if (ret) 160 goto out; 161 } 162 163 WRITE_ONCE(*highest_perf, (u32)val); 164 out: 165 return ret; 166 } 167 EXPORT_SYMBOL_GPL(amd_get_highest_perf); 168 169 /** 170 * amd_detect_prefcore: Detect if CPUs in the system support preferred cores 171 * @detected: Output variable for the result of the detection. 172 * 173 * Determine whether CPUs in the system support preferred cores. On systems 174 * that support preferred cores, different highest perf values will be found 175 * on different cores. On other systems, the highest perf value will be the 176 * same on all cores. 177 * 178 * The result of the detection will be stored in the 'detected' parameter. 179 * 180 * Return: 0 for success, negative error code otherwise 181 */ 182 int amd_detect_prefcore(bool *detected) 183 { 184 int cpu, count = 0; 185 u64 highest_perf[2] = {0}; 186 187 if (WARN_ON(!detected)) 188 return -EINVAL; 189 190 switch (amd_pref_core_detected) { 191 case AMD_PREF_CORE_SUPPORTED: 192 *detected = true; 193 return 0; 194 case AMD_PREF_CORE_UNSUPPORTED: 195 *detected = false; 196 return 0; 197 default: 198 break; 199 } 200 201 for_each_online_cpu(cpu) { 202 u32 tmp; 203 int ret; 204 205 ret = amd_get_highest_perf(cpu, &tmp); 206 if (ret) 207 return ret; 208 209 if (!count || (count == 1 && tmp != highest_perf[0])) 210 highest_perf[count++] = tmp; 211 212 if (count == 2) 213 break; 214 } 215 216 *detected = (count == 2); 217 boost_numerator = highest_perf[0]; 218 219 amd_pref_core_detected = *detected ? AMD_PREF_CORE_SUPPORTED : 220 AMD_PREF_CORE_UNSUPPORTED; 221 222 pr_debug("AMD CPPC preferred core is %ssupported (highest perf: 0x%llx)\n", 223 *detected ? "" : "un", highest_perf[0]); 224 225 return 0; 226 } 227 EXPORT_SYMBOL_GPL(amd_detect_prefcore); 228 229 /** 230 * amd_get_effective_highest_perf: Get the effective highest performance value 231 * @cpu: CPU to get highest performance for. 232 * 233 * Get the effective highest performance value for a CPU, accounting for 234 * preferred cores and heterogeneous topologies. On systems with preferred 235 * cores, this may be a hardcoded value. On heterogeneous systems, this 236 * may be a per-CPU value. On other systems, this is the shared highest 237 * performance value. 238 * 239 * Return: Effective highest performance value, or negative error code. 240 */ 241 int amd_get_effective_highest_perf(unsigned int cpu) 242 { 243 bool prefcore; 244 int ret; 245 u32 tmp; 246 247 ret = amd_detect_prefcore(&prefcore); 248 if (ret < 0) 249 return ret; 250 251 /* without preferred cores, return the highest perf register value */ 252 if (!prefcore) 253 return boost_numerator; 254 255 /* 256 * For AMD CPUs with Family ID 19H and Model ID range 0x70 to 0x7f, 257 * the highest performance level is set to 196. 258 * https://bugzilla.kernel.org/show_bug.cgi?id=218759 259 */ 260 if (cpu_feature_enabled(X86_FEATURE_ZEN4)) { 261 switch (boot_cpu_data.x86_model) { 262 case 0x70 ... 0x7f: 263 return CPPC_HIGHEST_PERF_PERFORMANCE; 264 default: 265 break; 266 } 267 } 268 269 /* detect if running on heterogeneous design */ 270 if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) { 271 if (cpu_feature_enabled(X86_FEATURE_ZEN5) && 272 cpu_data(cpu).topo.cpu_type == TOPO_CPU_TYPE_PERFORMANCE) 273 return CPPC_HIGHEST_PERF_PERFORMANCE; 274 275 /* Zen 5 efficiency, and Zen 6+ */ 276 ret = amd_get_highest_perf(cpu, &tmp); 277 if (ret < 0) 278 return ret; 279 280 return tmp; 281 } 282 283 return CPPC_HIGHEST_PERF_PREFCORE; 284 } 285 EXPORT_SYMBOL_GPL(amd_get_effective_highest_perf); 286 287 struct amd_max_freq { 288 u32 performance; 289 u32 efficiency; 290 u32 low_power; 291 }; 292 293 static const struct amd_max_freq max_freq_zen6_client = { 294 .performance = 5025, 295 .efficiency = 3524, 296 .low_power = 2399, 297 }; 298 299 int amd_get_max_frequency(unsigned int cpu) 300 { 301 enum x86_topology_cpu_type type = cpu_data(cpu).topo.cpu_type; 302 const struct amd_max_freq *max_freq = NULL; 303 304 if (cpu_feature_enabled(X86_FEATURE_ZEN6) && 305 cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) 306 max_freq = &max_freq_zen6_client; 307 308 if (!max_freq) 309 return 0; 310 311 switch (type) { 312 case TOPO_CPU_TYPE_PERFORMANCE: 313 return max_freq->performance; 314 case TOPO_CPU_TYPE_EFFICIENCY: 315 return max_freq->efficiency; 316 case TOPO_CPU_TYPE_LOW_POWER: 317 return max_freq->low_power; 318 default: 319 break; 320 } 321 322 return 0; 323 } 324 EXPORT_SYMBOL_GPL(amd_get_max_frequency); 325 326 /** 327 * amd_get_boost_ratio: Get numerator and denominator for boost ratio 328 * @cpu: CPU to get the boost ratio for. 329 * @numerator: Output variable for numerator. 330 * @denominator: Output variable for denominator. 331 * 332 * Get the numerator and denominator for calculating the boost ratio. 333 * 334 * Return: 0 for success, negative error code otherwise. 335 */ 336 int amd_get_boost_ratio(unsigned int cpu, u64 *numerator, u64 *denominator) 337 { 338 struct cppc_perf_caps perf_caps; 339 int max_frequency; 340 int ret; 341 342 ret = cppc_get_perf_caps(cpu, &perf_caps); 343 if (ret) 344 return ret; 345 346 max_frequency = amd_get_max_frequency(cpu); 347 /* Use frequency values if available */ 348 if (max_frequency && perf_caps.nominal_freq) { 349 *numerator = max_frequency; 350 *denominator = perf_caps.nominal_freq; 351 return 0; 352 } 353 354 /* Fall back to performance values */ 355 ret = amd_get_effective_highest_perf(cpu); 356 if (ret < 0) 357 return ret; 358 359 *numerator = ret; 360 361 *denominator = perf_caps.nominal_perf; 362 if (!*denominator) 363 return -EINVAL; 364 365 return 0; 366 } 367 EXPORT_SYMBOL_GPL(amd_get_boost_ratio); 368