[PATCH 0/6] support NMI watchdog

Douglas Anderson (1): arm64: enable perf events based hard lockup detector Ionela Voinescu (1): cpufreq: add function to get the hardware max frequency Jingyi Wang (1): arm64: watchdog: add switch to select sdei_watchdog/pmu_watchdog Lecopzer Chen (1): arm64: add hw_nmi_get_sample_period for preparation of lockup detector Wei Li (1): arm64: add new config CONFIG_PMU_WATCHDOG Yicong Yang (1): irqchip/gic-v3: Fix one race condition due to NMI withdraw arch/arm64/Kconfig | 1 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/watchdog_hld.c | 24 ++++++++++++++++++++++++ arch/arm64/kernel/watchdog_sdei.c | 23 +++++++++++++++++------ drivers/cpufreq/cpufreq.c | 20 ++++++++++++++++++++ drivers/irqchip/irq-gic-v3.c | 22 ++++++++++++++++++++++ include/linux/cpufreq.h | 5 +++++ include/linux/nmi.h | 11 +++++++++++ kernel/watchdog.c | 28 +++++++++++++++++++++------- lib/Kconfig.debug | 10 ++++++++++ 10 files changed, 132 insertions(+), 13 deletions(-) create mode 100644 arch/arm64/kernel/watchdog_hld.c -- 2.25.1

From: Ionela Voinescu <ionela.voinescu@arm.com> Add weak function to return the hardware maximum frequency of a CPU, with the default implementation returning cpuinfo.max_freq, which is the best information we can generically get from the cpufreq framework. The default can be overwritten by a strong function in platforms that want to provide an alternative implementation, with more accurate information, obtained either from hardware or firmware. Signed-off-by: Ionela Voinescu <ionela.voinescu@arm.com> Reviewed-by: Valentin Schneider <valentin.schneider@arm.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Cc: Viresh Kumar <viresh.kumar@linaro.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> --- drivers/cpufreq/cpufreq.c | 20 ++++++++++++++++++++ include/linux/cpufreq.h | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 57a820ad1206..2920ddc74f73 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1802,6 +1802,26 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_quick_get_max); +/** + * cpufreq_get_hw_max_freq - get the max hardware frequency of the CPU + * @cpu: CPU number + * + * The default return value is the max_freq field of cpuinfo. + */ +__weak unsigned int cpufreq_get_hw_max_freq(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + unsigned int ret_freq = 0; + + if (policy) { + ret_freq = policy->cpuinfo.max_freq; + cpufreq_cpu_put(policy); + } + + return ret_freq; +} +EXPORT_SYMBOL(cpufreq_get_hw_max_freq); + static unsigned int __cpufreq_get(struct cpufreq_policy *policy) { if (unlikely(policy_is_inactive(policy))) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index bf47a225b8f6..24bd8b3f65d8 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -211,6 +211,7 @@ extern struct kobject *cpufreq_global_kobject; unsigned int cpufreq_get(unsigned int cpu); unsigned int cpufreq_quick_get(unsigned int cpu); unsigned int cpufreq_quick_get_max(unsigned int cpu); +unsigned int cpufreq_get_hw_max_freq(unsigned int cpu); void disable_cpufreq(void); u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy); @@ -238,6 +239,10 @@ static inline unsigned int cpufreq_quick_get_max(unsigned int cpu) { return 0; } +static inline unsigned int cpufreq_get_hw_max_freq(unsigned int cpu) +{ + return 0; +} static inline void disable_cpufreq(void) { } #endif -- 2.25.1

