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

arm64: topology: Fix false warning in counters_read_on_cpu() for same-CPU reads

The counters_read_on_cpu() function warns when called with IRQs
disabled to prevent deadlock in smp_call_function_single(). However,
this warning is spurious when reading counters on the current CPU,
since no IPI is needed for same CPU reads.

Commit 12eb8f4fff24 ("cpufreq: CPPC: Update FIE arch_freq_scale in
ticks for non-PCC regs") changed the CPPC Frequency Invariance Engine
to read AMU counters directly from the scheduler tick for non-PCC
register spaces (like FFH), instead of deferring to a kthread. This
means counters_read_on_cpu() is now called with IRQs disabled from the
tick handler, triggering the warning.

Fix this by restructuring the logic: when IRQs are disabled (tick
context), call the function directly for same-CPU reads. Otherwise
use smp_call_function_single().

Fixes: 997c021abc6e ("cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs")
Suggested-by: Will Deacon <will@kernel.org>
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Sumit Gupta and committed by
Will Deacon
df6e4ab6 e5cb94ba

+15 -6
+15 -6
arch/arm64/kernel/topology.c
··· 400 400 int counters_read_on_cpu(int cpu, smp_call_func_t func, u64 *val) 401 401 { 402 402 /* 403 - * Abort call on counterless CPU or when interrupts are 404 - * disabled - can lead to deadlock in smp sync call. 403 + * Abort call on counterless CPU. 405 404 */ 406 405 if (!cpu_has_amu_feat(cpu)) 407 406 return -EOPNOTSUPP; 408 407 409 - if (WARN_ON_ONCE(irqs_disabled())) 410 - return -EPERM; 411 - 412 - smp_call_function_single(cpu, func, val, 1); 408 + if (irqs_disabled()) { 409 + /* 410 + * When IRQs are disabled (tick path: sched_tick -> 411 + * topology_scale_freq_tick or cppc_scale_freq_tick), only local 412 + * CPU counter reads are allowed. Remote CPU counter read would 413 + * require smp_call_function_single() which is unsafe with IRQs 414 + * disabled. 415 + */ 416 + if (WARN_ON_ONCE(cpu != smp_processor_id())) 417 + return -EPERM; 418 + func(val); 419 + } else { 420 + smp_call_function_single(cpu, func, val, 1); 421 + } 413 422 414 423 return 0; 415 424 }