
From: Yicong Yang <yangyicong@hisilicon.com> Currently we cannot use watchdog_{perf, buddy} if CONFIG_SDEI_WATCHDOG=y. Not all the platforms has watchdog_sdei so this patch tries to make watchdog_sdei coexist with other watchdogs. Only one watchdog will finally works. By default watchdog_sdei will be used. If boot with "disable_sdei_nmi_watchdog", other watchdogs will be used if probed. Signed-off-by: Yicong Yang <yangyicong@hisilicon.com> Signed-off-by: Jie Liu <liujie375@h-partners.com> --- arch/arm64/kernel/watchdog_sdei.c | 6 +++--- include/linux/nmi.h | 6 ++++++ kernel/watchdog.c | 16 ++++++++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/watchdog_sdei.c b/arch/arm64/kernel/watchdog_sdei.c index 414e869c5483..50d545813cbc 100644 --- a/arch/arm64/kernel/watchdog_sdei.c +++ b/arch/arm64/kernel/watchdog_sdei.c @@ -25,7 +25,7 @@ bool disable_sdei_nmi_watchdog = true; static bool sdei_watchdog_registered; static DEFINE_PER_CPU(ktime_t, last_check_time); -int watchdog_nmi_enable(unsigned int cpu) +int sdei_watchdog_nmi_enable(unsigned int cpu) { int ret; @@ -49,7 +49,7 @@ int watchdog_nmi_enable(unsigned int cpu) return 0; } -void watchdog_nmi_disable(unsigned int cpu) +void sdei_watchdog_nmi_disable(unsigned int cpu) { int ret; @@ -111,7 +111,7 @@ void sdei_watchdog_clear_eoi(void) sdei_api_clear_eoi(SDEI_NMI_WATCHDOG_HWIRQ); } -int __init watchdog_nmi_probe(void) +int __init sdei_watchdog_nmi_probe(void) { int ret; diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 15827822a493..e0bcc0356898 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -233,10 +233,16 @@ extern int proc_watchdog_cpumask(struct ctl_table *, int, #endif #ifdef CONFIG_SDEI_WATCHDOG +int sdei_watchdog_nmi_enable(unsigned int cpu); +void sdei_watchdog_nmi_disable(unsigned int cpu); void sdei_watchdog_clear_eoi(void); +int sdei_watchdog_nmi_probe(void); extern bool disable_sdei_nmi_watchdog; #else +static inline int sdei_watchdog_nmi_enable(unsigned int cpu) { return -ENODEV; } +static inline void sdei_watchdog_nmi_disable(unsigned int cpu) { } static inline void sdei_watchdog_clear_eoi(void) { } +static inline int sdei_watchdog_nmi_probe(void) { return -ENODEV; } #define disable_sdei_nmi_watchdog 1 #endif diff --git a/kernel/watchdog.c b/kernel/watchdog.c index e4a4b91a5b47..e733c6f4b5c7 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -514,8 +514,12 @@ static void watchdog_enable(unsigned int cpu) /* Initialize timestamp */ __touch_watchdog(); /* Enable the perf event */ - if (watchdog_enabled & NMI_WATCHDOG_ENABLED) - watchdog_nmi_enable(cpu); + if (watchdog_enabled & NMI_WATCHDOG_ENABLED) { + if (disable_sdei_nmi_watchdog) + watchdog_nmi_enable(cpu); + else + sdei_watchdog_nmi_enable(cpu); + } } static void watchdog_disable(unsigned int cpu) @@ -529,7 +533,10 @@ static void watchdog_disable(unsigned int cpu) * between disabling the timer and disabling the perf event causes * the perf NMI to detect a false positive. */ - watchdog_nmi_disable(cpu); + if (disable_sdei_nmi_watchdog) + watchdog_nmi_disable(cpu); + else + sdei_watchdog_nmi_enable(cpu); hrtimer_cancel(hrtimer); wait_for_completion(this_cpu_ptr(&softlockup_completion)); } @@ -866,7 +873,8 @@ void __init lockup_detector_init(void) cpumask_copy(&watchdog_cpumask, housekeeping_cpumask(HK_FLAG_TIMER)); - if (!watchdog_nmi_probe()) + if ((!disable_sdei_nmi_watchdog && !sdei_watchdog_nmi_probe()) || + !watchdog_nmi_probe()) nmi_watchdog_available = true; else allow_lockup_detector_init_retry = true; -- 2.25.1