From: Lecopzer Chen <lecopzer.chen@mediatek.com> Set safe maximum CPU frequency to 5 GHz in case a particular platform doesn't implement cpufreq driver. Although, architecture doesn't put any restrictions on maximum frequency but 5 GHz seems to be safe maximum given the available Arm CPUs in the market which are clocked much less than 5 GHz. On the other hand, we can't make it much higher as it would lead to a large hard-lockup detection timeout on parts which are running slower (eg. 1GHz on Developerbox) and doesn't possess a cpufreq driver. Link: https://lkml.kernel.org/r/20230519101840.v5.17.Ia9d02578e89c3f44d3cb12eec8b0... Co-developed-by: Sumit Garg <sumit.garg@linaro.org> Signed-off-by: Sumit Garg <sumit.garg@linaro.org> Co-developed-by: Pingfan Liu <kernelfans@gmail.com> Signed-off-by: Pingfan Liu <kernelfans@gmail.com> Signed-off-by: Lecopzer Chen <lecopzer.chen@mediatek.com> Signed-off-by: Douglas Anderson <dianders@chromium.org> Cc: Andi Kleen <ak@linux.intel.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chen-Yu Tsai <wens@csie.org> Cc: Christophe Leroy <christophe.leroy@csgroup.eu> Cc: Colin Cross <ccross@android.com> Cc: Daniel Thompson <daniel.thompson@linaro.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Guenter Roeck <groeck@chromium.org> Cc: Ian Rogers <irogers@google.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Masayoshi Mizuma <msys.mizuma@gmail.com> Cc: Matthias Kaehlcke <mka@chromium.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Petr Mladek <pmladek@suse.com> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: "Ravi V. Shankar" <ravi.v.shankar@intel.com> Cc: Ricardo Neri <ricardo.neri@intel.com> Cc: Stephane Eranian <eranian@google.com> Cc: Stephen Boyd <swboyd@chromium.org> Cc: Tzung-Bi Shih <tzungbi@chromium.org> Cc: Will Deacon <will@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> --- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/watchdog_hld.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 arch/arm64/kernel/watchdog_hld.c diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 9763b9f576d8..1965fd12afcb 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o +obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF) += watchdog_hld.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_CPU_PM) += sleep.o suspend.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o diff --git a/arch/arm64/kernel/watchdog_hld.c b/arch/arm64/kernel/watchdog_hld.c new file mode 100644 index 000000000000..2401eb1b7e55 --- /dev/null +++ b/arch/arm64/kernel/watchdog_hld.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/cpufreq.h> + +/* + * Safe maximum CPU frequency in case a particular platform doesn't implement + * cpufreq driver. Although, architecture doesn't put any restrictions on + * maximum frequency but 5 GHz seems to be safe maximum given the available + * Arm CPUs in the market which are clocked much less than 5 GHz. On the other + * hand, we can't make it much higher as it would lead to a large hard-lockup + * detection timeout on parts which are running slower (eg. 1GHz on + * Developerbox) and doesn't possess a cpufreq driver. + */ +#define SAFE_MAX_CPU_FREQ 5000000000UL // 5 GHz +u64 hw_nmi_get_sample_period(int watchdog_thresh) +{ + unsigned int cpu = smp_processor_id(); + unsigned long max_cpu_freq; + + max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL; + if (!max_cpu_freq) + max_cpu_freq = SAFE_MAX_CPU_FREQ; + + return (u64)max_cpu_freq * watchdog_thresh; +} -- 2.25.1

