* [PATCH] cpufreq: Avoid fallback values in cpuinfo_avg_freq
@ 2026-10-19 6:53 Jackie Liu
0 siblings, 0 replies; only message in thread
From: Jackie Liu @ 2026-10-19 6:53 UTC (permalink / raw)
To: tglx; +Cc: mingo, bp, dave.hansen, x86, linux-pm
From: Jackie Liu <liuyun01@kylinos.cn>
On x86, arch_freq_get_on_cpu() can return the requested or nominal
frequency when hardware feedback is unavailable. cpuinfo_avg_freq then
reports fallback values as hardware averages, even without APERF/MPERF.
Use a separate sampling hook for the attribute and its support probe:
return -EOPNOTSUPP without APERF/MPERF and -EAGAIN for zero MPERF deltas
or stale samples. Preserve the scaling_cur_freq and /proc/cpuinfo fallback
and the existing ARM64 AMU implementation.
Fixes: fbb4a4759b54 ("cpufreq: Introduce an optional cpuinfo_avg_freq sysfs entry")
Signed-off-by: Jackie Liu <liuyun01@kylinos.cn>
---
arch/x86/kernel/cpu/aperfmperf.c | 18 +++++++++++++-----
drivers/cpufreq/cpufreq.c | 9 +++++++--
include/linux/cpufreq.h | 1 +
3 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kernel/cpu/aperfmperf.c b/arch/x86/kernel/cpu/aperfmperf.c
index 7ffc78d5ebf2..fa8376d9ce94 100644
--- a/arch/x86/kernel/cpu/aperfmperf.c
+++ b/arch/x86/kernel/cpu/aperfmperf.c
@@ -503,15 +503,15 @@ void arch_scale_freq_tick(void)
*/
#define MAX_SAMPLE_AGE ((unsigned long)HZ / 50)
-int arch_freq_get_on_cpu(int cpu)
+int arch_freq_get_avg_on_cpu(int cpu)
{
struct aperfmperf *s = per_cpu_ptr(&cpu_samples, cpu);
- unsigned int seq, freq;
+ unsigned int seq;
unsigned long last;
u64 acnt, mcnt;
if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF))
- goto fallback;
+ return -EOPNOTSUPP;
do {
seq = raw_read_seqcount_begin(&s->seq);
@@ -525,11 +525,19 @@ int arch_freq_get_on_cpu(int cpu)
* which covers idle and NOHZ full CPUs.
*/
if (!mcnt || (jiffies - last) > MAX_SAMPLE_AGE)
- goto fallback;
+ return -EAGAIN;
return div64_u64((cpu_khz * acnt), mcnt);
+}
+
+int arch_freq_get_on_cpu(int cpu)
+{
+ int avg_freq = arch_freq_get_avg_on_cpu(cpu);
+ unsigned int freq;
+
+ if (avg_freq >= 0)
+ return avg_freq;
-fallback:
freq = cpufreq_quick_get(cpu);
return freq ? freq : cpu_khz;
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 54dde8419bdc..2e44b6ee14c9 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -705,9 +705,14 @@ __weak int arch_freq_get_on_cpu(int cpu)
return -EOPNOTSUPP;
}
+__weak int arch_freq_get_avg_on_cpu(int cpu)
+{
+ return arch_freq_get_on_cpu(cpu);
+}
+
static inline bool cpufreq_avg_freq_supported(struct cpufreq_policy *policy)
{
- return arch_freq_get_on_cpu(policy->cpu) != -EOPNOTSUPP;
+ return arch_freq_get_avg_on_cpu(policy->cpu) != -EOPNOTSUPP;
}
static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf)
@@ -769,7 +774,7 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
static ssize_t show_cpuinfo_avg_freq(struct cpufreq_policy *policy,
char *buf)
{
- int avg_freq = arch_freq_get_on_cpu(policy->cpu);
+ int avg_freq = arch_freq_get_avg_on_cpu(policy->cpu);
if (avg_freq > 0)
return sysfs_emit(buf, "%u\n", avg_freq);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index d3d0d9d02aa4..925a3d3b6c31 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -1228,6 +1228,7 @@ static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_
#endif
extern int arch_freq_get_on_cpu(int cpu);
+extern int arch_freq_get_avg_on_cpu(int cpu);
#ifndef arch_set_freq_scale
static __always_inline
--
2.56.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-19 6:54 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19 6:53 [PATCH] cpufreq: Avoid fallback values in cpuinfo_avg_freq Jackie Liu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox