riscv: kexec: Fixup irq controller broken in kexec crash path
authorGuo Ren <guoren@linux.alibaba.com>
Thu, 20 Oct 2022 14:16:02 +0000 (10:16 -0400)
committerPalmer Dabbelt <palmer@rivosinc.com>
Wed, 30 Nov 2022 05:50:58 +0000 (21:50 -0800)
If a crash happens on cpu3 and all interrupts are binding on cpu0, the
bad irq routing will cause a crash kernel which can't receive any irq.
Because crash kernel won't clean up all harts' PLIC enable bits in
enable registers. This patch is similar to 9141a003a491 ("ARM: 7316/1:
kexec: EOI active and mask all interrupts in kexec crash path") and
78fd584cdec0 ("arm64: kdump: implement machine_crash_shutdown()"), and
PowerPC also has the same mechanism.

Fixes: fba8a8674f68 ("RISC-V: Add kexec support")
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Xianting Tian <xianting.tian@linux.alibaba.com>
Cc: Nick Kossifidis <mick@ics.forth.gr>
Cc: Palmer Dabbelt <palmer@rivosinc.com>
Link: https://lore.kernel.org/r/20221020141603.2856206-2-guoren@kernel.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/kernel/machine_kexec.c

index ee79e68..db41c67 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/compiler.h>    /* For unreachable() */
 #include <linux/cpu.h>         /* For cpu_down() */
 #include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 
 /*
  * kexec_image_info - Print received image details
@@ -154,6 +156,37 @@ 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;
+               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 - Prepare to kexec after a kernel crash
  *
@@ -169,6 +202,8 @@ machine_crash_shutdown(struct pt_regs *regs)
        crash_smp_send_stop();
 
        crash_save_cpu(regs, smp_processor_id());
+       machine_kexec_mask_interrupts();
+
        pr_info("Starting crashdump kernel...\n");
 }