Skip to content

Commit 7a88444

Browse files
Yicong Yangwilldeacon
authored andcommitted
arm64/watchdog_hld: Add a cpufreq notifier for update watchdog thresh
arm64 depends on the cpufreq driver to gain the maximum cpu frequency to convert the watchdog_thresh to perf event period. cpufreq drivers like cppc_cpufreq will be initialized lately after the initializing of the hard lockup detector so just use a safe cpufreq which will be inaccurency. Use a cpufreq notifier to adjust the event's period to a more accurate one. Reviewed-by: Jie Zhan <[email protected]> Reviewed-by: Douglas Anderson <[email protected]> Signed-off-by: Yicong Yang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 60bc47b commit 7a88444

File tree

1 file changed

+58
-0
lines changed

1 file changed

+58
-0
lines changed

arch/arm64/kernel/watchdog_hld.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,61 @@ bool __init arch_perf_nmi_is_available(void)
3434
*/
3535
return arm_pmu_irq_is_nmi();
3636
}
37+
38+
static int watchdog_perf_update_period(void *data)
39+
{
40+
int cpu = smp_processor_id();
41+
u64 max_cpu_freq, new_period;
42+
43+
max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
44+
if (!max_cpu_freq)
45+
return 0;
46+
47+
new_period = watchdog_thresh * max_cpu_freq;
48+
hardlockup_detector_perf_adjust_period(new_period);
49+
50+
return 0;
51+
}
52+
53+
static int watchdog_freq_notifier_callback(struct notifier_block *nb,
54+
unsigned long val, void *data)
55+
{
56+
struct cpufreq_policy *policy = data;
57+
int cpu;
58+
59+
if (val != CPUFREQ_CREATE_POLICY)
60+
return NOTIFY_DONE;
61+
62+
/*
63+
* Let each online CPU related to the policy update the period by their
64+
* own. This will serialize with the framework on start/stop the lockup
65+
* detector (softlockup_{start,stop}_all) and avoid potential race
66+
* condition. Otherwise we may have below theoretical race condition:
67+
* (core 0/1 share the same policy)
68+
* [core 0] [core 1]
69+
* hardlockup_detector_event_create()
70+
* hw_nmi_get_sample_period()
71+
* (cpufreq registered, notifier callback invoked)
72+
* watchdog_freq_notifier_callback()
73+
* watchdog_perf_update_period()
74+
* (since core 1's event's not yet created,
75+
* the period is not set)
76+
* perf_event_create_kernel_counter()
77+
* (event's period is SAFE_MAX_CPU_FREQ)
78+
*/
79+
for_each_cpu(cpu, policy->cpus)
80+
smp_call_on_cpu(cpu, watchdog_perf_update_period, NULL, false);
81+
82+
return NOTIFY_DONE;
83+
}
84+
85+
static struct notifier_block watchdog_freq_notifier = {
86+
.notifier_call = watchdog_freq_notifier_callback,
87+
};
88+
89+
static int __init init_watchdog_freq_notifier(void)
90+
{
91+
return cpufreq_register_notifier(&watchdog_freq_notifier,
92+
CPUFREQ_POLICY_NOTIFIER);
93+
}
94+
core_initcall(init_watchdog_freq_notifier);

0 commit comments

Comments
 (0)