[PATCH] powerpc/crash: save cpu register data in crash_smp_send_stop()
Hari Bathini
hbathini at linux.ibm.com
Thu Jun 30 16:37:06 AEST 2022
Please ignore this thread. Will resend with v2 tag..
On 30/06/22 11:00 am, Hari Bathini wrote:
> During kdump, two set of NMI IPIs are sent to secondary CPUs, if
> 'crash_kexec_post_notifiers' option is set. The first set of NMI IPIs
> to stop the CPUs and the other set to collect register data. Instead,
> capture register data for secondary CPUs while stopping them itself.
> Also, fallback to smp_send_stop() in case the function gets called
> without kdump configured.
>
> Signed-off-by: Hari Bathini <hbathini at linux.ibm.com>
> ---
> arch/powerpc/include/asm/kexec.h | 1 +
> arch/powerpc/kernel/smp.c | 29 ++++--------
> arch/powerpc/kexec/crash.c | 77 +++++++++++++++++++-------------
> 3 files changed, 57 insertions(+), 50 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
> index 2aefe14e1442..cce69101205e 100644
> --- a/arch/powerpc/include/asm/kexec.h
> +++ b/arch/powerpc/include/asm/kexec.h
> @@ -83,6 +83,7 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs);
> extern int crash_shutdown_register(crash_shutdown_t handler);
> extern int crash_shutdown_unregister(crash_shutdown_t handler);
>
> +extern void crash_kexec_prepare(void);
> extern void crash_kexec_secondary(struct pt_regs *regs);
> int __init overlaps_crashkernel(unsigned long start, unsigned long size);
> extern void reserve_crashkernel(void);
> diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
> index bcefab484ea6..6b850c157a62 100644
> --- a/arch/powerpc/kernel/smp.c
> +++ b/arch/powerpc/kernel/smp.c
> @@ -35,6 +35,7 @@
> #include <linux/stackprotector.h>
> #include <linux/pgtable.h>
> #include <linux/clockchips.h>
> +#include <linux/kexec.h>
>
> #include <asm/ptrace.h>
> #include <linux/atomic.h>
> @@ -55,7 +56,6 @@
> #endif
> #include <asm/vdso.h>
> #include <asm/debug.h>
> -#include <asm/kexec.h>
> #include <asm/cpu_has_feature.h>
> #include <asm/ftrace.h>
> #include <asm/kup.h>
> @@ -619,20 +619,6 @@ void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
> }
> #endif
>
> -#ifdef CONFIG_NMI_IPI
> -static void crash_stop_this_cpu(struct pt_regs *regs)
> -#else
> -static void crash_stop_this_cpu(void *dummy)
> -#endif
> -{
> - /*
> - * Just busy wait here and avoid marking CPU as offline to ensure
> - * register data is captured appropriately.
> - */
> - while (1)
> - cpu_relax();
> -}
> -
> void crash_smp_send_stop(void)
> {
> static bool stopped = false;
> @@ -651,11 +637,14 @@ void crash_smp_send_stop(void)
>
> stopped = true;
>
> -#ifdef CONFIG_NMI_IPI
> - smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_stop_this_cpu, 1000000);
> -#else
> - smp_call_function(crash_stop_this_cpu, NULL, 0);
> -#endif /* CONFIG_NMI_IPI */
> +#ifdef CONFIG_KEXEC_CORE
> + if (kexec_crash_image) {
> + crash_kexec_prepare();
> + return;
> + }
> +#endif
> +
> + smp_send_stop();
> }
>
> #ifdef CONFIG_NMI_IPI
> diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
> index 80f54723cf6d..252724ed666a 100644
> --- a/arch/powerpc/kexec/crash.c
> +++ b/arch/powerpc/kexec/crash.c
> @@ -40,6 +40,14 @@
> #define REAL_MODE_TIMEOUT 10000
>
> static int time_to_dump;
> +
> +/*
> + * In case of system reset, secondary CPUs enter crash_kexec_secondary with out
> + * having to send an IPI explicitly. So, indicate if the crash is via
> + * system reset to avoid sending another IPI.
> + */
> +static int is_via_system_reset;
> +
> /*
> * crash_wake_offline should be set to 1 by platforms that intend to wake
> * up offline cpus prior to jumping to a kdump kernel. Currently powernv
> @@ -101,7 +109,7 @@ void crash_ipi_callback(struct pt_regs *regs)
> /* NOTREACHED */
> }
>
> -static void crash_kexec_prepare_cpus(int cpu)
> +static void crash_kexec_prepare_cpus(void)
> {
> unsigned int msecs;
> volatile unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
> @@ -113,7 +121,15 @@ static void crash_kexec_prepare_cpus(int cpu)
> if (crash_wake_offline)
> ncpus = num_present_cpus() - 1;
>
> - crash_send_ipi(crash_ipi_callback);
> + /*
> + * If we came in via system reset, secondaries enter via crash_kexec_secondary().
> + * So, wait a while for the secondary CPUs to enter for that case.
> + * Else, send IPI to all other CPUs.
> + */
> + if (is_via_system_reset)
> + mdelay(PRIMARY_TIMEOUT);
> + else
> + crash_send_ipi(crash_ipi_callback);
> smp_wmb();
>
> again:
> @@ -202,7 +218,7 @@ void crash_kexec_secondary(struct pt_regs *regs)
>
> #else /* ! CONFIG_SMP */
>
> -static void crash_kexec_prepare_cpus(int cpu)
> +static void crash_kexec_prepare_cpus(void)
> {
> /*
> * move the secondaries to us so that we can copy
> @@ -248,6 +264,32 @@ noinstr static void __maybe_unused crash_kexec_wait_realmode(int cpu)
> static inline void crash_kexec_wait_realmode(int cpu) {}
> #endif /* CONFIG_SMP && CONFIG_PPC64 */
>
> +void crash_kexec_prepare(void)
> +{
> + /* Avoid hardlocking with irresponsive CPU holding logbuf_lock */
> + printk_deferred_enter();
> +
> + /*
> + * This function is only called after the system
> + * has panicked or is otherwise in a critical state.
> + * The minimum amount of code to allow a kexec'd kernel
> + * to run successfully needs to happen here.
> + *
> + * In practice this means stopping other cpus in
> + * an SMP system.
> + * The kernel is broken so disable interrupts.
> + */
> + hard_irq_disable();
> +
> + /*
> + * Make a note of crashing cpu. Will be used in machine_kexec
> + * such that another IPI will not be sent.
> + */
> + crashing_cpu = smp_processor_id();
> +
> + crash_kexec_prepare_cpus();
> +}
> +
> /*
> * Register a function to be called on shutdown. Only use this if you
> * can't reset your device in the second kernel.
> @@ -311,35 +353,10 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
> unsigned int i;
> int (*old_handler)(struct pt_regs *regs);
>
> - /* Avoid hardlocking with irresponsive CPU holding logbuf_lock */
> - printk_deferred_enter();
> -
> - /*
> - * This function is only called after the system
> - * has panicked or is otherwise in a critical state.
> - * The minimum amount of code to allow a kexec'd kernel
> - * to run successfully needs to happen here.
> - *
> - * In practice this means stopping other cpus in
> - * an SMP system.
> - * The kernel is broken so disable interrupts.
> - */
> - hard_irq_disable();
> -
> - /*
> - * Make a note of crashing cpu. Will be used in machine_kexec
> - * such that another IPI will not be sent.
> - */
> - crashing_cpu = smp_processor_id();
> -
> - /*
> - * If we came in via system reset, wait a while for the secondary
> - * CPUs to enter.
> - */
> if (TRAP(regs) == INTERRUPT_SYSTEM_RESET)
> - mdelay(PRIMARY_TIMEOUT);
> + is_via_system_reset = 1;
>
> - crash_kexec_prepare_cpus(crashing_cpu);
> + crash_smp_send_stop();
>
> crash_save_cpu(regs, crashing_cpu);
>
More information about the Linuxppc-dev
mailing list