powerpc/crash: save cpu register data in crash_smp_send_stop()
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@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20220630064942.192283-1-hbathini@linux.ibm.com
This commit is contained in:
parent
51ac6d4cea
commit
c7255058b5
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue