sdei_watchdog: clear EOI of the secure timer before kdump

commit 75ac7be96da43f12bad247de69137500e02fd37f openeuler.

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: huwentao <huwentao19@h-partners.com>
This commit is contained in:
Xiongfeng Wang 2021-02-20 11:01:00 +08:00 committed by lcy
parent fb960c0410
commit 3d3ce61def
6 changed files with 30 additions and 0 deletions

View File

@ -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>
@ -266,6 +267,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();

View File

@ -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;

View File

@ -202,6 +202,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,

View File

@ -45,6 +45,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,

View File

@ -229,4 +229,10 @@ extern int proc_watchdog_cpumask(struct ctl_table *, int,
#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

View File

@ -24,6 +24,7 @@
#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE SDEI_1_0_FN(0x0E)
#define SDEI_1_0_FN_SDEI_PRIVATE_RESET SDEI_1_0_FN(0x11)
#define SDEI_1_0_FN_SDEI_SHARED_RESET SDEI_1_0_FN(0x12)
#define SDEI_1_0_FN_SDEI_CLEAR_EOI SDEI_1_0_FN(0x18)
#define SDEI_VERSION_MAJOR_SHIFT 48
#define SDEI_VERSION_MAJOR_MASK 0x7fff