Use the new play_dead() interface to prepare an environment for the new kernel. Do not rely on non-crashing CPUs jumping to kexec_start_address. Signed-off-by: Dengcheng Zhu <dzhu@xxxxxxxxxxxx> --- arch/mips/cavium-octeon/setup.c | 2 +- arch/mips/include/asm/kexec.h | 1 + arch/mips/kernel/crash.c | 4 +++- arch/mips/kernel/machine_kexec.c | 28 ++++++++++++++++++++++++---- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index a8034d0..3a1f7fa 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -95,7 +95,7 @@ static void octeon_kexec_smp_down(void *ignored) " sync \n" " synci ($0) \n"); - relocated_kexec_smp_wait(NULL); + kexec_smp_reboot(); } #endif diff --git a/arch/mips/include/asm/kexec.h b/arch/mips/include/asm/kexec.h index 493a3cc..8f1d0ef 100644 --- a/arch/mips/include/asm/kexec.h +++ b/arch/mips/include/asm/kexec.h @@ -45,6 +45,7 @@ extern const unsigned char kexec_smp_wait[]; extern unsigned long secondary_kexec_args[4]; extern void (*relocated_kexec_smp_wait) (void *); extern atomic_t kexec_ready_to_reboot; +extern void kexec_smp_reboot(void); extern void (*_crash_smp_send_stop)(void); #endif #endif diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index d455363..6d43200 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -43,7 +43,9 @@ static void crash_shutdown_secondary(void *passed_regs) while (!atomic_read(&kexec_ready_to_reboot)) cpu_relax(); - relocated_kexec_smp_wait(NULL); + + kexec_smp_reboot(); + /* NOTREACHED */ } diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 8b574bc..02146ad 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -12,6 +12,7 @@ #include <asm/cacheflush.h> #include <asm/page.h> +#include <asm/mipsmtregs.h> extern const unsigned char relocate_new_kernel[]; extern const size_t relocate_new_kernel_size; @@ -19,6 +20,10 @@ extern const size_t relocate_new_kernel_size; extern unsigned long kexec_start_address; extern unsigned long kexec_indirection_page; +static unsigned long reboot_code_buffer; + +typedef void (*noretfun_t)(void) __noreturn; + int (*_machine_kexec_prepare)(struct kimage *) = NULL; void (*_machine_kexec_shutdown)(void) = NULL; void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; @@ -26,6 +31,19 @@ void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; void (*relocated_kexec_smp_wait) (void *); atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); void (*_crash_smp_send_stop)(void) = NULL; + +void kexec_smp_reboot(void) +{ + if (smp_processor_id() > 0) { + /* + * Instead of cpu_relax() or wait, this is needed for kexec + * smp reboot. Kdump usually doesn't require an smp new + * kernel, but kexec may do. + */ + play_dead(true); + } else + ((noretfun_t) reboot_code_buffer)(); +} #endif static void kexec_image_info(const struct kimage *kimage) @@ -79,12 +97,9 @@ machine_crash_shutdown(struct pt_regs *regs) default_machine_crash_shutdown(regs); } -typedef void (*noretfun_t)(void) __noreturn; - void machine_kexec(struct kimage *image) { - unsigned long reboot_code_buffer; unsigned long entry; unsigned long *ptr; @@ -132,6 +147,11 @@ machine_kexec(struct kimage *image) (void *)(kexec_smp_wait - relocate_new_kernel); smp_wmb(); atomic_set(&kexec_ready_to_reboot, 1); -#endif + + kexec_smp_reboot(); + + /* NOT REACHED */ +#else ((noretfun_t) reboot_code_buffer)(); +#endif } -- 2.7.4