Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

Signed-off-by: Eliav Farber <farbere@amazon.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20241204142003.32859-2-farbere@amazon.com

authored by

Eliav Farber and committed by
Thomas Gleixner
bad6722e 429f49ad

+52 -101
-23
arch/arm/kernel/machine_kexec.c
··· 127 127 cpus_stopped = 1; 128 128 } 129 129 130 - static void machine_kexec_mask_interrupts(void) 131 - { 132 - unsigned int i; 133 - struct irq_desc *desc; 134 - 135 - for_each_irq_desc(i, desc) { 136 - struct irq_chip *chip; 137 - 138 - chip = irq_desc_get_chip(desc); 139 - if (!chip) 140 - continue; 141 - 142 - if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data)) 143 - chip->irq_eoi(&desc->irq_data); 144 - 145 - if (chip->irq_mask) 146 - chip->irq_mask(&desc->irq_data); 147 - 148 - if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data)) 149 - chip->irq_disable(&desc->irq_data); 150 - } 151 - } 152 - 153 130 void machine_crash_shutdown(struct pt_regs *regs) 154 131 { 155 132 local_irq_disable();
+1
arch/arm64/Kconfig
··· 149 149 select GENERIC_IDLE_POLL_SETUP 150 150 select GENERIC_IOREMAP 151 151 select GENERIC_IRQ_IPI 152 + select GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD 152 153 select GENERIC_IRQ_PROBE 153 154 select GENERIC_IRQ_SHOW 154 155 select GENERIC_IRQ_SHOW_LEVEL
-31
arch/arm64/kernel/machine_kexec.c
··· 207 207 BUG(); /* Should never get here. */ 208 208 } 209 209 210 - static void machine_kexec_mask_interrupts(void) 211 - { 212 - unsigned int i; 213 - struct irq_desc *desc; 214 - 215 - for_each_irq_desc(i, desc) { 216 - struct irq_chip *chip; 217 - int ret; 218 - 219 - chip = irq_desc_get_chip(desc); 220 - if (!chip) 221 - continue; 222 - 223 - /* 224 - * First try to remove the active state. If this 225 - * fails, try to EOI the interrupt. 226 - */ 227 - ret = irq_set_irqchip_state(i, IRQCHIP_STATE_ACTIVE, false); 228 - 229 - if (ret && irqd_irq_inprogress(&desc->irq_data) && 230 - chip->irq_eoi) 231 - chip->irq_eoi(&desc->irq_data); 232 - 233 - if (chip->irq_mask) 234 - chip->irq_mask(&desc->irq_data); 235 - 236 - if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data)) 237 - chip->irq_disable(&desc->irq_data); 238 - } 239 - } 240 - 241 210 /** 242 211 * machine_crash_shutdown - shutdown non-crashing cpus and save registers 243 212 */
-1
arch/powerpc/include/asm/kexec.h
··· 61 61 extern void kexec_smp_wait(void); /* get and clear naca physid, wait for 62 62 master to copy new code to 0 */ 63 63 extern void default_machine_kexec(struct kimage *image); 64 - extern void machine_kexec_mask_interrupts(void); 65 64 66 65 void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_code_buffer, 67 66 unsigned long start_address) __noreturn;
-22
arch/powerpc/kexec/core.c
··· 22 22 #include <asm/setup.h> 23 23 #include <asm/firmware.h> 24 24 25 - void machine_kexec_mask_interrupts(void) { 26 - unsigned int i; 27 - struct irq_desc *desc; 28 - 29 - for_each_irq_desc(i, desc) { 30 - struct irq_chip *chip; 31 - 32 - chip = irq_desc_get_chip(desc); 33 - if (!chip) 34 - continue; 35 - 36 - if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data)) 37 - chip->irq_eoi(&desc->irq_data); 38 - 39 - if (chip->irq_mask) 40 - chip->irq_mask(&desc->irq_data); 41 - 42 - if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data)) 43 - chip->irq_disable(&desc->irq_data); 44 - } 45 - } 46 - 47 25 #ifdef CONFIG_CRASH_DUMP 48 26 void machine_crash_shutdown(struct pt_regs *regs) 49 27 {
+1
arch/powerpc/kexec/core_32.c
··· 7 7 * Copyright (C) 2005 IBM Corporation. 8 8 */ 9 9 10 + #include <linux/irq.h> 10 11 #include <linux/kexec.h> 11 12 #include <linux/mm.h> 12 13 #include <linux/string.h>
-23
arch/riscv/kernel/machine_kexec.c
··· 114 114 #endif 115 115 } 116 116 117 - static void machine_kexec_mask_interrupts(void) 118 - { 119 - unsigned int i; 120 - struct irq_desc *desc; 121 - 122 - for_each_irq_desc(i, desc) { 123 - struct irq_chip *chip; 124 - 125 - chip = irq_desc_get_chip(desc); 126 - if (!chip) 127 - continue; 128 - 129 - if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data)) 130 - chip->irq_eoi(&desc->irq_data); 131 - 132 - if (chip->irq_mask) 133 - chip->irq_mask(&desc->irq_data); 134 - 135 - if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data)) 136 - chip->irq_disable(&desc->irq_data); 137 - } 138 - } 139 - 140 117 /* 141 118 * machine_crash_shutdown - Prepare to kexec after a kernel crash 142 119 *
+3
include/linux/irq.h
··· 694 694 extern void irq_chip_release_resources_parent(struct irq_data *data); 695 695 #endif 696 696 697 + /* Disable or mask interrupts during a kernel kexec */ 698 + extern void machine_kexec_mask_interrupts(void); 699 + 697 700 /* Handling of unhandled and spurious interrupts: */ 698 701 extern void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret); 699 702
+6
kernel/irq/Kconfig
··· 141 141 142 142 If you don't know what to do here, say N. 143 143 144 + # Clear forwarded VM interrupts during kexec. 145 + # This option ensures the kernel clears active states for interrupts 146 + # forwarded to virtual machines (VMs) during a machine kexec. 147 + config GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD 148 + bool 149 + 144 150 endmenu 145 151 146 152 config GENERIC_IRQ_MULTI_HANDLER
+1 -1
kernel/irq/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 - obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o 3 + obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o kexec.o 4 4 obj-$(CONFIG_IRQ_TIMINGS) += timings.o 5 5 ifeq ($(CONFIG_TEST_IRQ_TIMINGS),y) 6 6 CFLAGS_timings.o += -DDEBUG
+40
kernel/irq/kexec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/interrupt.h> 4 + #include <linux/irq.h> 5 + #include <linux/irqdesc.h> 6 + #include <linux/irqnr.h> 7 + 8 + #include "internals.h" 9 + 10 + void machine_kexec_mask_interrupts(void) 11 + { 12 + struct irq_desc *desc; 13 + unsigned int i; 14 + 15 + for_each_irq_desc(i, desc) { 16 + struct irq_chip *chip; 17 + int check_eoi = 1; 18 + 19 + chip = irq_desc_get_chip(desc); 20 + if (!chip) 21 + continue; 22 + 23 + if (IS_ENABLED(CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD)) { 24 + /* 25 + * First try to remove the active state from an interrupt which is forwarded 26 + * to a VM. If the interrupt is not forwarded, try to EOI the interrupt. 27 + */ 28 + check_eoi = irq_set_irqchip_state(i, IRQCHIP_STATE_ACTIVE, false); 29 + } 30 + 31 + if (check_eoi && chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data)) 32 + chip->irq_eoi(&desc->irq_data); 33 + 34 + if (chip->irq_mask) 35 + chip->irq_mask(&desc->irq_data); 36 + 37 + if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data)) 38 + chip->irq_disable(&desc->irq_data); 39 + } 40 + }