Improve interrupt handling during machine kexec
Subsystems (5)
v6 cover Improve interrupt handling during machine kexec
This patch series focuses on improving the machine_kexec_mask_interrupts() function by consolidating its implementation and optimizing its behavior to avoid redundant interrupt masking.
Patch Summary:
[PATCH v6 1/2] Move machine_kexec_mask_interrupts() to kernel/irq/kexec.c,
removing duplicate architecture-specific implementations.
[PATCH v6 2/2] Refine machine_kexec_mask_interrupts() to avoid re-masking
already-masked interrupts, resolving specific warnings triggered in GPIO IRQ flows.
Changes between v5 and v6:
- Change GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD to not be user selectable.
Changes between v4 and v5:
- The function machine_kexec_mask_interrupts() has been moved from kernel/kexec_core.c to a new file kernel/irq/kexec.c.
- A new configuration option, GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD, has been added.
- The parameters for the machine_kexec_mask_interrupts() function have been defined in reverse Christmas Tree style.
- The comment explaining the call to irq_set_irqchip_state() has been improved for clarity.
- The phrase 'This patch' has been removed from the commit message.
Changes between v3 and v4:
- Add missing <linux/irqdesc.h> and <linux/irq.h> includes.
Eliav Farber (2):
kexec: Consolidate machine_kexec_mask_interrupts() implementation
kexec: Prevent redundant IRQ masking by checking state before shutdown
arch/arm/kernel/machine_kexec.c | 23 -------------------- arch/arm64/Kconfig | 1 + arch/arm64/kernel/machine_kexec.c | 31 -------------------------- arch/powerpc/include/asm/kexec.h | 1 - arch/powerpc/kexec/core.c | 22 ------------------- arch/powerpc/kexec/core_32.c | 1 + arch/riscv/kernel/machine_kexec.c | 23 -------------------- include/linux/irq.h | 3 +++ kernel/irq/Kconfig | 6 ++++++ kernel/irq/Makefile | 2 +- kernel/irq/kexec.c | 36 +++++++++++++++++++++++++++++++ 11 files changed, 48 insertions(+), 101 deletions(-) create mode 100644 kernel/irq/kexec.c
Signature · 1 line
2.40.1
PATCH v6 1/2 kexec: Consolidate machine_kexec_mask_interrupts() implementation
Consolidate the machine_kexec_mask_interrupts implementation into a common function located in a new file: kernel/irq/kexec.c. This removes duplicate implementations from architecture-specific files in arch/arm, arch/arm64, arch/powerpc, and arch/riscv, reducing code duplication and improving maintainability.
The new implementation retains architecture-specific behavior for CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD, which was previously implemented for ARM64. When enabled (currently for ARM64), it clears the active state of interrupts forwarded to virtual machines (VMs) before handling other interrupt masking operations.
---
V5 -> V6:
- Change GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD to not be user selectable.
arch/arm/kernel/machine_kexec.c | 23 ------------------ arch/arm64/Kconfig | 1 + arch/arm64/kernel/machine_kexec.c | 31 ------------------------ arch/powerpc/include/asm/kexec.h | 1 - arch/powerpc/kexec/core.c | 22 ----------------- arch/powerpc/kexec/core_32.c | 1 + arch/riscv/kernel/machine_kexec.c | 23 ------------------ include/linux/irq.h | 3 +++ kernel/irq/Kconfig | 6 +++++ kernel/irq/Makefile | 2 +- kernel/irq/kexec.c | 40 +++++++++++++++++++++++++++++++ 11 files changed, 52 insertions(+), 101 deletions(-) create mode 100644 kernel/irq/kexec.c
arch/arm/kernel/machine_kexec.c +0 -23
@@ -127,29 +127,6 @@ void crash_smp_send_stop(void) cpus_stopped =1 ; } -static void machine_kexec_mask_interrupts (void ) -{ -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -if (chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -void machine_crash_shutdown (struct pt_regs *regs) {local_irq_disable ();
arch/arm64/Kconfig +1 -0
@@ -149,6 +149,7 @@ config ARM64 select GENERIC_IDLE_POLL_SETUP select GENERIC_IOREMAP select GENERIC_IRQ_IPI + select GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW_LEVEL
arch/arm64/kernel/machine_kexec.c +0 -31
@@ -207,37 +207,6 @@ void machine_kexec(struct kimage *kimage)BUG ();/* Should never get here. */ } -static void machine_kexec_mask_interrupts (void ) -{ -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; -int ret; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -/* -* First try to remove the active state. If this -* fails, try to EOI the interrupt. -*/ - ret =irq_set_irqchip_state (i,IRQCHIP_STATE_ACTIVE , false); - -if (ret &&irqd_irq_inprogress (&desc->irq_data) && - chip->irq_eoi) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -/** * machine_crash_shutdown - shutdown non-crashing cpus and save registers */
arch/powerpc/include/asm/kexec.h +0 -1
@@ -61,7 +61,6 @@ struct pt_regs;extern void kexec_smp_wait (void );/* get and clear naca physid, wait for master to copy new code to 0 */ extern void default_machine_kexec (struct kimage *image); -extern void machine_kexec_mask_interrupts (void );void relocate_new_kernel (unsigned long indirection_page,unsigned long reboot_code_buffer,unsigned long start_address)__noreturn ;
arch/powerpc/kexec/core.c +0 -22
@@ -22,28 +22,6 @@#include <asm/setup.h> #include <asm/firmware.h> -void machine_kexec_mask_interrupts (void ) { -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -if (chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -#ifdef CONFIG_CRASH_DUMP void machine_crash_shutdown (struct pt_regs *regs) {
arch/powerpc/kexec/core_32.c +1 -0
@@ -7,6 +7,7 @@* Copyright (C) 2005 IBM Corporation. */ +#include <linux/irq.h> #include <linux/kexec.h> #include <linux/mm.h> #include <linux/string.h>
arch/riscv/kernel/machine_kexec.c +0 -23
@@ -114,29 +114,6 @@ void machine_shutdown(void)#endif } -static void machine_kexec_mask_interrupts (void ) -{ -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -if (chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -/* * machine_crash_shutdown - Prepare to kexec after a kernel crash *
include/linux/irq.h +3 -0
@@ -694,6 +694,9 @@ extern int irq_chip_request_resources_parent(struct irq_data *data);extern void irq_chip_release_resources_parent (struct irq_data *data);#endif +/* Disable or mask interrupts during a kernel kexec */ +extern void machine_kexec_mask_interrupts (void ); +/* Handling of unhandled and spurious interrupts: */ extern void note_interrupt (struct irq_desc *desc,irqreturn_t action_ret);
kernel/irq/Kconfig +6 -0
@@ -141,6 +141,12 @@ config GENERIC_IRQ_DEBUGFS If you don't know what to do here, say N. +# Clear forwarded VM interrupts during kexec. +# This option ensures the kernel clears active states for interrupts +# forwarded to virtual machines (VMs) during a machine kexec. +config GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD + bool + endmenu config GENERIC_IRQ_MULTI_HANDLER
kernel/irq/Makefile +1 -1
@@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o +obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o kexec.o obj-$(CONFIG_IRQ_TIMINGS) += timings.o ifeq ($(CONFIG_TEST_IRQ_TIMINGS),y) CFLAGS_timings.o += -DDEBUG
kernel/irq/kexec.c new file +40 -0
@@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdesc.h> +#include <linux/irqnr.h> + +#include "internals.h" + +void machine_kexec_mask_interrupts (void ) +{ +struct irq_desc *desc; +unsigned int i; + +for_each_irq_desc (i, desc) { +struct irq_chip *chip; +int check_eoi =1 ; + + chip =irq_desc_get_chip (desc); +if (!chip) +continue ; + +if (IS_ENABLED (CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD )) { +/* +* First try to remove the active state from an interrupt which is forwarded +* to a VM. If the interrupt is not forwarded, try to EOI the interrupt. +*/ + check_eoi =irq_set_irqchip_state (i,IRQCHIP_STATE_ACTIVE , false); + } + +if (check_eoi && chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) + chip->irq_eoi (&desc->irq_data); + +if (chip->irq_mask) + chip->irq_mask (&desc->irq_data); + +if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) + chip->irq_disable (&desc->irq_data); + } +}
Signature · 1 line
2.40.1
[tip: irq/core] kexec: Consolidate machine_kexec_mask_interrupts() implementation
The following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: bad6722e478f5b17a5ceb039dfb4c680cf2c0b48 Gitweb: https://git.kernel.org/tip/bad6722e478f5b17a5ceb039dfb4c680cf2c0b48 Author: Eliav Farber <[email protected]> AuthorDate: Wed, 04 Dec 2024 14:20:02 Committer: Thomas Gleixner <[email protected]> CommitterDate: Wed, 11 Dec 2024 20:32:34 +01:00
kexec: Consolidate machine_kexec_mask_interrupts() implementation
Consolidate the machine_kexec_mask_interrupts implementation into a common function located in a new file: kernel/irq/kexec.c. This removes duplicate implementations from architecture-specific files in arch/arm, arch/arm64, arch/powerpc, and arch/riscv, reducing code duplication and improving maintainability.
The new implementation retains architecture-specific behavior for CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD, which was previously implemented for ARM64. When enabled (currently for ARM64), it clears the active state of interrupts forwarded to virtual machines (VMs) before handling other interrupt masking operations.
--- arch/arm/kernel/machine_kexec.c | 23 +----------------- arch/arm64/Kconfig | 1 +- arch/arm64/kernel/machine_kexec.c | 31 +----------------------- arch/powerpc/include/asm/kexec.h | 1 +- arch/powerpc/kexec/core.c | 22 +----------------- arch/powerpc/kexec/core_32.c | 1 +- arch/riscv/kernel/machine_kexec.c | 23 +----------------- include/linux/irq.h | 3 ++- kernel/irq/Kconfig | 6 +++++- kernel/irq/Makefile | 2 +- kernel/irq/kexec.c | 40 ++++++++++++++++++++++++++++++- 11 files changed, 52 insertions(+), 101 deletions(-) create mode 100644 kernel/irq/kexec.c
arch/arm/kernel/machine_kexec.c +0 -23
@@ -127,29 +127,6 @@ void crash_smp_send_stop(void) cpus_stopped =1 ; } -static void machine_kexec_mask_interrupts (void ) -{ -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -if (chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -void machine_crash_shutdown (struct pt_regs *regs) {local_irq_disable ();
arch/arm64/Kconfig +1 -0
@@ -149,6 +149,7 @@ config ARM64 select GENERIC_IDLE_POLL_SETUP select GENERIC_IOREMAP select GENERIC_IRQ_IPI + select GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW_LEVEL
arch/arm64/kernel/machine_kexec.c +0 -31
@@ -207,37 +207,6 @@ void machine_kexec(struct kimage *kimage)BUG ();/* Should never get here. */ } -static void machine_kexec_mask_interrupts (void ) -{ -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; -int ret; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -/* -* First try to remove the active state. If this -* fails, try to EOI the interrupt. -*/ - ret =irq_set_irqchip_state (i,IRQCHIP_STATE_ACTIVE , false); - -if (ret &&irqd_irq_inprogress (&desc->irq_data) && - chip->irq_eoi) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -/** * machine_crash_shutdown - shutdown non-crashing cpus and save registers */
arch/powerpc/include/asm/kexec.h +0 -1
@@ -61,7 +61,6 @@ struct pt_regs;extern void kexec_smp_wait (void );/* get and clear naca physid, wait for master to copy new code to 0 */ extern void default_machine_kexec (struct kimage *image); -extern void machine_kexec_mask_interrupts (void );void relocate_new_kernel (unsigned long indirection_page,unsigned long reboot_code_buffer,unsigned long start_address)__noreturn ;
arch/powerpc/kexec/core.c +0 -22
@@ -22,28 +22,6 @@#include <asm/setup.h> #include <asm/firmware.h> -void machine_kexec_mask_interrupts (void ) { -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -if (chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -#ifdef CONFIG_CRASH_DUMP void machine_crash_shutdown (struct pt_regs *regs) {
arch/powerpc/kexec/core_32.c +1 -0
@@ -7,6 +7,7 @@* Copyright (C) 2005 IBM Corporation. */ +#include <linux/irq.h> #include <linux/kexec.h> #include <linux/mm.h> #include <linux/string.h>
arch/riscv/kernel/machine_kexec.c +0 -23
@@ -114,29 +114,6 @@ void machine_shutdown(void)#endif } -static void machine_kexec_mask_interrupts (void ) -{ -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -if (chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -/* * machine_crash_shutdown - Prepare to kexec after a kernel crash *
include/linux/irq.h +3 -0
@@ -694,6 +694,9 @@ extern int irq_chip_request_resources_parent(struct irq_data *data);extern void irq_chip_release_resources_parent (struct irq_data *data);#endif +/* Disable or mask interrupts during a kernel kexec */ +extern void machine_kexec_mask_interrupts (void ); +/* Handling of unhandled and spurious interrupts: */ extern void note_interrupt (struct irq_desc *desc,irqreturn_t action_ret);
kernel/irq/Kconfig +6 -0
@@ -141,6 +141,12 @@ config GENERIC_IRQ_DEBUGFS If you don't know what to do here, say N. +# Clear forwarded VM interrupts during kexec. +# This option ensures the kernel clears active states for interrupts +# forwarded to virtual machines (VMs) during a machine kexec. +config GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD + bool + endmenu config GENERIC_IRQ_MULTI_HANDLER
kernel/irq/Makefile +1 -1
@@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o +obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o kexec.o obj-$(CONFIG_IRQ_TIMINGS) += timings.o ifeq ($(CONFIG_TEST_IRQ_TIMINGS),y) CFLAGS_timings.o += -DDEBUG
kernel/irq/kexec.c new file +40 -0
@@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdesc.h> +#include <linux/irqnr.h> + +#include "internals.h" + +void machine_kexec_mask_interrupts (void ) +{ +struct irq_desc *desc; +unsigned int i; + +for_each_irq_desc (i, desc) { +struct irq_chip *chip; +int check_eoi =1 ; + + chip =irq_desc_get_chip (desc); +if (!chip) +continue ; + +if (IS_ENABLED (CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD )) { +/* +* First try to remove the active state from an interrupt which is forwarded +* to a VM. If the interrupt is not forwarded, try to EOI the interrupt. +*/ + check_eoi =irq_set_irqchip_state (i,IRQCHIP_STATE_ACTIVE , false); + } + +if (check_eoi && chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) + chip->irq_eoi (&desc->irq_data); + +if (chip->irq_mask) + chip->irq_mask (&desc->irq_data); + +if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) + chip->irq_disable (&desc->irq_data); + } +}
Will Deacon
maintainerRe: [PATCH v6 1/2] kexec: Consolidate machine_kexec_mask_interrupts() implementation
In reply to Eliav FarberQuoted 70 lines · Eliav Farber
Consolidate the
machine_kexec_mask_interruptsimplementation into a common function located in a new file:kernel/irq/kexec.c. This removes duplicate implementations from architecture-specific files inarch/arm,arch/arm64,arch/powerpc, andarch/riscv, reducing code duplication and improving maintainability.The new implementation retains architecture-specific behavior for
CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD, which was previously implemented for ARM64. When enabled (currently for ARM64), it clears the active state of interrupts forwarded to virtual machines (VMs) before handling other interrupt masking operations.Signed-off-by Eliav Farber <[email protected]>---
V5 -> V6:
- ChangeGENERIC_IRQ_KEXEC_CLEAR_VM_FORWARDto not be user selectable.arch/arm/kernel/machine_kexec.c | 23 ------------------ arch/arm64/Kconfig | 1 + arch/arm64/kernel/machine_kexec.c | 31 ------------------------ arch/powerpc/include/asm/kexec.h | 1 - arch/powerpc/kexec/core.c | 22 ----------------- arch/powerpc/kexec/core_32.c | 1 + arch/riscv/kernel/machine_kexec.c | 23 ------------------ include/linux/irq.h | 3 +++ kernel/irq/Kconfig | 6 +++++ kernel/irq/Makefile | 2 +- kernel/irq/kexec.c | 40 +++++++++++++++++++++++++++++++ 11 files changed, 52 insertions(+), 101 deletions(-) create mode 100644 kernel/irq/kexec.carch/arm/kernel/machine_kexec.c +0
-23@@ -127,29 +127,6 @@ void crash_smp_send_stop(void) cpus_stopped =1 ; } -static void machine_kexec_mask_interrupts (void ) -{ -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; - - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -if (chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) - chip->irq_eoi (&desc->irq_data); - -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); - } -} -void machine_crash_shutdown (struct pt_regs *regs) {local_irq_disable ();arch/arm64/Kconfig +0
-0
arch/arm64/Kconfig config ARM64 · line 152
Quoted 4 lines
arch/arm64/Kconfig +1
-0@@ -149,6 +149,7 @@ config ARM64 select GENERIC_IDLE_POLL_SETUP select GENERIC_IOREMAP select GENERIC_IRQ_IPI + select GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD
Is this really specific to VMs? In the new code, it's just controlling this part of the old code:
Quoted 16 lines
arch/arm64/kernel/machine_kexec.c +0
-8@@ -207,37 +207,6 @@ void machine_kexec(struct kimage *kimage)BUG ();/* Should never get here. */ } -static void machine_kexec_mask_interrupts (void ) -{ -unsigned int i; -struct irq_desc *desc; - -for_each_irq_desc (i, desc) { -struct irq_chip *chip; -int ret;
arch/arm64/kernel/machine_kexec.c void machine_kexec(struct kimage *kimage) · line 227
Quoted 10 lines
arch/arm64/kernel/machine_kexec.c +0
-10- - chip =irq_desc_get_chip (desc); -if (!chip) -continue ; - -/* -* First try to remove the active state. If this -* fails, try to EOI the interrupt. -*/ - ret =irq_set_irqchip_state (i,IRQCHIP_STATE_ACTIVE , false);
which is about active interrupts. Why can't that happen for the host?
Will
PATCH v6 2/2 kexec: Prevent redundant IRQ masking by checking state before shutdown
In reply to Eliav FarberDuring machine kexec, the function machine_kexec_mask_interrupts() is responsible for disabling or masking all interrupts. While the irq_disable hook ensures that an already-disabled IRQ is not disabled again, the current implementation unconditionally invokes the irq_mask() function for every interrupt descriptor, even when the interrupt is already masked.
A specific issue was observed in the crash kernel flow after unbinding a device (prior to kexec) that used a GPIO as an IRQ source. The warning was triggered by the gpiochip_disable_irq() function, which attempted to clear the FLAG_IRQ_IS_ENABLED flag when FLAG_USED_AS_IRQ was not set:
```
void gpiochip_disable_irq(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_desc *desc = gpiochip_get_desc(gc, offset);
if (!IS_ERR(desc) &&
!WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags)))
clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
}
```This issue surfaced after commit a8173820f441 ("gpio: gpiolib: Allow GPIO IRQs to lazy disable") introduced lazy disablement for GPIO IRQs. It replaced disable/enable hooks with mask/unmask hooks. Unlike the disable hook, the mask hook doesn't handle already-masked IRQs.
When a GPIO-IRQ driver is unbound, the IRQ is released, triggering __irq_disable() and irq_state_set_masked(). A subsequent call to machine_kexec_mask_interrupts() re-invokes chip->irq_mask(). This results in a call chain, including gpiochip_irq_mask() and gpiochip_disable_irq(). Since FLAG_USED_AS_IRQ was cleared earlier, a warning occurs.
Replace calls to irq_mask() and irq_disable() hooks with a simplified call to irq_shutdown(), and check if the interrupt is started (irqd_is_started) before calling the shutdown.
---
V5 -> V6: No changes.
kernel/irq/kexec.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
kernel/irq/kexec.c +2 -6
@@ -17,7 +17,7 @@ void machine_kexec_mask_interrupts(void)int check_eoi =1 ; chip =irq_desc_get_chip (desc); -if (!chip) +if (!chip || !irqd_is_started (&desc->irq_data))continue ;if (IS_ENABLED (CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD )) {
@@ -31,10 +31,6 @@ void machine_kexec_mask_interrupts(void)if (check_eoi && chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) chip->irq_eoi (&desc->irq_data); -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); +irq_shutdown (desc); } }
Signature · 1 line
2.40.1
[tip: irq/core] genirq/kexec: Prevent redundant IRQ masking by checking state before shutdown
The following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: b4706d814921cc2df7bb59ad8f9ee84855a4f0c4 Gitweb: https://git.kernel.org/tip/b4706d814921cc2df7bb59ad8f9ee84855a4f0c4 Author: Eliav Farber <[email protected]> AuthorDate: Wed, 04 Dec 2024 14:20:03 Committer: Thomas Gleixner <[email protected]> CommitterDate: Wed, 11 Dec 2024 20:32:34 +01:00
genirq/kexec: Prevent redundant IRQ masking by checking state before shutdown
During machine kexec, machine_kexec_mask_interrupts() is responsible for disabling or masking all interrupts. While the irq_disable() is only invoked when the interrupt is not yet disabled, it unconditionally invokes the irq_mask() callback for every interrupt descriptor, even when the interrupt is already masked or not even started up yet.
A specific issue was observed in the crash kernel flow after unbinding a device (prior to kexec) that used a GPIO as an IRQ source. The warning was triggered by the gpiochip_disable_irq() function, which attempts to clear the FLAG_IRQ_IS_ENABLED flag when FLAG_USED_AS_IRQ was not set.
This issue surfaced after commit a8173820f441 ("gpio: gpiolib: Allow GPIO IRQs to lazy disable") introduced lazy disablement for GPIO IRQs. It replaced disable/enable hooks with mask/unmask hooks. Unlike the disable hook, the mask hook doesn't handle already-masked IRQs.
When a GPIO-IRQ driver is unbound, the IRQ is released, triggering __irq_disable() and irq_state_set_masked(). A subsequent call to machine_kexec_mask_interrupts() re-invokes chip->irq_mask(). This results in a call chain, including gpiochip_irq_mask() and gpiochip_disable_irq(). Since FLAG_USED_AS_IRQ was cleared earlier, the warning is triggered.
Replace the direct invocation of the irq_mask() and irq_disable() callbacks invoking to irq_shutdown(), which handles the cases correct and avoid it all together when the interrupt has never been started up.
--- kernel/irq/kexec.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
kernel/irq/kexec.c +2 -6
@@ -17,7 +17,7 @@ void machine_kexec_mask_interrupts(void)int check_eoi =1 ; chip =irq_desc_get_chip (desc); -if (!chip) +if (!chip || !irqd_is_started (&desc->irq_data))continue ;if (IS_ENABLED (CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD )) {
@@ -31,10 +31,6 @@ void machine_kexec_mask_interrupts(void)if (check_eoi && chip->irq_eoi &&irqd_irq_inprogress (&desc->irq_data)) chip->irq_eoi (&desc->irq_data); -if (chip->irq_mask) - chip->irq_mask (&desc->irq_data); - -if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) - chip->irq_disable (&desc->irq_data); +irq_shutdown (desc); } }
This series was applied to riscv/linux.git (fixes) by Thomas Gleixner <[email protected]>:
Hello:
This series was applied to riscv/linux.git (fixes) by Thomas Gleixner <[email protected]>:
Quoted 4 lines · On Wed, 4 Dec 2024 14:20:01 +0000 you wrote:
This patch series focuses on improving the
machine_kexec_mask_interrupts()function by consolidating its implementation and optimizing its behavior to avoid redundant interrupt masking.
Quoted 8 lines
Patch Summary:
[PATCH v6 1/2] Movemachine_kexec_mask_interrupts()tokernel/irq/kexec.c,
removing duplicate architecture-specific implementations.
[PATCH v6 2/2] Refinemachine_kexec_mask_interrupts()to avoid re-masking
already-masked interrupts, resolving specific warnings triggered in GPIO IRQ flows.[...]
Here is the summary with links:
- [v6,1/2] kexec: Consolidate machine_kexec_mask_interrupts() implementation
https://git.kernel.org/riscv/c/bad6722e478f - [v6,2/2] kexec: Prevent redundant IRQ masking by checking state before shutdown https://git.kernel.org/riscv/c/b4706d814921
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html