Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/aperfmperf: Untangle Intel and AMD frequency invariance init

AMD boot CPU initialization happens late via ACPI/CPPC which prevents the
Intel parts from being marked __init.

Split out the common code and provide a dedicated interface for the AMD
initialization and mark the Intel specific code and data __init.

The remaining text size is almost cut in half:

text: 2614 -> 1350
init.text: 0 -> 786

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Paul E. McKenney <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20220415161206.592465719@linutronix.de

+52 -57
+4 -9
arch/x86/include/asm/topology.h
··· 216 216 #define arch_scale_freq_tick arch_scale_freq_tick 217 217 218 218 extern void arch_set_max_freq_ratio(bool turbo_disabled); 219 - extern void bp_init_freq_invariance(bool cppc_ready); 219 + extern void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled); 220 + extern void bp_init_freq_invariance(void); 220 221 extern void ap_init_freq_invariance(void); 221 222 #else 222 223 static inline void arch_set_max_freq_ratio(bool turbo_disabled) { } 223 - static inline void bp_init_freq_invariance(bool cppc_ready) { } 224 + static inline void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled) { } 225 + static inline void bp_init_freq_invariance(void) { } 224 226 static inline void ap_init_freq_invariance(void) { } 225 227 #endif 226 228 227 229 #ifdef CONFIG_ACPI_CPPC_LIB 228 230 void init_freq_invariance_cppc(void); 229 231 #define arch_init_invariance_cppc init_freq_invariance_cppc 230 - 231 - bool amd_set_max_freq_ratio(u64 *ratio); 232 - #else 233 - static inline bool amd_set_max_freq_ratio(u64 *ratio) 234 - { 235 - return false; 236 - } 237 232 #endif 238 233 239 234 #endif /* _ASM_X86_TOPOLOGY_H */
+15 -17
arch/x86/kernel/acpi/cppc.c
··· 50 50 return err; 51 51 } 52 52 53 - bool amd_set_max_freq_ratio(u64 *ratio) 53 + static void amd_set_max_freq_ratio(void) 54 54 { 55 55 struct cppc_perf_caps perf_caps; 56 56 u64 highest_perf, nominal_perf; 57 57 u64 perf_ratio; 58 58 int rc; 59 59 60 - if (!ratio) 61 - return false; 62 - 63 60 rc = cppc_get_perf_caps(0, &perf_caps); 64 61 if (rc) { 65 62 pr_debug("Could not retrieve perf counters (%d)\n", rc); 66 - return false; 63 + return; 67 64 } 68 65 69 66 highest_perf = amd_get_highest_perf(); ··· 68 71 69 72 if (!highest_perf || !nominal_perf) { 70 73 pr_debug("Could not retrieve highest or nominal performance\n"); 71 - return false; 74 + return; 72 75 } 73 76 74 77 perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf); ··· 76 79 perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1; 77 80 if (!perf_ratio) { 78 81 pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n"); 79 - return false; 82 + return; 80 83 } 81 84 82 - *ratio = perf_ratio; 83 - arch_set_max_freq_ratio(false); 84 - 85 - return true; 85 + freq_invariance_set_perf_ratio(perf_ratio, false); 86 86 } 87 87 88 88 static DEFINE_MUTEX(freq_invariance_lock); 89 89 90 90 void init_freq_invariance_cppc(void) 91 91 { 92 - static bool secondary; 92 + static bool init_done; 93 + 94 + if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 95 + return; 96 + 97 + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 98 + return; 93 99 94 100 mutex_lock(&freq_invariance_lock); 95 - 96 - if (!secondary) 97 - bp_init_freq_invariance(true); 98 - secondary = true; 99 - 101 + if (!init_done) 102 + amd_set_max_freq_ratio(); 103 + init_done = true; 100 104 mutex_unlock(&freq_invariance_lock); 101 105 }
+32 -30
arch/x86/kernel/cpu/aperfmperf.c
··· 206 206 } 207 207 EXPORT_SYMBOL_GPL(arch_set_max_freq_ratio); 208 208 209 - static bool turbo_disabled(void) 209 + static bool __init turbo_disabled(void) 210 210 { 211 211 u64 misc_en; 212 212 int err; ··· 218 218 return (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE); 219 219 } 220 220 221 - static bool slv_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq) 221 + static bool __init slv_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq) 222 222 { 223 223 int err; 224 224 ··· 240 240 X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \ 241 241 INTEL_FAM6_##model, X86_FEATURE_APERFMPERF, NULL) 242 242 243 - static const struct x86_cpu_id has_knl_turbo_ratio_limits[] = { 243 + static const struct x86_cpu_id has_knl_turbo_ratio_limits[] __initconst = { 244 244 X86_MATCH(XEON_PHI_KNL), 245 245 X86_MATCH(XEON_PHI_KNM), 246 246 {} 247 247 }; 248 248 249 - static const struct x86_cpu_id has_skx_turbo_ratio_limits[] = { 249 + static const struct x86_cpu_id has_skx_turbo_ratio_limits[] __initconst = { 250 250 X86_MATCH(SKYLAKE_X), 251 251 {} 252 252 }; 253 253 254 - static const struct x86_cpu_id has_glm_turbo_ratio_limits[] = { 254 + static const struct x86_cpu_id has_glm_turbo_ratio_limits[] __initconst = { 255 255 X86_MATCH(ATOM_GOLDMONT), 256 256 X86_MATCH(ATOM_GOLDMONT_D), 257 257 X86_MATCH(ATOM_GOLDMONT_PLUS), 258 258 {} 259 259 }; 260 260 261 - static bool knl_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq, 262 - int num_delta_fratio) 261 + static bool __init knl_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq, 262 + int num_delta_fratio) 263 263 { 264 264 int fratio, delta_fratio, found; 265 265 int err, i; ··· 297 297 return true; 298 298 } 299 299 300 - static bool skx_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq, int size) 300 + static bool __init skx_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq, int size) 301 301 { 302 302 u64 ratios, counts; 303 303 u32 group_size; ··· 328 328 return false; 329 329 } 330 330 331 - static bool core_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq) 331 + static bool __init core_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq) 332 332 { 333 333 u64 msr; 334 334 int err; ··· 351 351 return true; 352 352 } 353 353 354 - static bool intel_set_max_freq_ratio(void) 354 + static bool __init intel_set_max_freq_ratio(void) 355 355 { 356 356 u64 base_freq, turbo_freq; 357 357 u64 turbo_ratio; ··· 418 418 419 419 static void register_freq_invariance_syscore_ops(void) 420 420 { 421 - /* Bail out if registered already. */ 422 - if (freq_invariance_syscore_ops.node.prev) 423 - return; 424 - 425 421 register_syscore_ops(&freq_invariance_syscore_ops); 426 422 } 427 423 #else 428 424 static inline void register_freq_invariance_syscore_ops(void) {} 429 425 #endif 430 426 431 - void bp_init_freq_invariance(bool cppc_ready) 427 + static void freq_invariance_enable(void) 432 428 { 433 - bool ret; 429 + if (static_branch_unlikely(&arch_scale_freq_key)) { 430 + WARN_ON_ONCE(1); 431 + return; 432 + } 433 + static_branch_enable(&arch_scale_freq_key); 434 + register_freq_invariance_syscore_ops(); 435 + pr_info("Estimated ratio of average max frequency by base frequency (times 1024): %llu\n", arch_max_freq_ratio); 436 + } 434 437 438 + void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled) 439 + { 440 + arch_turbo_freq_ratio = ratio; 441 + arch_set_max_freq_ratio(turbo_disabled); 442 + freq_invariance_enable(); 443 + } 444 + 445 + void __init bp_init_freq_invariance(void) 446 + { 435 447 if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 436 448 return; 437 449 438 450 init_counter_refs(); 439 451 440 - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) 441 - ret = intel_set_max_freq_ratio(); 442 - else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { 443 - if (!cppc_ready) 444 - return; 445 - ret = amd_set_max_freq_ratio(&arch_turbo_freq_ratio); 446 - } 452 + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 453 + return; 447 454 448 - if (ret) { 449 - static_branch_enable(&arch_scale_freq_key); 450 - register_freq_invariance_syscore_ops(); 451 - pr_info("Estimated ratio of average max frequency by base frequency (times 1024): %llu\n", arch_max_freq_ratio); 452 - } else { 453 - pr_debug("Couldn't determine max cpu frequency, necessary for scale-invariant accounting.\n"); 454 - } 455 + if (intel_set_max_freq_ratio()) 456 + freq_invariance_enable(); 455 457 } 456 458 457 459 void ap_init_freq_invariance(void)
+1 -1
arch/x86/kernel/smpboot.c
··· 1396 1396 { 1397 1397 smp_prepare_cpus_common(); 1398 1398 1399 - bp_init_freq_invariance(false); 1399 + bp_init_freq_invariance(); 1400 1400 smp_sanity_check(); 1401 1401 1402 1402 switch (apic_intr_mode) {