[PATCH OLK-6.6 0/2] Update the watchdog period according to real CPU frequency

driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7CQP ---------------------------------------------------------------------- watchdog perf needs architecture to provide method for converting the watchdog thresh to counter period. For arm64 we're using the max CPU frequency for doing the conversion which is from cpufreq driver. But some cpufreq driver are registered lately, for example cppc_cpufreq will be registered at late initcall which is after the initialization of watchdog perf (initialized in armv8_pmuv3 of device initcall). In such case the period of watchdog will not be accurate enough. Fix this by registering a cpufreq notifier and update the watchdog period once the cpufreq driver is initialized. Yicong Yang (2): watchdog/perf: Provide function for adjusting the event period arm64/watchdog_hld: Add a cpufreq notifier for update watchdog thresh arch/arm64/kernel/watchdog_hld.c | 58 ++++++++++++++++++++++++++++++++ include/linux/nmi.h | 2 ++ kernel/watchdog_perf.c | 23 +++++++++++++ 3 files changed, 83 insertions(+) -- 2.33.0

driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7CQP ---------------------------------------------------------------------- Architecture's using perf events for hard lockup detection needs to convert the watchdog_thresh to the event's period, some architecture for example arm64 perform this conversion using the CPU's maximum frequency which will be acquired by cpufreq. However by the time the lockup detector's initialized the cpufreq driver may not be initialized, thus launch a watchdog with inaccurate period. Provide a function hardlockup_detector_perf_adjust_period() to allowing adjust the event period. Then architecture can update with more accurate period if cpufreq is initialized. Signed-off-by: Yicong Yang <yangyicong@hisilicon.com> Reviewed-by: Yicong Yang <yangyicong@hisilicon.com> Signed-off-by: Hongye Lin <linhongye@h-partners.com> --- include/linux/nmi.h | 2 ++ kernel/watchdog_perf.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 08422f713580..25fe091e1d19 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -105,10 +105,12 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs); extern void hardlockup_detector_perf_stop(void); extern void hardlockup_detector_perf_restart(void); extern void hardlockup_detector_perf_cleanup(void); +extern void hardlockup_detector_perf_adjust_period(int cpu, u64 period); #else static inline void hardlockup_detector_perf_stop(void) { } static inline void hardlockup_detector_perf_restart(void) { } static inline void hardlockup_detector_perf_cleanup(void) { } +static inline void hardlockup_detector_perf_adjust_period(int cpu, u64 period) { } #endif void watchdog_hardlockup_stop(void); diff --git a/kernel/watchdog_perf.c b/kernel/watchdog_perf.c index 0052afe18b7f..989d30f80951 100644 --- a/kernel/watchdog_perf.c +++ b/kernel/watchdog_perf.c @@ -198,6 +198,29 @@ void hardlockup_detector_perf_cleanup(void) cpumask_clear(&dead_events_mask); } +/** + * hardlockup_detector_perf_adjust_period - Adjust the event period due + * to cpu frequency change + * @cpu: The CPU whose event period will be adjusted + * @period: The target period to be set + */ +void hardlockup_detector_perf_adjust_period(int cpu, u64 period) +{ + struct perf_event *event = per_cpu(watchdog_ev, cpu); + + if (!(watchdog_enabled & WATCHDOG_HARDLOCKUP_ENABLED)) + return; + + if (!event) + return; + + if (event->attr.sample_period == period) + return; + + if (perf_event_period(event, period)) + pr_err("failed to change period to %llu\n", period); +} + /** * hardlockup_detector_perf_stop - Globally stop watchdog events * -- 2.33.0

driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7CQP ---------------------------------------------------------------------- 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. Signed-off-by: Yicong Yang <yangyicong@hisilicon.com> Reviewed-by: Yicong Yang <yangyicong@hisilicon.com> Signed-off-by: Hongye Lin <linhongye@h-partners.com> --- arch/arm64/kernel/watchdog_hld.c | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/arch/arm64/kernel/watchdog_hld.c b/arch/arm64/kernel/watchdog_hld.c index 817f0b7f6f92..ae0da38214fa 100644 --- a/arch/arm64/kernel/watchdog_hld.c +++ b/arch/arm64/kernel/watchdog_hld.c @@ -35,3 +35,61 @@ bool __init arch_perf_nmi_is_available(void) */ return arm_pmu_irq_is_nmi(); } + +static int watchdog_perf_update_period(void *data) +{ + int cpu = raw_smp_processor_id(); + u64 max_cpu_freq, new_period; + + max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL; + if (!max_cpu_freq) + return 0; + + new_period = watchdog_thresh * max_cpu_freq; + hardlockup_detector_perf_adjust_period(cpu, new_period); + + return 0; +} + +static int watchdog_freq_notifier_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_policy *policy = data; + int cpu; + + if (val != CPUFREQ_CREATE_POLICY) + return NOTIFY_DONE; + + /* + * Let each online CPU related to the policy update the period by their + * own. This will serialize with the framework on start/stop the lockup + * detector (softlockup_{start,stop}_all) and avoid potential race + * condition. Otherwise we may have below theoretical race condition: + * (core 0/1 share the same policy) + * [core 0] [core 1] + * hardlockup_detector_event_create() + * hw_nmi_get_sample_period() + * (cpufreq registered, notifier callback invoked) + * watchdog_freq_notifier_callback() + * watchdog_perf_update_period() + * (since core 1's event's not yet created, + * the period is not set) + * perf_event_create_kernel_counter() + * (event's period is SAFE_MAX_CPU_FREQ) + */ + for_each_cpu(cpu, policy->cpus) + smp_call_on_cpu(cpu, watchdog_perf_update_period, NULL, false); + + return NOTIFY_DONE; +} + +static struct notifier_block watchdog_freq_notifier = { + .notifier_call = watchdog_freq_notifier_callback, +}; + +static int __init init_watchdog_freq_notifier(void) +{ + return cpufreq_register_notifier(&watchdog_freq_notifier, + CPUFREQ_POLICY_NOTIFIER); +} +core_initcall(init_watchdog_freq_notifier); -- 2.33.0

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/16260 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/Q4B... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/16260 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/Q4B...
participants (2)
-
patchwork bot
-
Qinxin Xia