Add a shim hardlockup detector that allows to select between the perf- and HPET-driven implementations available for x86.
Override the interfaces of the default hardlockup detector. Cc: Andi Kleen <a...@linux.intel.com> Cc: Stephane Eranian <eran...@google.com> Cc: "Ravi V. Shankar" <ravi.v.shan...@intel.com> Cc: io...@lists.linux-foundation.org Cc: linuxppc-dev@lists.ozlabs.org Suggested-by: Nicholas Piggin <npig...@gmail.com> Reviewed-by: Tony Luck <tony.l...@intel.com> Signed-off-by: Ricardo Neri <ricardo.neri-calde...@linux.intel.com> --- Changes since v6: * None Changes since v5: * Added watchdog_nmi_start() to be used when the watchdog is reconfigured. * Always build the x86-specific hardlockup detector shim; not only when the HPET-based detector is selected. * Corrected a typo in comment in watchdog_nmi_probe() (Ani) * Removed useless local ret variable in watchdog_nmi_enable(). (Ani) Changes since v4: * Use a switch to enable and disable the various available detectors. (Andi) Changes since v3: * Fixed style in multi-line comment. (Randy Dunlap) Changes since v2: * Pass cpu number as argument to hardlockup_detector_[enable|disable]. (Thomas Gleixner) Changes since v1: * Introduced this patch: Added an x86-specific shim hardlockup detector. (Nicholas Piggin) --- arch/x86/Kconfig.debug | 3 ++ arch/x86/kernel/Makefile | 2 + arch/x86/kernel/watchdog_hld.c | 86 ++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 arch/x86/kernel/watchdog_hld.c diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index b4dced142116..41ae46314307 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -3,6 +3,9 @@ config EARLY_PRINTK_USB bool +config X86_HARDLOCKUP_DETECTOR + def_bool y if HARDLOCKUP_DETECTOR_CORE + config X86_VERBOSE_BOOTUP bool "Enable verbose x86 bootup info messages" default y diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 58eb858f33ff..706294fd5e46 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -108,6 +108,8 @@ obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_VM86) += vm86_32.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_X86_HARDLOCKUP_DETECTOR) += watchdog_hld.o + obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_X86_HARDLOCKUP_DETECTOR_HPET) += watchdog_hld_hpet.o diff --git a/arch/x86/kernel/watchdog_hld.c b/arch/x86/kernel/watchdog_hld.c new file mode 100644 index 000000000000..33c22f6456a3 --- /dev/null +++ b/arch/x86/kernel/watchdog_hld.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * A shim hardlockup detector for x86 to select between the perf- and HPET- + * driven implementations. + * + * Copyright (C) Intel Corporation 2023 + */ + +#include <linux/nmi.h> +#include <asm/hpet.h> + +enum x86_hardlockup_detector { + X86_HARDLOCKUP_DETECTOR_PERF, + X86_HARDLOCKUP_DETECTOR_HPET, +}; + +static enum x86_hardlockup_detector detector_type __ro_after_init; + +int watchdog_nmi_enable(unsigned int cpu) +{ + switch (detector_type) { + case X86_HARDLOCKUP_DETECTOR_PERF: + hardlockup_detector_perf_enable(); + break; + case X86_HARDLOCKUP_DETECTOR_HPET: + hardlockup_detector_hpet_enable(cpu); + break; + default: + return -ENODEV; + } + + return 0; +} + +void watchdog_nmi_disable(unsigned int cpu) +{ + switch (detector_type) { + case X86_HARDLOCKUP_DETECTOR_PERF: + hardlockup_detector_perf_disable(); + break; + case X86_HARDLOCKUP_DETECTOR_HPET: + hardlockup_detector_hpet_disable(cpu); + break; + } +} + +int __init watchdog_nmi_probe(void) +{ + int ret; + + /* + * Try first with the HPET hardlockup detector. It will only succeed if + * requested via the kernel command line. The perf-based detector is + * used by default. + */ + ret = hardlockup_detector_hpet_init(); + if (!ret) { + detector_type = X86_HARDLOCKUP_DETECTOR_HPET; + return ret; + } + + ret = hardlockup_detector_perf_init(); + if (!ret) { + detector_type = X86_HARDLOCKUP_DETECTOR_PERF; + return ret; + } + + return 0; +} + +void watchdog_nmi_stop(void) +{ + /* Only the HPET lockup detector defines a stop function. */ + if (detector_type == X86_HARDLOCKUP_DETECTOR_HPET) + hardlockup_detector_hpet_stop(); +} + +void watchdog_nmi_start(void) +{ + if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED)) + return; + + /* Only the HPET lockup detector defines a start function. */ + if (detector_type == X86_HARDLOCKUP_DETECTOR_HPET) + hardlockup_detector_hpet_start(); +} -- 2.25.1