18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Architecture specific (PPC64) functions for kexec based crash dumps.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005, IBM Corp.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Created by: Haren Myneni
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/smp.h>
128c2ecf20Sopenharmony_ci#include <linux/reboot.h>
138c2ecf20Sopenharmony_ci#include <linux/kexec.h>
148c2ecf20Sopenharmony_ci#include <linux/export.h>
158c2ecf20Sopenharmony_ci#include <linux/crash_dump.h>
168c2ecf20Sopenharmony_ci#include <linux/delay.h>
178c2ecf20Sopenharmony_ci#include <linux/irq.h>
188c2ecf20Sopenharmony_ci#include <linux/types.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <asm/processor.h>
218c2ecf20Sopenharmony_ci#include <asm/machdep.h>
228c2ecf20Sopenharmony_ci#include <asm/kexec.h>
238c2ecf20Sopenharmony_ci#include <asm/prom.h>
248c2ecf20Sopenharmony_ci#include <asm/smp.h>
258c2ecf20Sopenharmony_ci#include <asm/setjmp.h>
268c2ecf20Sopenharmony_ci#include <asm/debug.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/*
298c2ecf20Sopenharmony_ci * The primary CPU waits a while for all secondary CPUs to enter. This is to
308c2ecf20Sopenharmony_ci * avoid sending an IPI if the secondary CPUs are entering
318c2ecf20Sopenharmony_ci * crash_kexec_secondary on their own (eg via a system reset).
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * The secondary timeout has to be longer than the primary. Both timeouts are
348c2ecf20Sopenharmony_ci * in milliseconds.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci#define PRIMARY_TIMEOUT		500
378c2ecf20Sopenharmony_ci#define SECONDARY_TIMEOUT	1000
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define IPI_TIMEOUT		10000
408c2ecf20Sopenharmony_ci#define REAL_MODE_TIMEOUT	10000
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int time_to_dump;
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * crash_wake_offline should be set to 1 by platforms that intend to wake
458c2ecf20Sopenharmony_ci * up offline cpus prior to jumping to a kdump kernel. Currently powernv
468c2ecf20Sopenharmony_ci * sets it to 1, since we want to avoid things from happening when an
478c2ecf20Sopenharmony_ci * offline CPU wakes up due to something like an HMI (malfunction error),
488c2ecf20Sopenharmony_ci * which propagates to all threads.
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_ciint crash_wake_offline;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define CRASH_HANDLER_MAX 3
538c2ecf20Sopenharmony_ci/* List of shutdown handles */
548c2ecf20Sopenharmony_cistatic crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX];
558c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(crash_handlers_lock);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic unsigned long crash_shutdown_buf[JMP_BUF_LEN];
588c2ecf20Sopenharmony_cistatic int crash_shutdown_cpu = -1;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic int handle_fault(struct pt_regs *regs)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	if (crash_shutdown_cpu == smp_processor_id())
638c2ecf20Sopenharmony_ci		longjmp(crash_shutdown_buf, 1);
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic atomic_t cpus_in_crash;
708c2ecf20Sopenharmony_civoid crash_ipi_callback(struct pt_regs *regs)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	static cpumask_t cpus_state_saved = CPU_MASK_NONE;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	int cpu = smp_processor_id();
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	hard_irq_disable();
778c2ecf20Sopenharmony_ci	if (!cpumask_test_cpu(cpu, &cpus_state_saved)) {
788c2ecf20Sopenharmony_ci		crash_save_cpu(regs, cpu);
798c2ecf20Sopenharmony_ci		cpumask_set_cpu(cpu, &cpus_state_saved);
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	atomic_inc(&cpus_in_crash);
838c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/*
868c2ecf20Sopenharmony_ci	 * Starting the kdump boot.
878c2ecf20Sopenharmony_ci	 * This barrier is needed to make sure that all CPUs are stopped.
888c2ecf20Sopenharmony_ci	 */
898c2ecf20Sopenharmony_ci	while (!time_to_dump)
908c2ecf20Sopenharmony_ci		cpu_relax();
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (ppc_md.kexec_cpu_down)
938c2ecf20Sopenharmony_ci		ppc_md.kexec_cpu_down(1, 1);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
968c2ecf20Sopenharmony_ci	kexec_smp_wait();
978c2ecf20Sopenharmony_ci#else
988c2ecf20Sopenharmony_ci	for (;;);	/* FIXME */
998c2ecf20Sopenharmony_ci#endif
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/* NOTREACHED */
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void crash_kexec_prepare_cpus(int cpu)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	unsigned int msecs;
1078c2ecf20Sopenharmony_ci	unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
1088c2ecf20Sopenharmony_ci	int tries = 0;
1098c2ecf20Sopenharmony_ci	int (*old_handler)(struct pt_regs *regs);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	printk(KERN_EMERG "Sending IPI to other CPUs\n");
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (crash_wake_offline)
1148c2ecf20Sopenharmony_ci		ncpus = num_present_cpus() - 1;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	crash_send_ipi(crash_ipi_callback);
1178c2ecf20Sopenharmony_ci	smp_wmb();
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ciagain:
1208c2ecf20Sopenharmony_ci	/*
1218c2ecf20Sopenharmony_ci	 * FIXME: Until we will have the way to stop other CPUs reliably,
1228c2ecf20Sopenharmony_ci	 * the crash CPU will send an IPI and wait for other CPUs to
1238c2ecf20Sopenharmony_ci	 * respond.
1248c2ecf20Sopenharmony_ci	 */
1258c2ecf20Sopenharmony_ci	msecs = IPI_TIMEOUT;
1268c2ecf20Sopenharmony_ci	while ((atomic_read(&cpus_in_crash) < ncpus) && (--msecs > 0))
1278c2ecf20Sopenharmony_ci		mdelay(1);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* Would it be better to replace the trap vector here? */
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (atomic_read(&cpus_in_crash) >= ncpus) {
1328c2ecf20Sopenharmony_ci		printk(KERN_EMERG "IPI complete\n");
1338c2ecf20Sopenharmony_ci		return;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	printk(KERN_EMERG "ERROR: %d cpu(s) not responding\n",
1378c2ecf20Sopenharmony_ci		ncpus - atomic_read(&cpus_in_crash));
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/*
1408c2ecf20Sopenharmony_ci	 * If we have a panic timeout set then we can't wait indefinitely
1418c2ecf20Sopenharmony_ci	 * for someone to activate system reset. We also give up on the
1428c2ecf20Sopenharmony_ci	 * second time through if system reset fail to work.
1438c2ecf20Sopenharmony_ci	 */
1448c2ecf20Sopenharmony_ci	if ((panic_timeout > 0) || (tries > 0))
1458c2ecf20Sopenharmony_ci		return;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/*
1488c2ecf20Sopenharmony_ci	 * A system reset will cause all CPUs to take an 0x100 exception.
1498c2ecf20Sopenharmony_ci	 * The primary CPU returns here via setjmp, and the secondary
1508c2ecf20Sopenharmony_ci	 * CPUs reexecute the crash_kexec_secondary path.
1518c2ecf20Sopenharmony_ci	 */
1528c2ecf20Sopenharmony_ci	old_handler = __debugger;
1538c2ecf20Sopenharmony_ci	__debugger = handle_fault;
1548c2ecf20Sopenharmony_ci	crash_shutdown_cpu = smp_processor_id();
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (setjmp(crash_shutdown_buf) == 0) {
1578c2ecf20Sopenharmony_ci		printk(KERN_EMERG "Activate system reset (dumprestart) "
1588c2ecf20Sopenharmony_ci				  "to stop other cpu(s)\n");
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		/*
1618c2ecf20Sopenharmony_ci		 * A system reset will force all CPUs to execute the
1628c2ecf20Sopenharmony_ci		 * crash code again. We need to reset cpus_in_crash so we
1638c2ecf20Sopenharmony_ci		 * wait for everyone to do this.
1648c2ecf20Sopenharmony_ci		 */
1658c2ecf20Sopenharmony_ci		atomic_set(&cpus_in_crash, 0);
1668c2ecf20Sopenharmony_ci		smp_mb();
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		while (atomic_read(&cpus_in_crash) < ncpus)
1698c2ecf20Sopenharmony_ci			cpu_relax();
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	crash_shutdown_cpu = -1;
1738c2ecf20Sopenharmony_ci	__debugger = old_handler;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	tries++;
1768c2ecf20Sopenharmony_ci	goto again;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/*
1808c2ecf20Sopenharmony_ci * This function will be called by secondary cpus.
1818c2ecf20Sopenharmony_ci */
1828c2ecf20Sopenharmony_civoid crash_kexec_secondary(struct pt_regs *regs)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	unsigned long flags;
1858c2ecf20Sopenharmony_ci	int msecs = SECONDARY_TIMEOUT;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	local_irq_save(flags);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* Wait for the primary crash CPU to signal its progress */
1908c2ecf20Sopenharmony_ci	while (crashing_cpu < 0) {
1918c2ecf20Sopenharmony_ci		if (--msecs < 0) {
1928c2ecf20Sopenharmony_ci			/* No response, kdump image may not have been loaded */
1938c2ecf20Sopenharmony_ci			local_irq_restore(flags);
1948c2ecf20Sopenharmony_ci			return;
1958c2ecf20Sopenharmony_ci		}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		mdelay(1);
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	crash_ipi_callback(regs);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci#else	/* ! CONFIG_SMP */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic void crash_kexec_prepare_cpus(int cpu)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	/*
2088c2ecf20Sopenharmony_ci	 * move the secondaries to us so that we can copy
2098c2ecf20Sopenharmony_ci	 * the new kernel 0-0x100 safely
2108c2ecf20Sopenharmony_ci	 *
2118c2ecf20Sopenharmony_ci	 * do this if kexec in setup.c ?
2128c2ecf20Sopenharmony_ci	 */
2138c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
2148c2ecf20Sopenharmony_ci	smp_release_cpus();
2158c2ecf20Sopenharmony_ci#else
2168c2ecf20Sopenharmony_ci	/* FIXME */
2178c2ecf20Sopenharmony_ci#endif
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_civoid crash_kexec_secondary(struct pt_regs *regs)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci#endif	/* CONFIG_SMP */
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci/* wait for all the CPUs to hit real mode but timeout if they don't come in */
2268c2ecf20Sopenharmony_ci#if defined(CONFIG_SMP) && defined(CONFIG_PPC64)
2278c2ecf20Sopenharmony_cistatic void __maybe_unused crash_kexec_wait_realmode(int cpu)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	unsigned int msecs;
2308c2ecf20Sopenharmony_ci	int i;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	msecs = REAL_MODE_TIMEOUT;
2338c2ecf20Sopenharmony_ci	for (i=0; i < nr_cpu_ids && msecs > 0; i++) {
2348c2ecf20Sopenharmony_ci		if (i == cpu)
2358c2ecf20Sopenharmony_ci			continue;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		while (paca_ptrs[i]->kexec_state < KEXEC_STATE_REAL_MODE) {
2388c2ecf20Sopenharmony_ci			barrier();
2398c2ecf20Sopenharmony_ci			if (!cpu_possible(i) || !cpu_online(i) || (msecs <= 0))
2408c2ecf20Sopenharmony_ci				break;
2418c2ecf20Sopenharmony_ci			msecs--;
2428c2ecf20Sopenharmony_ci			mdelay(1);
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	mb();
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci#else
2488c2ecf20Sopenharmony_cistatic inline void crash_kexec_wait_realmode(int cpu) {}
2498c2ecf20Sopenharmony_ci#endif	/* CONFIG_SMP && CONFIG_PPC64 */
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/*
2528c2ecf20Sopenharmony_ci * Register a function to be called on shutdown.  Only use this if you
2538c2ecf20Sopenharmony_ci * can't reset your device in the second kernel.
2548c2ecf20Sopenharmony_ci */
2558c2ecf20Sopenharmony_ciint crash_shutdown_register(crash_shutdown_t handler)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	unsigned int i, rc;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	spin_lock(&crash_handlers_lock);
2608c2ecf20Sopenharmony_ci	for (i = 0 ; i < CRASH_HANDLER_MAX; i++)
2618c2ecf20Sopenharmony_ci		if (!crash_shutdown_handles[i]) {
2628c2ecf20Sopenharmony_ci			/* Insert handle at first empty entry */
2638c2ecf20Sopenharmony_ci			crash_shutdown_handles[i] = handler;
2648c2ecf20Sopenharmony_ci			rc = 0;
2658c2ecf20Sopenharmony_ci			break;
2668c2ecf20Sopenharmony_ci		}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (i == CRASH_HANDLER_MAX) {
2698c2ecf20Sopenharmony_ci		printk(KERN_ERR "Crash shutdown handles full, "
2708c2ecf20Sopenharmony_ci		       "not registered.\n");
2718c2ecf20Sopenharmony_ci		rc = 1;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	spin_unlock(&crash_handlers_lock);
2758c2ecf20Sopenharmony_ci	return rc;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(crash_shutdown_register);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ciint crash_shutdown_unregister(crash_shutdown_t handler)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	unsigned int i, rc;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	spin_lock(&crash_handlers_lock);
2848c2ecf20Sopenharmony_ci	for (i = 0 ; i < CRASH_HANDLER_MAX; i++)
2858c2ecf20Sopenharmony_ci		if (crash_shutdown_handles[i] == handler)
2868c2ecf20Sopenharmony_ci			break;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (i == CRASH_HANDLER_MAX) {
2898c2ecf20Sopenharmony_ci		printk(KERN_ERR "Crash shutdown handle not found\n");
2908c2ecf20Sopenharmony_ci		rc = 1;
2918c2ecf20Sopenharmony_ci	} else {
2928c2ecf20Sopenharmony_ci		/* Shift handles down */
2938c2ecf20Sopenharmony_ci		for (; i < (CRASH_HANDLER_MAX - 1); i++)
2948c2ecf20Sopenharmony_ci			crash_shutdown_handles[i] =
2958c2ecf20Sopenharmony_ci				crash_shutdown_handles[i+1];
2968c2ecf20Sopenharmony_ci		/*
2978c2ecf20Sopenharmony_ci		 * Reset last entry to NULL now that it has been shifted down,
2988c2ecf20Sopenharmony_ci		 * this will allow new handles to be added here.
2998c2ecf20Sopenharmony_ci		 */
3008c2ecf20Sopenharmony_ci		crash_shutdown_handles[i] = NULL;
3018c2ecf20Sopenharmony_ci		rc = 0;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	spin_unlock(&crash_handlers_lock);
3058c2ecf20Sopenharmony_ci	return rc;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(crash_shutdown_unregister);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_civoid default_machine_crash_shutdown(struct pt_regs *regs)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	unsigned int i;
3128c2ecf20Sopenharmony_ci	int (*old_handler)(struct pt_regs *regs);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* Avoid hardlocking with irresponsive CPU holding logbuf_lock */
3158c2ecf20Sopenharmony_ci	printk_nmi_enter();
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/*
3188c2ecf20Sopenharmony_ci	 * This function is only called after the system
3198c2ecf20Sopenharmony_ci	 * has panicked or is otherwise in a critical state.
3208c2ecf20Sopenharmony_ci	 * The minimum amount of code to allow a kexec'd kernel
3218c2ecf20Sopenharmony_ci	 * to run successfully needs to happen here.
3228c2ecf20Sopenharmony_ci	 *
3238c2ecf20Sopenharmony_ci	 * In practice this means stopping other cpus in
3248c2ecf20Sopenharmony_ci	 * an SMP system.
3258c2ecf20Sopenharmony_ci	 * The kernel is broken so disable interrupts.
3268c2ecf20Sopenharmony_ci	 */
3278c2ecf20Sopenharmony_ci	hard_irq_disable();
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/*
3308c2ecf20Sopenharmony_ci	 * Make a note of crashing cpu. Will be used in machine_kexec
3318c2ecf20Sopenharmony_ci	 * such that another IPI will not be sent.
3328c2ecf20Sopenharmony_ci	 */
3338c2ecf20Sopenharmony_ci	crashing_cpu = smp_processor_id();
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/*
3368c2ecf20Sopenharmony_ci	 * If we came in via system reset, wait a while for the secondary
3378c2ecf20Sopenharmony_ci	 * CPUs to enter.
3388c2ecf20Sopenharmony_ci	 */
3398c2ecf20Sopenharmony_ci	if (TRAP(regs) == 0x100)
3408c2ecf20Sopenharmony_ci		mdelay(PRIMARY_TIMEOUT);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	crash_kexec_prepare_cpus(crashing_cpu);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	crash_save_cpu(regs, crashing_cpu);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	time_to_dump = 1;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	crash_kexec_wait_realmode(crashing_cpu);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	machine_kexec_mask_interrupts();
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/*
3538c2ecf20Sopenharmony_ci	 * Call registered shutdown routines safely.  Swap out
3548c2ecf20Sopenharmony_ci	 * __debugger_fault_handler, and replace on exit.
3558c2ecf20Sopenharmony_ci	 */
3568c2ecf20Sopenharmony_ci	old_handler = __debugger_fault_handler;
3578c2ecf20Sopenharmony_ci	__debugger_fault_handler = handle_fault;
3588c2ecf20Sopenharmony_ci	crash_shutdown_cpu = smp_processor_id();
3598c2ecf20Sopenharmony_ci	for (i = 0; i < CRASH_HANDLER_MAX && crash_shutdown_handles[i]; i++) {
3608c2ecf20Sopenharmony_ci		if (setjmp(crash_shutdown_buf) == 0) {
3618c2ecf20Sopenharmony_ci			/*
3628c2ecf20Sopenharmony_ci			 * Insert syncs and delay to ensure
3638c2ecf20Sopenharmony_ci			 * instructions in the dangerous region don't
3648c2ecf20Sopenharmony_ci			 * leak away from this protected region.
3658c2ecf20Sopenharmony_ci			 */
3668c2ecf20Sopenharmony_ci			asm volatile("sync; isync");
3678c2ecf20Sopenharmony_ci			/* dangerous region */
3688c2ecf20Sopenharmony_ci			crash_shutdown_handles[i]();
3698c2ecf20Sopenharmony_ci			asm volatile("sync; isync");
3708c2ecf20Sopenharmony_ci		}
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci	crash_shutdown_cpu = -1;
3738c2ecf20Sopenharmony_ci	__debugger_fault_handler = old_handler;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (ppc_md.kexec_cpu_down)
3768c2ecf20Sopenharmony_ci		ppc_md.kexec_cpu_down(1, 0);
3778c2ecf20Sopenharmony_ci}
378