[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