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

x86/aperfmperf: Make parts of the frequency invariance code unconditional

The frequency invariance support is currently limited to x86/64 and SMP,
which is the vast majority of machines.

arch_scale_freq_tick() is called every tick on all CPUs and reads the APERF
and MPERF MSRs. The CPU frequency getters function do the same via dedicated
IPIs.

While it could be argued that on systems where frequency invariance support
is disabled (32bit, !SMP) the per tick read of the APERF and MPERF MSRs can
be avoided, it does not make sense to keep the extra code and the resulting
runtime issues of mass IPIs around.

As a first step split out the non frequency invariance specific
initialization code and the read MSR portion of arch_scale_freq_tick(). The
rest of the code is still conditional and guarded with a static key.

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.761988704@linutronix.de

+41 -31
+2
arch/x86/include/asm/cpu.h
··· 36 36 #endif 37 37 #endif 38 38 39 + extern void ap_init_aperfmperf(void); 40 + 39 41 int mwait_usable(const struct cpuinfo_x86 *); 40 42 41 43 unsigned int x86_family(unsigned int sig);
-4
arch/x86/include/asm/topology.h
··· 217 217 218 218 extern void arch_set_max_freq_ratio(bool turbo_disabled); 219 219 extern void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled); 220 - extern void bp_init_freq_invariance(void); 221 - extern void ap_init_freq_invariance(void); 222 220 #else 223 221 static inline void arch_set_max_freq_ratio(bool turbo_disabled) { } 224 222 static inline void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled) { } 225 - static inline void bp_init_freq_invariance(void) { } 226 - static inline void ap_init_freq_invariance(void) { } 227 223 #endif 228 224 229 225 #ifdef CONFIG_ACPI_CPPC_LIB
+38 -25
arch/x86/kernel/cpu/aperfmperf.c
··· 17 17 #include <linux/smp.h> 18 18 #include <linux/syscore_ops.h> 19 19 20 + #include <asm/cpu.h> 20 21 #include <asm/cpu_device_id.h> 21 22 #include <asm/intel-family.h> 22 23 ··· 163 162 smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1); 164 163 165 164 return per_cpu(samples.khz, cpu); 165 + } 166 + 167 + static void init_counter_refs(void) 168 + { 169 + u64 aperf, mperf; 170 + 171 + rdmsrl(MSR_IA32_APERF, aperf); 172 + rdmsrl(MSR_IA32_MPERF, mperf); 173 + 174 + this_cpu_write(cpu_samples.aperf, aperf); 175 + this_cpu_write(cpu_samples.mperf, mperf); 166 176 } 167 177 168 178 #if defined(CONFIG_X86_64) && defined(CONFIG_SMP) ··· 417 405 return true; 418 406 } 419 407 420 - static void init_counter_refs(void) 421 - { 422 - u64 aperf, mperf; 423 - 424 - rdmsrl(MSR_IA32_APERF, aperf); 425 - rdmsrl(MSR_IA32_MPERF, mperf); 426 - 427 - this_cpu_write(cpu_samples.aperf, aperf); 428 - this_cpu_write(cpu_samples.mperf, mperf); 429 - } 430 - 431 408 #ifdef CONFIG_PM_SLEEP 432 409 static struct syscore_ops freq_invariance_syscore_ops = { 433 410 .resume = init_counter_refs, ··· 448 447 freq_invariance_enable(); 449 448 } 450 449 451 - void __init bp_init_freq_invariance(void) 450 + static void __init bp_init_freq_invariance(void) 452 451 { 453 - if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 454 - return; 455 - 456 - init_counter_refs(); 457 - 458 452 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 459 453 return; 460 454 461 455 if (intel_set_max_freq_ratio()) 462 456 freq_invariance_enable(); 463 - } 464 - 465 - void ap_init_freq_invariance(void) 466 - { 467 - if (cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 468 - init_counter_refs(); 469 457 } 470 458 471 459 static void disable_freq_invariance_workfn(struct work_struct *work) ··· 470 480 static void scale_freq_tick(u64 acnt, u64 mcnt) 471 481 { 472 482 u64 freq_scale; 483 + 484 + if (!arch_scale_freq_invariant()) 485 + return; 473 486 474 487 if (check_shl_overflow(acnt, 2*SCHED_CAPACITY_SHIFT, &acnt)) 475 488 goto error; ··· 494 501 pr_warn("Scheduler frequency invariance went wobbly, disabling!\n"); 495 502 schedule_work(&disable_freq_invariance_work); 496 503 } 504 + #else 505 + static inline void bp_init_freq_invariance(void) { } 506 + static inline void scale_freq_tick(u64 acnt, u64 mcnt) { } 507 + #endif /* CONFIG_X86_64 && CONFIG_SMP */ 497 508 498 509 void arch_scale_freq_tick(void) 499 510 { 500 511 struct aperfmperf *s = this_cpu_ptr(&cpu_samples); 501 512 u64 acnt, mcnt, aperf, mperf; 502 513 503 - if (!arch_scale_freq_invariant()) 514 + if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 504 515 return; 505 516 506 517 rdmsrl(MSR_IA32_APERF, aperf); ··· 517 520 518 521 scale_freq_tick(acnt, mcnt); 519 522 } 520 - #endif /* CONFIG_X86_64 && CONFIG_SMP */ 523 + 524 + static int __init bp_init_aperfmperf(void) 525 + { 526 + if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 527 + return 0; 528 + 529 + init_counter_refs(); 530 + bp_init_freq_invariance(); 531 + return 0; 532 + } 533 + early_initcall(bp_init_aperfmperf); 534 + 535 + void ap_init_aperfmperf(void) 536 + { 537 + if (cpu_feature_enabled(X86_FEATURE_APERFMPERF)) 538 + init_counter_refs(); 539 + }
+1 -2
arch/x86/kernel/smpboot.c
··· 186 186 */ 187 187 set_cpu_sibling_map(raw_smp_processor_id()); 188 188 189 - ap_init_freq_invariance(); 189 + ap_init_aperfmperf(); 190 190 191 191 /* 192 192 * Get our bogomips. ··· 1396 1396 { 1397 1397 smp_prepare_cpus_common(); 1398 1398 1399 - bp_init_freq_invariance(); 1400 1399 smp_sanity_check(); 1401 1400 1402 1401 switch (apic_intr_mode) {