Skip to content

Commit 6fd9be0

Browse files
Lifeng Zhengwilldeacon
authored andcommitted
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 <zhenglifeng1@huawei.com> Acked-by: Beata Michalska <beata.michalska@arm.com> Signed-off-by: Will Deacon <will@kernel.org>
1 parent 4221504 commit 6fd9be0

2 files changed

Lines changed: 71 additions & 3 deletions

File tree

arch/arm64/kernel/topology.c

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val,
284284
struct cpufreq_policy *policy = data;
285285

286286
if (val == CPUFREQ_CREATE_POLICY)
287-
amu_fie_setup(policy->related_cpus);
287+
amu_fie_setup(policy->cpus);
288288

289289
/*
290290
* 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 = {
303303
.notifier_call = init_amu_fie_callback,
304304
};
305305

306+
static int cpuhp_topology_online(unsigned int cpu)
307+
{
308+
struct cpufreq_policy *policy = cpufreq_cpu_policy(cpu);
309+
310+
/* Those are cheap checks */
311+
312+
/*
313+
* Skip this CPU if:
314+
* - it has no cpufreq policy assigned yet,
315+
* - no policy exists that spans CPUs with AMU counters, or
316+
* - it was already handled.
317+
*/
318+
if (unlikely(!policy) || !cpumask_available(amu_fie_cpus) ||
319+
cpumask_test_cpu(cpu, amu_fie_cpus))
320+
return 0;
321+
322+
/*
323+
* Only proceed if all already-online CPUs in this policy
324+
* support AMU counters.
325+
*/
326+
if (unlikely(!cpumask_subset(policy->cpus, amu_fie_cpus)))
327+
return 0;
328+
329+
/*
330+
* If the new online CPU cannot pass this check, all the CPUs related to
331+
* the same policy should be clear from amu_fie_cpus mask, otherwise they
332+
* may use different source of the freq scale.
333+
*/
334+
if (!freq_counters_valid(cpu)) {
335+
pr_warn("CPU[%u] doesn't support AMU counters\n", cpu);
336+
topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_ARCH,
337+
policy->related_cpus);
338+
cpumask_andnot(amu_fie_cpus, amu_fie_cpus, policy->related_cpus);
339+
return 0;
340+
}
341+
342+
cpumask_set_cpu(cpu, amu_fie_cpus);
343+
344+
topology_set_scale_freq_source(&amu_sfd, cpumask_of(cpu));
345+
346+
pr_debug("CPU[%u]: counter will be used for FIE.", cpu);
347+
348+
return 0;
349+
}
350+
306351
static int __init init_amu_fie(void)
307352
{
308-
return cpufreq_register_notifier(&init_amu_fie_notifier,
353+
int ret;
354+
355+
ret = cpufreq_register_notifier(&init_amu_fie_notifier,
309356
CPUFREQ_POLICY_NOTIFIER);
357+
if (ret)
358+
return ret;
359+
360+
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
361+
"arm64/topology:online",
362+
cpuhp_topology_online,
363+
NULL);
364+
if (ret < 0) {
365+
cpufreq_unregister_notifier(&init_amu_fie_notifier,
366+
CPUFREQ_POLICY_NOTIFIER);
367+
return ret;
368+
}
369+
370+
return 0;
310371
}
311372
core_initcall(init_amu_fie);
312373

drivers/base/arch_topology.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ EXPORT_PER_CPU_SYMBOL_GPL(capacity_freq_ref);
3434

3535
static bool supports_scale_freq_counters(const struct cpumask *cpus)
3636
{
37-
return cpumask_subset(cpus, &scale_freq_counters_mask);
37+
int i;
38+
39+
for_each_cpu(i, cpus) {
40+
if (cpumask_test_cpu(i, &scale_freq_counters_mask))
41+
return true;
42+
}
43+
44+
return false;
3845
}
3946

4047
bool topology_scale_freq_invariant(void)

0 commit comments

Comments
 (0)