From af15bc259e260cbe5221c220d56a716b6facf155 Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Wed, 19 Nov 2025 16:13:54 +0800 Subject: [PATCH 1/4] arm64: topology: Skip already covered CPUs when setting freq source The scale freq source of the CPUs in 'amu_fie_cpus' mask are already set to AMU tick before, so in amu_fie_setup(), only the CPUs in the 'cpus' mask should be set. Signed-off-by: Lifeng Zheng Reviewed-by: Beata Michalska Reviewed-by: Jie Zhan Acked-by: Beata Michalska Signed-off-by: Will Deacon --- arch/arm64/kernel/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 5d24dc53799b..cf9bb761af3a 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -272,7 +272,7 @@ static void amu_fie_setup(const struct cpumask *cpus) cpumask_or(amu_fie_cpus, amu_fie_cpus, cpus); - topology_set_scale_freq_source(&amu_sfd, amu_fie_cpus); + topology_set_scale_freq_source(&amu_sfd, cpus); pr_debug("CPUs[%*pbl]: counters will be used for FIE.", cpumask_pr_args(cpus)); From 4221504c4328d4d9e57962bf530fa52913591139 Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Wed, 19 Nov 2025 16:13:55 +0800 Subject: [PATCH 2/4] cpufreq: Add new helper function returning cpufreq policy cpufreq_cpu_get_raw() gets cpufreq policy only if the CPU is in policy->cpus mask, which means the CPU is already online. But in some cases, the policy is needed before the CPU is added to cpus mask. Add a function to get the policy in these cases. Signed-off-by: Lifeng Zheng Reviewed-by: Rafael J. Wysocki (Intel) Reviewed-by: Jie Zhan Acked-by: Beata Michalska Signed-off-by: Will Deacon --- drivers/cpufreq/cpufreq.c | 6 ++++++ include/linux/cpufreq.h | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 4472bb1ec83c..076c8eb5db37 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -198,6 +198,12 @@ struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu) } EXPORT_SYMBOL_GPL(cpufreq_cpu_get_raw); +struct cpufreq_policy *cpufreq_cpu_policy(unsigned int cpu) +{ + return per_cpu(cpufreq_cpu_data, cpu); +} +EXPORT_SYMBOL_GPL(cpufreq_cpu_policy); + unsigned int cpufreq_generic_get(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 0465d1e6f72a..cc894fc38971 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -203,6 +203,7 @@ struct cpufreq_freqs { #ifdef CONFIG_CPU_FREQ struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu); +struct cpufreq_policy *cpufreq_cpu_policy(unsigned int cpu); struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu); void cpufreq_cpu_put(struct cpufreq_policy *policy); #else @@ -210,6 +211,10 @@ static inline struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu) { return NULL; } +static inline struct cpufreq_policy *cpufreq_cpu_policy(unsigned int cpu) +{ + return NULL; +} static inline struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) { return NULL; From 6fd9be0b7b2e957d24b0490b989658c4d18d92c7 Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Wed, 19 Nov 2025 16:13:56 +0800 Subject: [PATCH 3/4] arm64: topology: Handle AMU FIE setup on CPU hotplug Currently, when a cpufreq policy is created, the AMU FIE setup process checks all CPUs in the policy -- including those that are offline. If any of these CPUs are offline at that time, their AMU capability flag hasn't been verified yet, leading the check fail. As a result, AMU FIE is not enabled, even if the CPUs that are online do support it. Later, when the previously offline CPUs come online and report AMU support, there's no mechanism in place to re-enable AMU FIE for the policy. This leaves the entire frequency domain without AMU FIE, despite being eligible. Restrict the initial AMU FIE check to only those CPUs that are online at the time the policy is created, and allow CPUs that come online later to join the policy with AMU FIE enabled. Signed-off-by: Lifeng Zheng Acked-by: Beata Michalska Signed-off-by: Will Deacon --- arch/arm64/kernel/topology.c | 65 ++++++++++++++++++++++++++++++++++-- drivers/base/arch_topology.c | 9 ++++- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index cf9bb761af3a..539b38935182 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -284,7 +284,7 @@ static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val, struct cpufreq_policy *policy = data; if (val == CPUFREQ_CREATE_POLICY) - amu_fie_setup(policy->related_cpus); + amu_fie_setup(policy->cpus); /* * We don't need to handle CPUFREQ_REMOVE_POLICY event as the AMU @@ -303,10 +303,71 @@ static struct notifier_block init_amu_fie_notifier = { .notifier_call = init_amu_fie_callback, }; +static int cpuhp_topology_online(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_policy(cpu); + + /* Those are cheap checks */ + + /* + * Skip this CPU if: + * - it has no cpufreq policy assigned yet, + * - no policy exists that spans CPUs with AMU counters, or + * - it was already handled. + */ + if (unlikely(!policy) || !cpumask_available(amu_fie_cpus) || + cpumask_test_cpu(cpu, amu_fie_cpus)) + return 0; + + /* + * Only proceed if all already-online CPUs in this policy + * support AMU counters. + */ + if (unlikely(!cpumask_subset(policy->cpus, amu_fie_cpus))) + return 0; + + /* + * If the new online CPU cannot pass this check, all the CPUs related to + * the same policy should be clear from amu_fie_cpus mask, otherwise they + * may use different source of the freq scale. + */ + if (!freq_counters_valid(cpu)) { + pr_warn("CPU[%u] doesn't support AMU counters\n", cpu); + topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_ARCH, + policy->related_cpus); + cpumask_andnot(amu_fie_cpus, amu_fie_cpus, policy->related_cpus); + return 0; + } + + cpumask_set_cpu(cpu, amu_fie_cpus); + + topology_set_scale_freq_source(&amu_sfd, cpumask_of(cpu)); + + pr_debug("CPU[%u]: counter will be used for FIE.", cpu); + + return 0; +} + static int __init init_amu_fie(void) { - return cpufreq_register_notifier(&init_amu_fie_notifier, + int ret; + + ret = cpufreq_register_notifier(&init_amu_fie_notifier, CPUFREQ_POLICY_NOTIFIER); + if (ret) + return ret; + + ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "arm64/topology:online", + cpuhp_topology_online, + NULL); + if (ret < 0) { + cpufreq_unregister_notifier(&init_amu_fie_notifier, + CPUFREQ_POLICY_NOTIFIER); + return ret; + } + + return 0; } core_initcall(init_amu_fie); diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 84ec92bff642..c0ef6ea9c111 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -34,7 +34,14 @@ EXPORT_PER_CPU_SYMBOL_GPL(capacity_freq_ref); static bool supports_scale_freq_counters(const struct cpumask *cpus) { - return cpumask_subset(cpus, &scale_freq_counters_mask); + int i; + + for_each_cpu(i, cpus) { + if (cpumask_test_cpu(i, &scale_freq_counters_mask)) + return true; + } + + return false; } bool topology_scale_freq_invariant(void) From 747d5b6735caa0178b3f1c922cfa9c285b093f22 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 15 Jan 2026 09:51:45 +0100 Subject: [PATCH 4/4] arm64: topology: Do not warn on missing AMU in cpuhp_topology_online() When CONFIG_CPUMASK_OFFSTACK is not enabled, and resuming from s2ram on Renesas R-Car H3 (big.LITTLE 4x Cortex-A57 + 4x Cortex-A53), during enabling of the first little core, a warning message is printed: AMU: CPU[4] doesn't support AMU counters This confuses users, as during boot amu_fie_setup() does not print such a message, unless debugging is enabled (freq_counters_valid() prints "CPU%d: counters are not supported.\n" at debug level in that case). Hence drop the warning, freq_counters_valid() has already printed a debug message anyway. Fixes: 6fd9be0b7b2e ("arm64: topology: Handle AMU FIE setup on CPU hotplug") Signed-off-by: Geert Uytterhoeven Reviewed-by: Lifeng Zheng Signed-off-by: Will Deacon --- arch/arm64/kernel/topology.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 539b38935182..3fe1faab0362 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -332,7 +332,6 @@ static int cpuhp_topology_online(unsigned int cpu) * may use different source of the freq scale. */ if (!freq_counters_valid(cpu)) { - pr_warn("CPU[%u] doesn't support AMU counters\n", cpu); topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_ARCH, policy->related_cpus); cpumask_andnot(amu_fie_cpus, amu_fie_cpus, policy->related_cpus);