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