[PATCH] panic/kexec: Allow forcing panic execution on a specific CPU

Pnina Feder
2026-01-01T12:33:52Z

Some platforms require panic handling to execute on a specific CPU
for crash dump to work reliably. This may be due to firmware,
interrupt routing, or platform-specific constraints where only one
CPU is able to safely enter the crash kernel.

Add an optional configuration that allows redirecting panic execution
to a designated target CPU before invoking kexec into the crash kernel.

When CONFIG_PANIC_FORCE_CPU is enabled, the initial panic CPU will
forward the panic to the configured CPU using smp_call_function_single().
If a panic is already in progress on another CPU, redirection is
skipped and a warning is printed.

There is no functional change when the option is disabled.

Signed-off-by: Pnina Feder <pnina.feder@mobileye.com>
---
kernel/Kconfig.kexec | 17 ++++++++++++
kernel/panic.c | 66 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+)

diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
index 15632358bcf7..4ba08888cc4a 100644
--- a/kernel/Kconfig.kexec
+++ b/kernel/Kconfig.kexec
@@ -179,4 +179,21 @@ config CRASH_MAX_MEMORY_RANGES
the computation behind the value provided through the
/sys/kernel/crash_elfcorehdr_size attribute.

+config PANIC_FORCE_CPU
+ bool "Force panic to execute on a specific CPU"
+ depends on SMP && CRASH_DUMP
+ help
+ Some platforms require panic handling to occur on a specific CPU
+ for the crash kernel to function correctly. This option forces
+ panic handling to be redirected to the specified CPU before kexec
+ into the crash kernel.
+
+config PANIC_FORCE_CPU_ID
+ int "CPU number for panic execution"
+ depends on PANIC_FORCE_CPU
+ default 0
+ help
+ The CPU number that should handle panic when PANIC_FORCE_CPU is
+ enabled.
+
endmenu
diff --git a/kernel/panic.c b/kernel/panic.c
index 0d52210a9e2b..c3fe254292c0 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -300,6 +300,65 @@ void __weak crash_smp_send_stop(void)

atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);

+#ifdef CONFIG_PANIC_FORCE_CPU
+static void do_panic_on_target_cpu(void *info)
+{
+ panic("%s", (char *)info);
+}
+
+/**
+ * panic_force_target_cpu - Redirect panic to a specific CPU for crash kernel
+ * @fmt: panic message format string
+ * @args: arguments for format string
+ *
+ * Some platforms require panic handling to occur on a specific CPU
+ * for the crash kernel to function correctly. This function redirects
+ * panic handling to CONFIG_PANIC_FORCE_CPU_ID before kexec.
+ *
+ * Returns true if panic should proceed on current CPU.
+ * Returns false (never returns) if panic was redirected.
+ */
+static bool panic_force_target_cpu(const char *fmt, va_list args)
+{
+ static char panic_redirect_msg[1024];
+ int cpu = raw_smp_processor_id();
+ int target_cpu = CONFIG_PANIC_FORCE_CPU_ID;
+
+ /* Already on target CPU - proceed normally */
+ if (cpu == target_cpu)
+ return true;
+
+ /* Target CPU is offline, can't redirect */
+ if (!cpu_online(target_cpu)) {
+ pr_warn("panic: CPU %d is offline, cannot redirect panic. "
+ "Crash kernel interrupts may be unavailable.\n", target_cpu);
+ return true;
+ }
+
+ /* Another panic already in progress */
+ if (panic_in_progress()) {
+ pr_warn("panic: Another panic in progress on CPU %d, cannot redirect to CPU %d. "
+ "Crash kernel interrupts may be unavailable.\n",
+ atomic_read(&panic_cpu), target_cpu);
+ return true;
+ }
+
+ pr_info("panic: Redirecting from CPU %d to CPU %d for crash kernel\n",
+ cpu, target_cpu);
+
+ vsnprintf(panic_redirect_msg, sizeof(panic_redirect_msg), fmt, args);
+
+ smp_call_function_single(target_cpu, do_panic_on_target_cpu, panic_redirect_msg, false);
+
+ return false;
+}
+#else
+static inline bool panic_force_target_cpu(const char *fmt, va_list args)
+{
+ return true;
+}
+#endif /* CONFIG_PANIC_FORCE_CPU */
+
bool panic_try_start(void)
{
int old_cpu, this_cpu;
@@ -451,6 +510,13 @@ void vpanic(const char *fmt, va_list args)
local_irq_disable();
preempt_disable_notrace();

+ /*
+ * Redirect panic to target CPU if configured (CONFIG_PANIC_FORCE_CPU).
+ * Returns false and never returns if panic was redirected.
+ */
+ if (!panic_force_target_cpu(fmt, args))
+ panic_smp_self_stop();
+
/*
* It's possible to come here directly from a panic-assertion and
* not have preempt disabled. Some functions called from here want
--
2.43.0