From: Douglas Anderson <dianders@chromium.org> With the recent feature added to enable perf events to use pseudo NMIs as interrupts on platforms which support GICv3 or later, its now been possible to enable hard lockup detector (or NMI watchdog) on arm64 platforms. So enable corresponding support. One thing to note here is that normally lockup detector is initialized just after the early initcalls but PMU on arm64 comes up much later as device_initcall(). To cope with that, override arch_perf_nmi_is_available() to let the watchdog framework know PMU not ready, and inform the framework to re-initialize lockup detection once PMU has been initialized. [dianders@chromium.org: only HAVE_HARDLOCKUP_DETECTOR_PERF if the PMU config is enabled] Link: https://lkml.kernel.org/r/20230523073952.1.I60217a63acc35621e13f10be16c0cd7c... Link: https://lkml.kernel.org/r/20230519101840.v5.18.Ia44852044cdcb074f387e80df6b4... Co-developed-by: Sumit Garg <sumit.garg@linaro.org> Signed-off-by: Sumit Garg <sumit.garg@linaro.org> Co-developed-by: Pingfan Liu <kernelfans@gmail.com> Signed-off-by: Pingfan Liu <kernelfans@gmail.com> Signed-off-by: Lecopzer Chen <lecopzer.chen@mediatek.com> Signed-off-by: Douglas Anderson <dianders@chromium.org> Cc: Andi Kleen <ak@linux.intel.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chen-Yu Tsai <wens@csie.org> Cc: Christophe Leroy <christophe.leroy@csgroup.eu> Cc: Colin Cross <ccross@android.com> Cc: Daniel Thompson <daniel.thompson@linaro.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Guenter Roeck <groeck@chromium.org> Cc: Ian Rogers <irogers@google.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Masayoshi Mizuma <msys.mizuma@gmail.com> Cc: Matthias Kaehlcke <mka@chromium.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Petr Mladek <pmladek@suse.com> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: "Ravi V. Shankar" <ravi.v.shankar@intel.com> Cc: Ricardo Neri <ricardo.neri@intel.com> Cc: Stephane Eranian <eranian@google.com> Cc: Stephen Boyd <swboyd@chromium.org> Cc: Tzung-Bi Shih <tzungbi@chromium.org> Cc: Will Deacon <will@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> --- arch/arm64/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index d34089914ab9..e9fb2987086d 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -157,12 +157,15 @@ config ARM64 select HAVE_FUNCTION_ERROR_INJECTION select HAVE_FUNCTION_GRAPH_TRACER select HAVE_GCC_PLUGINS + select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && \ + HW_PERF_EVENTS && HAVE_PERF_EVENTS_NMI select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_IRQ_TIME_ACCOUNTING select HAVE_MEMBLOCK_NODE_MAP if NUMA select HAVE_NMI select HAVE_PATA_PLATFORM select HAVE_PERF_EVENTS + select HAVE_PERF_EVENTS_NMI if ARM64_PSEUDO_NMI select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP select HAVE_REGS_AND_STACK_ACCESS_API -- 2.25.1

From: Wei Li <liwei391@huawei.com> hulk inclusion category: feature bugzilla: 49592 CVE: NA ------------------------------------------------- Add new config CONFIG_PMU_WATCHDOG for watchdog implementation method configuration. Signed-off-by: Wei Li <liwei391@huawei.com> Reviewed-by: Hanjun Guo <guohanjun@huawei.com> Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> --- arch/arm64/Kconfig | 2 -- lib/Kconfig.debug | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index e9fb2987086d..6b1c292e3dba 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -157,8 +157,6 @@ config ARM64 select HAVE_FUNCTION_ERROR_INJECTION select HAVE_FUNCTION_GRAPH_TRACER select HAVE_GCC_PLUGINS - select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && \ - HW_PERF_EVENTS && HAVE_PERF_EVENTS_NMI select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_IRQ_TIME_ACCOUNTING select HAVE_MEMBLOCK_NODE_MAP if NUMA diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 74a7a2077c51..943af5ac0e08 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -853,12 +853,25 @@ config HARDLOCKUP_DETECTOR_PERF bool select SOFTLOCKUP_DETECTOR +choice + prompt "aarch64 NMI watchdog method" + depends on ARM64 + help + Watchdog implementation method configuration. + config SDEI_WATCHDOG bool "SDEI NMI Watchdog support" depends on ARM_SDE_INTERFACE && !HARDLOCKUP_CHECK_TIMESTAMP select HAVE_HARDLOCKUP_DETECTOR_ARCH select HARDLOCKUP_DETECTOR +config PMU_WATCHDOG + bool "PMU NMI Watchdog support" + depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI + select HAVE_HARDLOCKUP_DETECTOR_PERF + +endchoice + # # Enables a timestamp based low pass filter to compensate for perf based # hard lockup detection which runs too fast due to turbo modes. -- 2.25.1

