Commit 75ac7be9 authored by Xiongfeng Wang's avatar Xiongfeng Wang Committed by Zheng Zengkai
Browse files

sdei_watchdog: clear EOI of the secure timer before kdump



hulk inclusion
category: feature
bugzilla: 48046
CVE: NA

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

When we panic in hardlockup, the secure timer interrupt remains activate
because firmware clear eoi after dispatch is completed. This will cause
arm_arch_timer interrupt failed to trigger in the second kernel.

This patch add a new SMC helper to clear eoi of a certain interrupt and
clear eoi of the secure timer before booting the second kernel.

Signed-off-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
Reviewed-by: default avatarHanjun Guo <guohanjun@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 5bc048a1
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/nmi.h>
#include <linux/page-flags.h>
#include <linux/smp.h>

@@ -254,6 +255,15 @@ void machine_crash_shutdown(struct pt_regs *regs)
	/* shutdown non-crashing cpus */
	crash_smp_send_stop();

	/*
	 * when we panic in hardlockup detected by sdei_watchdog, the secure
	 * timer interrupt remains activate here because firmware clear eoi
	 * after dispatch is completed. This will cause arm_arch_timer
	 * interrupt failed to trigger in the second kernel. So we clear eoi
	 * of the secure timer before booting the second kernel.
	 */
	sdei_watchdog_clear_eoi();

	/* for crashing cpu */
	crash_save_cpu(regs, smp_processor_id());
	machine_kexec_mask_interrupts();
+6 −0
Original line number Diff line number Diff line
@@ -80,6 +80,12 @@ static int __init disable_sdei_nmi_watchdog_setup(char *str)
}
__setup("disable_sdei_nmi_watchdog", disable_sdei_nmi_watchdog_setup);

void sdei_watchdog_clear_eoi(void)
{
	if (sdei_watchdog_registered)
		sdei_api_clear_eoi(SDEI_NMI_WATCHDOG_HWIRQ);
}

int __init watchdog_nmi_probe(void)
{
	int ret;
+6 −0
Original line number Diff line number Diff line
@@ -197,6 +197,12 @@ int sdei_api_event_interrupt_bind(int hwirq)
	return (int)event_number;
}

int sdei_api_clear_eoi(int hwirq)
{
	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_CLEAR_EOI, hwirq, 0, 0, 0, 0,
			NULL);
}

static int sdei_api_event_get_info(u32 event, u32 info, u64 *result)
{
	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_GET_INFO, event, info, 0,
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ int sdei_event_disable(u32 event_num);
int sdei_api_event_interrupt_bind(int hwirq);
int sdei_api_event_disable(u32 event_num);
int sdei_api_event_enable(u32 event_num);
int sdei_api_clear_eoi(int hwirq);

/* GHES register/unregister helpers */
int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
+6 −0
Original line number Diff line number Diff line
@@ -222,4 +222,10 @@ int proc_watchdog_cpumask(struct ctl_table *, int, void *, size_t *, loff_t *);
#include <asm/nmi.h>
#endif

#ifdef CONFIG_SDEI_WATCHDOG
void sdei_watchdog_clear_eoi(void);
#else
static inline void sdei_watchdog_clear_eoi(void) { }
#endif

#endif
Loading