Merge branch 'for-next/cpufreq' into for-next/core

* for-next/cpufreq:
  arm64: topology: Do not warn on missing AMU in cpuhp_topology_online()
  arm64: topology: Handle AMU FIE setup on CPU hotplug
  cpufreq: Add new helper function returning cpufreq policy
  arm64: topology: Skip already covered CPUs when setting freq source
master
Will Deacon 2026-01-29 12:05:25 +00:00
commit c2581836cc
4 changed files with 82 additions and 4 deletions

View File

@ -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));
@ -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,70 @@ 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)) {
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);

View File

@ -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)

View File

@ -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);

View File

@ -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;