From: Jingyi Wang <wangjingyi11@huawei.com> hulk inclusion category: feature bugzilla: 49592 CVE: NA ------------------------------------------------- On aarch64, we can compile both SDEI_WATCHODG and PMU_WATCHDOG code instead of choosing one. SDEI_WATCHDOG is used by default, and if SDEI_WATCHDOG is disabled by kernel parameter "disable_sdei_nmi_watchdog", PMU_WATCHDOG is used instead. Signed-off-by: Jingyi Wang <wangjingyi11@huawei.com> Signed-off-by: Wei Li <liwei391@huawei.com> Reviewed-by: Hanjun Guo <guohanjun@huawei.com> Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> --- arch/arm64/kernel/watchdog_sdei.c | 23 +++++++++++++++++------ include/linux/nmi.h | 11 +++++++++++ kernel/watchdog.c | 28 +++++++++++++++++++++------- lib/Kconfig.debug | 7 ++----- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/arch/arm64/kernel/watchdog_sdei.c b/arch/arm64/kernel/watchdog_sdei.c index ad68ed383fce..e7845f379ca2 100644 --- a/arch/arm64/kernel/watchdog_sdei.c +++ b/arch/arm64/kernel/watchdog_sdei.c @@ -25,7 +25,7 @@ static 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 watchdog_sdei_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 watchdog_sdei_disable(unsigned int cpu) { int ret; @@ -111,13 +111,10 @@ void sdei_watchdog_clear_eoi(void) sdei_api_clear_eoi(SDEI_NMI_WATCHDOG_HWIRQ); } -int __init watchdog_nmi_probe(void) +int __init watchdog_sdei_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; @@ -154,3 +151,17 @@ int __init watchdog_nmi_probe(void) return 0; } + +static struct watchdog_operations arch_watchdog_ops = { + .watchdog_nmi_stop = &watchdog_nmi_stop, + .watchdog_nmi_start = &watchdog_nmi_start, + .watchdog_nmi_probe = &watchdog_sdei_probe, + .watchdog_nmi_enable = &watchdog_sdei_enable, + .watchdog_nmi_disable = &watchdog_sdei_disable, +}; + +void watchdog_ops_init(void) +{ + if (!disable_sdei_nmi_watchdog) + nmi_watchdog_ops = arch_watchdog_ops; +} diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 020768634b29..a22dfa989a39 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -131,6 +131,17 @@ int watchdog_nmi_probe(void); int watchdog_nmi_enable(unsigned int cpu); void watchdog_nmi_disable(unsigned int cpu); +struct watchdog_operations { + void (*watchdog_nmi_stop)(void); + void (*watchdog_nmi_start)(void); + int (*watchdog_nmi_probe)(void); + int (*watchdog_nmi_enable)(unsigned int cpu); + void (*watchdog_nmi_disable)(unsigned int cpu); +}; + +extern struct watchdog_operations nmi_watchdog_ops; +void watchdog_ops_init(void); + void lockup_detector_reconfigure(void); /** diff --git a/kernel/watchdog.c b/kernel/watchdog.c index bc48dfdcf257..07e494879c4a 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -50,6 +50,14 @@ static struct cpumask watchdog_allowed_mask __read_mostly; struct cpumask watchdog_cpumask __read_mostly; unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask); +struct watchdog_operations nmi_watchdog_ops = { + .watchdog_nmi_stop = &watchdog_nmi_stop, + .watchdog_nmi_start = &watchdog_nmi_start, + .watchdog_nmi_probe = &watchdog_nmi_probe, + .watchdog_nmi_enable = &watchdog_nmi_enable, + .watchdog_nmi_disable = &watchdog_nmi_disable, +}; + #ifdef CONFIG_HARDLOCKUP_DETECTOR /* * Should we panic when a soft-lockup or hard-lockup occurs: @@ -509,7 +517,7 @@ static void watchdog_enable(unsigned int cpu) __touch_watchdog(); /* Enable the perf event */ if (watchdog_enabled & NMI_WATCHDOG_ENABLED) - watchdog_nmi_enable(cpu); + nmi_watchdog_ops.watchdog_nmi_enable(cpu); } static void watchdog_disable(unsigned int cpu) @@ -523,7 +531,7 @@ 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); + nmi_watchdog_ops.watchdog_nmi_disable(cpu); hrtimer_cancel(hrtimer); wait_for_completion(this_cpu_ptr(&softlockup_completion)); } @@ -579,7 +587,7 @@ int lockup_detector_offline_cpu(unsigned int cpu) static void __lockup_detector_reconfigure(void) { cpus_read_lock(); - watchdog_nmi_stop(); + nmi_watchdog_ops.watchdog_nmi_stop(); softlockup_stop_all(); set_sample_period(); @@ -587,7 +595,7 @@ static void __lockup_detector_reconfigure(void) if (watchdog_enabled && watchdog_thresh) softlockup_start_all(); - watchdog_nmi_start(); + nmi_watchdog_ops.watchdog_nmi_start(); cpus_read_unlock(); /* * Must be called outside the cpus locked section to prevent @@ -632,9 +640,9 @@ static __init void lockup_detector_setup(void) static void __lockup_detector_reconfigure(void) { cpus_read_lock(); - watchdog_nmi_stop(); + nmi_watchdog_ops.watchdog_nmi_stop(); lockup_detector_update_enable(); - watchdog_nmi_start(); + nmi_watchdog_ops.watchdog_nmi_start(); cpus_read_unlock(); } void lockup_detector_reconfigure(void) @@ -796,15 +804,21 @@ int proc_watchdog_cpumask(struct ctl_table *table, int write, } #endif /* CONFIG_SYSCTL */ +void __weak watchdog_ops_init(void) +{ +} + void __init lockup_detector_init(void) { + watchdog_ops_init(); + if (tick_nohz_full_enabled()) pr_info("Disabling watchdog on nohz_full cores by default\n"); cpumask_copy(&watchdog_cpumask, housekeeping_cpumask(HK_FLAG_TIMER)); - if (!watchdog_nmi_probe()) + if (!nmi_watchdog_ops.watchdog_nmi_probe()) nmi_watchdog_available = true; lockup_detector_setup(); } diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 943af5ac0e08..ea78dfe8ec3c 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -853,11 +853,8 @@ config HARDLOCKUP_DETECTOR_PERF bool select SOFTLOCKUP_DETECTOR -choice - prompt "aarch64 NMI watchdog method" +menu "ARM64 NMI watchdog configuration" depends on ARM64 - help - Watchdog implementation method configuration. config SDEI_WATCHDOG bool "SDEI NMI Watchdog support" @@ -870,7 +867,7 @@ config PMU_WATCHDOG depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI select HAVE_HARDLOCKUP_DETECTOR_PERF -endchoice +endmenu # "ARM64 NMI watchdog configuration" # # Enables a timestamp based low pass filter to compensate for perf based -- 2.25.1

From: Yicong Yang <yangyicong@hisilicon.com> kunpeng inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9QIWG CVE: NA ---------------------------------------------------------------------- The introduce of FEAT_NMI/FEAT_GICv3_NMI will cause a race problem that we may handle the normal interrupt in interrupt disabled context due to the withdraw of NMI interrupt. The flow will be like below: [interrupt disabled] <- normal interrupt pending, for example timer interrupt <- NMI occurs, ISR_EL1.nmi = 1 do_el1_interrupt() <- NMI withdraw, ISR_EL1.nmi = 0 ISR_EL1.nmi = 0, not an NMI interrupt gic_handle_irq() __gic_handle_irq_from_irqson() irqnr = gic_read_iar() <- Oops, ack and handle an normal interrupt in interrupt disabled context! Fix this by checking the interrupt status in __gic_handle_irq_from_irqson() and ignore the interrupt if we're in interrupt disabled context. Fixes: 0408b5bc4300 ("irqchip/gic-v3: Implement FEAT_GICv3_NMI support") Signed-off-by: Yicong Yang <yangyicong@hisilicon.com> Signed-off-by: Jie Liu <liujie375@h-partners.com> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> --- drivers/irqchip/irq-gic-v3.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 1c744285bc38..a46e8ff4a50e 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -679,6 +679,28 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs } #endif + /* + * We should enter here with interrupts disabled, otherwise we may met + * a race here with FEAT_NMI/FEAT_GICv3_NMI: + * + * [interrupt disabled] + * <- normal interrupt pending, for example timer interrupt + * <- NMI occurs, ISR_EL1.nmi = 1 + * do_el1_interrupt() + * <- NMI withdraw, ISR_EL1.nmi = 0 + * ISR_EL1.nmi = 0, not an NMI interrupt + * gic_handle_irq() + * __gic_handle_irq_from_irqson() + * irqnr = gic_read_iar() <- Oops, ack and handle an normal interrupt + * in interrupt disabled context! + * + * So if we met this case here, just return from the interrupt context. + * Since the interrupt is still pending, we can handle it once the + * interrupt re-enabled and it'll not be missing. + */ + if (unlikely(!gic_supports_pseudo_nmis() && !interrupts_enabled(regs))) + return; + irqnr = gic_read_iar(); /* Check for special IDs first */ -- 2.25.1
participants (1)
-
Yang Yingliang