Commit 06f3c8d5 authored by Xiongfeng Wang's avatar Xiongfeng Wang
Browse files

watchdog: add nmi_watchdog support for arm64 based on SDEI

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8LQCC


CVE: NA

-------------------------------------------------

Add nmi_watchdog support for arm64 based on SDEI.

Signed-off-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
Reviewed-by: default avatarKefeng Wang <wangkefeng.wang@huawei.com>
Reviewed-by: default avatarHanjun Guo <guohanjun@huawei.com>

 Conflicts:
	lib/Kconfig.debug
	arch/arm64/kernel/watchdog_sdei.c
Signed-off-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
parent 07842846
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
obj-$(CONFIG_CRASH_DUMP)		+= crash_dump.o
obj-$(CONFIG_CRASH_CORE)		+= crash_core.o
obj-$(CONFIG_ARM_SDE_INTERFACE)		+= sdei.o
obj-$(CONFIG_SDEI_WATCHDOG)		+= watchdog_sdei.o
obj-$(CONFIG_ARM64_PTR_AUTH)		+= pointer_auth.o
obj-$(CONFIG_ARM64_MTE)			+= mte.o
obj-y					+= vdso-wrap.o
+112 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Detect hard lockups on a system
 *
 * Note: Most of this code is borrowed heavily from the perf hardlockup
 * detector, so thanks to Don for the initial implementation.
 */

#define pr_fmt(fmt) "SDEI NMI watchdog: " fmt

#include <asm/irq_regs.h>
#include <asm/kvm_hyp.h>
#include <asm/smp_plat.h>
#include <asm/sdei.h>
#include <asm/virt.h>
#include <linux/arm_sdei.h>
#include <linux/nmi.h>

/* We use the secure physical timer as SDEI NMI watchdog timer */
#define SDEI_NMI_WATCHDOG_HWIRQ		29

static int sdei_watchdog_event_num;
static bool disable_sdei_nmi_watchdog;
static bool sdei_watchdog_registered;

void watchdog_hardlockup_enable(unsigned int cpu)
{
	int ret;

	if (!sdei_watchdog_registered)
		return;

	/* Skip the first hardlockup check incase BIOS didn't init the
	 * secure timer correctly */
	watchdog_hardlockup_touch_cpu(cpu);
	ret = sdei_api_event_enable(sdei_watchdog_event_num);
	if (ret) {
		pr_err("Enable NMI Watchdog failed on cpu%d\n",
				smp_processor_id());
	}
}

void watchdog_hardlockup_disable(unsigned int cpu)
{
	int ret;

	if (!sdei_watchdog_registered)
		return;

	ret = sdei_api_event_disable(sdei_watchdog_event_num);
	if (ret)
		pr_err("Disable NMI Watchdog failed on cpu%d\n",
				smp_processor_id());
}

static int sdei_watchdog_callback(u32 event,
		struct pt_regs *regs, void *arg)
{
	watchdog_hardlockup_check(smp_processor_id(), regs);

	return 0;
}

static void sdei_nmi_watchdog_bind(void *data)
{
	int ret;

	ret = sdei_api_event_interrupt_bind(SDEI_NMI_WATCHDOG_HWIRQ);
	if (ret < 0)
		pr_err("SDEI bind failed on cpu%d, return %d\n",
				smp_processor_id(), ret);
}

static int __init disable_sdei_nmi_watchdog_setup(char *str)
{
	disable_sdei_nmi_watchdog = true;
	return 1;
}
__setup("disable_sdei_nmi_watchdog", disable_sdei_nmi_watchdog_setup);

int __init watchdog_hardlockup_probe(void)
{
	int ret;

	if (disable_sdei_nmi_watchdog)
		return -EINVAL;

	if (!is_hyp_mode_available()) {
		pr_err("Disable SDEI NMI Watchdog in VM\n");
		return -EINVAL;
	}

	sdei_watchdog_event_num = sdei_api_event_interrupt_bind(SDEI_NMI_WATCHDOG_HWIRQ);
	if (sdei_watchdog_event_num < 0) {
		pr_err("Bind interrupt failed. Firmware may not support SDEI !\n");
		return sdei_watchdog_event_num;
	}

	on_each_cpu(sdei_nmi_watchdog_bind, NULL, true);

	ret = sdei_event_register(sdei_watchdog_event_num,
					sdei_watchdog_callback, NULL);
	if (ret) {
		pr_err("SDEI Watchdog register callback failed\n");
		return ret;
	}

	sdei_watchdog_registered = true;
	pr_info("SDEI Watchdog registered successfully\n");

	return 0;
}
+9 −0
Original line number Diff line number Diff line
@@ -1045,6 +1045,12 @@ config HAVE_HARDLOCKUP_DETECTOR_BUDDY
	depends on SMP
	default y

config SDEI_WATCHDOG
	bool "SDEI NMI Watchdog support"
	depends on ARM_SDE_INTERFACE
	depends on HARDLOCKUP_DETECTOR
	select HARDLOCKUP_DETECTOR_COUNTS_HRTIMER

#
# Global switch whether to build a hardlockup detector at all. It is available
# only when the architecture supports at least one implementation. There are
@@ -1061,6 +1067,7 @@ config HARDLOCKUP_DETECTOR
	depends on HAVE_HARDLOCKUP_DETECTOR_PERF || HAVE_HARDLOCKUP_DETECTOR_BUDDY || HAVE_HARDLOCKUP_DETECTOR_ARCH
	imply HARDLOCKUP_DETECTOR_PERF
	imply HARDLOCKUP_DETECTOR_BUDDY
	imply SDEI_WATCHDOG
	imply HARDLOCKUP_DETECTOR_ARCH
	select LOCKUP_DETECTOR

@@ -1097,6 +1104,7 @@ config HARDLOCKUP_DETECTOR_PERF
	depends on HARDLOCKUP_DETECTOR
	depends on HAVE_HARDLOCKUP_DETECTOR_PERF && !HARDLOCKUP_DETECTOR_PREFER_BUDDY
	depends on !HAVE_HARDLOCKUP_DETECTOR_ARCH
	depends on !SDEI_WATCHDOG
	select HARDLOCKUP_DETECTOR_COUNTS_HRTIMER

config HARDLOCKUP_DETECTOR_BUDDY
@@ -1105,6 +1113,7 @@ config HARDLOCKUP_DETECTOR_BUDDY
	depends on HAVE_HARDLOCKUP_DETECTOR_BUDDY
	depends on !HAVE_HARDLOCKUP_DETECTOR_PERF || HARDLOCKUP_DETECTOR_PREFER_BUDDY
	depends on !HAVE_HARDLOCKUP_DETECTOR_ARCH
	depends on !SDEI_WATCHDOG
	select HARDLOCKUP_DETECTOR_COUNTS_HRTIMER

config HARDLOCKUP_DETECTOR_ARCH