162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Architecture specific (PPC64) functions for kexec based crash dumps. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005, IBM Corp. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Created by: Haren Myneni 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/smp.h> 1262306a36Sopenharmony_ci#include <linux/reboot.h> 1362306a36Sopenharmony_ci#include <linux/kexec.h> 1462306a36Sopenharmony_ci#include <linux/export.h> 1562306a36Sopenharmony_ci#include <linux/crash_dump.h> 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci#include <linux/irq.h> 1862306a36Sopenharmony_ci#include <linux/types.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <asm/processor.h> 2162306a36Sopenharmony_ci#include <asm/machdep.h> 2262306a36Sopenharmony_ci#include <asm/kexec.h> 2362306a36Sopenharmony_ci#include <asm/smp.h> 2462306a36Sopenharmony_ci#include <asm/setjmp.h> 2562306a36Sopenharmony_ci#include <asm/debug.h> 2662306a36Sopenharmony_ci#include <asm/interrupt.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * The primary CPU waits a while for all secondary CPUs to enter. This is to 3062306a36Sopenharmony_ci * avoid sending an IPI if the secondary CPUs are entering 3162306a36Sopenharmony_ci * crash_kexec_secondary on their own (eg via a system reset). 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * The secondary timeout has to be longer than the primary. Both timeouts are 3462306a36Sopenharmony_ci * in milliseconds. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci#define PRIMARY_TIMEOUT 500 3762306a36Sopenharmony_ci#define SECONDARY_TIMEOUT 1000 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define IPI_TIMEOUT 10000 4062306a36Sopenharmony_ci#define REAL_MODE_TIMEOUT 10000 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic int time_to_dump; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * In case of system reset, secondary CPUs enter crash_kexec_secondary with out 4662306a36Sopenharmony_ci * having to send an IPI explicitly. So, indicate if the crash is via 4762306a36Sopenharmony_ci * system reset to avoid sending another IPI. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_cistatic int is_via_system_reset; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * crash_wake_offline should be set to 1 by platforms that intend to wake 5362306a36Sopenharmony_ci * up offline cpus prior to jumping to a kdump kernel. Currently powernv 5462306a36Sopenharmony_ci * sets it to 1, since we want to avoid things from happening when an 5562306a36Sopenharmony_ci * offline CPU wakes up due to something like an HMI (malfunction error), 5662306a36Sopenharmony_ci * which propagates to all threads. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ciint crash_wake_offline; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define CRASH_HANDLER_MAX 3 6162306a36Sopenharmony_ci/* List of shutdown handles */ 6262306a36Sopenharmony_cistatic crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX]; 6362306a36Sopenharmony_cistatic DEFINE_SPINLOCK(crash_handlers_lock); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic unsigned long crash_shutdown_buf[JMP_BUF_LEN]; 6662306a36Sopenharmony_cistatic int crash_shutdown_cpu = -1; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int handle_fault(struct pt_regs *regs) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci if (crash_shutdown_cpu == smp_processor_id()) 7162306a36Sopenharmony_ci longjmp(crash_shutdown_buf, 1); 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#ifdef CONFIG_SMP 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic atomic_t cpus_in_crash; 7862306a36Sopenharmony_civoid crash_ipi_callback(struct pt_regs *regs) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci static cpumask_t cpus_state_saved = CPU_MASK_NONE; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci int cpu = smp_processor_id(); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci hard_irq_disable(); 8562306a36Sopenharmony_ci if (!cpumask_test_cpu(cpu, &cpus_state_saved)) { 8662306a36Sopenharmony_ci crash_save_cpu(regs, cpu); 8762306a36Sopenharmony_ci cpumask_set_cpu(cpu, &cpus_state_saved); 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci atomic_inc(&cpus_in_crash); 9162306a36Sopenharmony_ci smp_mb__after_atomic(); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* 9462306a36Sopenharmony_ci * Starting the kdump boot. 9562306a36Sopenharmony_ci * This barrier is needed to make sure that all CPUs are stopped. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci while (!time_to_dump) 9862306a36Sopenharmony_ci cpu_relax(); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (ppc_md.kexec_cpu_down) 10162306a36Sopenharmony_ci ppc_md.kexec_cpu_down(1, 1); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#ifdef CONFIG_PPC64 10462306a36Sopenharmony_ci kexec_smp_wait(); 10562306a36Sopenharmony_ci#else 10662306a36Sopenharmony_ci for (;;); /* FIXME */ 10762306a36Sopenharmony_ci#endif 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* NOTREACHED */ 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void crash_kexec_prepare_cpus(void) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci unsigned int msecs; 11562306a36Sopenharmony_ci volatile unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ 11662306a36Sopenharmony_ci volatile int tries = 0; 11762306a36Sopenharmony_ci int (*old_handler)(struct pt_regs *regs); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci printk(KERN_EMERG "Sending IPI to other CPUs\n"); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (crash_wake_offline) 12262306a36Sopenharmony_ci ncpus = num_present_cpus() - 1; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* 12562306a36Sopenharmony_ci * If we came in via system reset, secondaries enter via crash_kexec_secondary(). 12662306a36Sopenharmony_ci * So, wait a while for the secondary CPUs to enter for that case. 12762306a36Sopenharmony_ci * Else, send IPI to all other CPUs. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci if (is_via_system_reset) 13062306a36Sopenharmony_ci mdelay(PRIMARY_TIMEOUT); 13162306a36Sopenharmony_ci else 13262306a36Sopenharmony_ci crash_send_ipi(crash_ipi_callback); 13362306a36Sopenharmony_ci smp_wmb(); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ciagain: 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * FIXME: Until we will have the way to stop other CPUs reliably, 13862306a36Sopenharmony_ci * the crash CPU will send an IPI and wait for other CPUs to 13962306a36Sopenharmony_ci * respond. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci msecs = IPI_TIMEOUT; 14262306a36Sopenharmony_ci while ((atomic_read(&cpus_in_crash) < ncpus) && (--msecs > 0)) 14362306a36Sopenharmony_ci mdelay(1); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Would it be better to replace the trap vector here? */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (atomic_read(&cpus_in_crash) >= ncpus) { 14862306a36Sopenharmony_ci printk(KERN_EMERG "IPI complete\n"); 14962306a36Sopenharmony_ci return; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci printk(KERN_EMERG "ERROR: %d cpu(s) not responding\n", 15362306a36Sopenharmony_ci ncpus - atomic_read(&cpus_in_crash)); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* 15662306a36Sopenharmony_ci * If we have a panic timeout set then we can't wait indefinitely 15762306a36Sopenharmony_ci * for someone to activate system reset. We also give up on the 15862306a36Sopenharmony_ci * second time through if system reset fail to work. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci if ((panic_timeout > 0) || (tries > 0)) 16162306a36Sopenharmony_ci return; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* 16462306a36Sopenharmony_ci * A system reset will cause all CPUs to take an 0x100 exception. 16562306a36Sopenharmony_ci * The primary CPU returns here via setjmp, and the secondary 16662306a36Sopenharmony_ci * CPUs reexecute the crash_kexec_secondary path. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci old_handler = __debugger; 16962306a36Sopenharmony_ci __debugger = handle_fault; 17062306a36Sopenharmony_ci crash_shutdown_cpu = smp_processor_id(); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (setjmp(crash_shutdown_buf) == 0) { 17362306a36Sopenharmony_ci printk(KERN_EMERG "Activate system reset (dumprestart) " 17462306a36Sopenharmony_ci "to stop other cpu(s)\n"); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * A system reset will force all CPUs to execute the 17862306a36Sopenharmony_ci * crash code again. We need to reset cpus_in_crash so we 17962306a36Sopenharmony_ci * wait for everyone to do this. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci atomic_set(&cpus_in_crash, 0); 18262306a36Sopenharmony_ci smp_mb(); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci while (atomic_read(&cpus_in_crash) < ncpus) 18562306a36Sopenharmony_ci cpu_relax(); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci crash_shutdown_cpu = -1; 18962306a36Sopenharmony_ci __debugger = old_handler; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci tries++; 19262306a36Sopenharmony_ci goto again; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/* 19662306a36Sopenharmony_ci * This function will be called by secondary cpus. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_civoid crash_kexec_secondary(struct pt_regs *regs) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci unsigned long flags; 20162306a36Sopenharmony_ci int msecs = SECONDARY_TIMEOUT; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci local_irq_save(flags); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Wait for the primary crash CPU to signal its progress */ 20662306a36Sopenharmony_ci while (crashing_cpu < 0) { 20762306a36Sopenharmony_ci if (--msecs < 0) { 20862306a36Sopenharmony_ci /* No response, kdump image may not have been loaded */ 20962306a36Sopenharmony_ci local_irq_restore(flags); 21062306a36Sopenharmony_ci return; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci mdelay(1); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci crash_ipi_callback(regs); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#else /* ! CONFIG_SMP */ 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void crash_kexec_prepare_cpus(void) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * move the secondaries to us so that we can copy 22562306a36Sopenharmony_ci * the new kernel 0-0x100 safely 22662306a36Sopenharmony_ci * 22762306a36Sopenharmony_ci * do this if kexec in setup.c ? 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci#ifdef CONFIG_PPC64 23062306a36Sopenharmony_ci smp_release_cpus(); 23162306a36Sopenharmony_ci#else 23262306a36Sopenharmony_ci /* FIXME */ 23362306a36Sopenharmony_ci#endif 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_civoid crash_kexec_secondary(struct pt_regs *regs) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci#endif /* CONFIG_SMP */ 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* wait for all the CPUs to hit real mode but timeout if they don't come in */ 24262306a36Sopenharmony_ci#if defined(CONFIG_SMP) && defined(CONFIG_PPC64) 24362306a36Sopenharmony_cinoinstr static void __maybe_unused crash_kexec_wait_realmode(int cpu) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci unsigned int msecs; 24662306a36Sopenharmony_ci int i; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci msecs = REAL_MODE_TIMEOUT; 24962306a36Sopenharmony_ci for (i=0; i < nr_cpu_ids && msecs > 0; i++) { 25062306a36Sopenharmony_ci if (i == cpu) 25162306a36Sopenharmony_ci continue; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci while (paca_ptrs[i]->kexec_state < KEXEC_STATE_REAL_MODE) { 25462306a36Sopenharmony_ci barrier(); 25562306a36Sopenharmony_ci if (!cpu_possible(i) || !cpu_online(i) || (msecs <= 0)) 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci msecs--; 25862306a36Sopenharmony_ci mdelay(1); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci mb(); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci#else 26462306a36Sopenharmony_cistatic inline void crash_kexec_wait_realmode(int cpu) {} 26562306a36Sopenharmony_ci#endif /* CONFIG_SMP && CONFIG_PPC64 */ 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_civoid crash_kexec_prepare(void) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci /* Avoid hardlocking with irresponsive CPU holding logbuf_lock */ 27062306a36Sopenharmony_ci printk_deferred_enter(); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* 27362306a36Sopenharmony_ci * This function is only called after the system 27462306a36Sopenharmony_ci * has panicked or is otherwise in a critical state. 27562306a36Sopenharmony_ci * The minimum amount of code to allow a kexec'd kernel 27662306a36Sopenharmony_ci * to run successfully needs to happen here. 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * In practice this means stopping other cpus in 27962306a36Sopenharmony_ci * an SMP system. 28062306a36Sopenharmony_ci * The kernel is broken so disable interrupts. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci hard_irq_disable(); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * Make a note of crashing cpu. Will be used in machine_kexec 28662306a36Sopenharmony_ci * such that another IPI will not be sent. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci crashing_cpu = smp_processor_id(); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci crash_kexec_prepare_cpus(); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci/* 29462306a36Sopenharmony_ci * Register a function to be called on shutdown. Only use this if you 29562306a36Sopenharmony_ci * can't reset your device in the second kernel. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ciint crash_shutdown_register(crash_shutdown_t handler) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci unsigned int i, rc; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci spin_lock(&crash_handlers_lock); 30262306a36Sopenharmony_ci for (i = 0 ; i < CRASH_HANDLER_MAX; i++) 30362306a36Sopenharmony_ci if (!crash_shutdown_handles[i]) { 30462306a36Sopenharmony_ci /* Insert handle at first empty entry */ 30562306a36Sopenharmony_ci crash_shutdown_handles[i] = handler; 30662306a36Sopenharmony_ci rc = 0; 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (i == CRASH_HANDLER_MAX) { 31162306a36Sopenharmony_ci printk(KERN_ERR "Crash shutdown handles full, " 31262306a36Sopenharmony_ci "not registered.\n"); 31362306a36Sopenharmony_ci rc = 1; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci spin_unlock(&crash_handlers_lock); 31762306a36Sopenharmony_ci return rc; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ciEXPORT_SYMBOL(crash_shutdown_register); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ciint crash_shutdown_unregister(crash_shutdown_t handler) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci unsigned int i, rc; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci spin_lock(&crash_handlers_lock); 32662306a36Sopenharmony_ci for (i = 0 ; i < CRASH_HANDLER_MAX; i++) 32762306a36Sopenharmony_ci if (crash_shutdown_handles[i] == handler) 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (i == CRASH_HANDLER_MAX) { 33162306a36Sopenharmony_ci printk(KERN_ERR "Crash shutdown handle not found\n"); 33262306a36Sopenharmony_ci rc = 1; 33362306a36Sopenharmony_ci } else { 33462306a36Sopenharmony_ci /* Shift handles down */ 33562306a36Sopenharmony_ci for (; i < (CRASH_HANDLER_MAX - 1); i++) 33662306a36Sopenharmony_ci crash_shutdown_handles[i] = 33762306a36Sopenharmony_ci crash_shutdown_handles[i+1]; 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * Reset last entry to NULL now that it has been shifted down, 34062306a36Sopenharmony_ci * this will allow new handles to be added here. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci crash_shutdown_handles[i] = NULL; 34362306a36Sopenharmony_ci rc = 0; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci spin_unlock(&crash_handlers_lock); 34762306a36Sopenharmony_ci return rc; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ciEXPORT_SYMBOL(crash_shutdown_unregister); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_civoid default_machine_crash_shutdown(struct pt_regs *regs) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci volatile unsigned int i; 35462306a36Sopenharmony_ci int (*old_handler)(struct pt_regs *regs); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (TRAP(regs) == INTERRUPT_SYSTEM_RESET) 35762306a36Sopenharmony_ci is_via_system_reset = 1; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci crash_smp_send_stop(); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci crash_save_cpu(regs, crashing_cpu); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci time_to_dump = 1; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci crash_kexec_wait_realmode(crashing_cpu); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci machine_kexec_mask_interrupts(); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* 37062306a36Sopenharmony_ci * Call registered shutdown routines safely. Swap out 37162306a36Sopenharmony_ci * __debugger_fault_handler, and replace on exit. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci old_handler = __debugger_fault_handler; 37462306a36Sopenharmony_ci __debugger_fault_handler = handle_fault; 37562306a36Sopenharmony_ci crash_shutdown_cpu = smp_processor_id(); 37662306a36Sopenharmony_ci for (i = 0; i < CRASH_HANDLER_MAX && crash_shutdown_handles[i]; i++) { 37762306a36Sopenharmony_ci if (setjmp(crash_shutdown_buf) == 0) { 37862306a36Sopenharmony_ci /* 37962306a36Sopenharmony_ci * Insert syncs and delay to ensure 38062306a36Sopenharmony_ci * instructions in the dangerous region don't 38162306a36Sopenharmony_ci * leak away from this protected region. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci asm volatile("sync; isync"); 38462306a36Sopenharmony_ci /* dangerous region */ 38562306a36Sopenharmony_ci crash_shutdown_handles[i](); 38662306a36Sopenharmony_ci asm volatile("sync; isync"); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci crash_shutdown_cpu = -1; 39062306a36Sopenharmony_ci __debugger_fault_handler = old_handler; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (ppc_md.kexec_cpu_down) 39362306a36Sopenharmony_ci ppc_md.kexec_cpu_down(1, 0); 39462306a36Sopenharmony_ci} 395