1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2a7956113SZou Nan hai /*
3a7956113SZou Nan hai * arch/ia64/kernel/crash.c
4a7956113SZou Nan hai *
5a7956113SZou Nan hai * Architecture specific (ia64) functions for kexec based crash dumps.
6a7956113SZou Nan hai *
7a7956113SZou Nan hai * Created by: Khalid Aziz <khalid.aziz@hp.com>
8a7956113SZou Nan hai * Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
9a7956113SZou Nan hai * Copyright (C) 2005 Intel Corp Zou Nan hai <nanhai.zou@intel.com>
10a7956113SZou Nan hai *
11a7956113SZou Nan hai */
12a7956113SZou Nan hai #include <linux/smp.h>
13a7956113SZou Nan hai #include <linux/delay.h>
14a7956113SZou Nan hai #include <linux/crash_dump.h>
1557c8a661SMike Rapoport #include <linux/memblock.h>
16a7956113SZou Nan hai #include <linux/kexec.h>
17a7956113SZou Nan hai #include <linux/elfcore.h>
18a5b7c61eSMasahiro Yamada #include <linux/reboot.h>
19a7956113SZou Nan hai #include <linux/sysctl.h>
20a7956113SZou Nan hai #include <linux/init.h>
211eeb66a1SChristoph Hellwig #include <linux/kdebug.h>
22a7956113SZou Nan hai
23a7956113SZou Nan hai #include <asm/mca.h>
24a7956113SZou Nan hai
25a7956113SZou Nan hai int kdump_status[NR_CPUS];
260ac1facaSSimon Horman static atomic_t kdump_cpu_frozen;
27a7956113SZou Nan hai atomic_t kdump_in_progress;
281726b088SHidetoshi Seto static int kdump_freeze_monarch;
290ac1facaSSimon Horman static int kdump_on_init = 1;
30b0247a55SHidetoshi Seto static int kdump_on_fatal_mca = 1;
31a7956113SZou Nan hai
32a7956113SZou Nan hai extern void ia64_dump_cpu_regs(void *);
33a7956113SZou Nan hai
34a7956113SZou Nan hai static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus);
35a7956113SZou Nan hai
36a7956113SZou Nan hai void
crash_save_this_cpu(void)37ccbebdacSAl Viro crash_save_this_cpu(void)
38a7956113SZou Nan hai {
39a7956113SZou Nan hai void *buf;
40a7956113SZou Nan hai unsigned long cfm, sof, sol;
41a7956113SZou Nan hai
42a7956113SZou Nan hai int cpu = smp_processor_id();
43a7956113SZou Nan hai struct elf_prstatus *prstatus = &per_cpu(elf_prstatus, cpu);
44a7956113SZou Nan hai
45a7956113SZou Nan hai elf_greg_t *dst = (elf_greg_t *)&(prstatus->pr_reg);
46a7956113SZou Nan hai memset(prstatus, 0, sizeof(*prstatus));
47f2485a2dSAl Viro prstatus->common.pr_pid = current->pid;
48a7956113SZou Nan hai
49a7956113SZou Nan hai ia64_dump_cpu_regs(dst);
50a7956113SZou Nan hai cfm = dst[43];
51a7956113SZou Nan hai sol = (cfm >> 7) & 0x7f;
52a7956113SZou Nan hai sof = cfm & 0x7f;
53a7956113SZou Nan hai dst[46] = (unsigned long)ia64_rse_skip_regs((unsigned long *)dst[46],
54a7956113SZou Nan hai sof - sol);
55a7956113SZou Nan hai
56a7956113SZou Nan hai buf = (u64 *) per_cpu_ptr(crash_notes, cpu);
57a7956113SZou Nan hai if (!buf)
58a7956113SZou Nan hai return;
596672f76aSSimon Horman buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, prstatus,
60a7956113SZou Nan hai sizeof(*prstatus));
61a7956113SZou Nan hai final_note(buf);
62a7956113SZou Nan hai }
63a7956113SZou Nan hai
64bcb9b99dSMagnus Damm #ifdef CONFIG_SMP
65a7956113SZou Nan hai static int
kdump_wait_cpu_freeze(void)66a7956113SZou Nan hai kdump_wait_cpu_freeze(void)
67a7956113SZou Nan hai {
68a7956113SZou Nan hai int cpu_num = num_online_cpus() - 1;
69a7956113SZou Nan hai int timeout = 1000;
70a7956113SZou Nan hai while(timeout-- > 0) {
710ac1facaSSimon Horman if (atomic_read(&kdump_cpu_frozen) == cpu_num)
72a7956113SZou Nan hai return 0;
73a7956113SZou Nan hai udelay(1000);
74a7956113SZou Nan hai }
75a7956113SZou Nan hai return 1;
76a7956113SZou Nan hai }
77bcb9b99dSMagnus Damm #endif
78a7956113SZou Nan hai
79a7956113SZou Nan hai void
machine_crash_shutdown(struct pt_regs * pt)80a7956113SZou Nan hai machine_crash_shutdown(struct pt_regs *pt)
81a7956113SZou Nan hai {
82a7956113SZou Nan hai /* This function is only called after the system
83a7956113SZou Nan hai * has paniced or is otherwise in a critical state.
84a7956113SZou Nan hai * The minimum amount of code to allow a kexec'd kernel
85a7956113SZou Nan hai * to run successfully needs to happen here.
86a7956113SZou Nan hai *
87a7956113SZou Nan hai * In practice this means shooting down the other cpus in
88a7956113SZou Nan hai * an SMP system.
89a7956113SZou Nan hai */
90a7956113SZou Nan hai kexec_disable_iosapic();
91a7956113SZou Nan hai #ifdef CONFIG_SMP
921726b088SHidetoshi Seto /*
931726b088SHidetoshi Seto * If kdump_on_init is set and an INIT is asserted here, kdump will
941726b088SHidetoshi Seto * be started again via INIT monarch.
951726b088SHidetoshi Seto */
961726b088SHidetoshi Seto local_irq_disable();
971726b088SHidetoshi Seto ia64_set_psr_mc(); /* mask MCA/INIT */
981726b088SHidetoshi Seto if (atomic_inc_return(&kdump_in_progress) != 1)
991726b088SHidetoshi Seto unw_init_running(kdump_cpu_freeze, NULL);
1001726b088SHidetoshi Seto
1011726b088SHidetoshi Seto /*
1021726b088SHidetoshi Seto * Now this cpu is ready for kdump.
1031726b088SHidetoshi Seto * Stop all others by IPI or INIT. They could receive INIT from
1041726b088SHidetoshi Seto * outside and might be INIT monarch, but only thing they have to
1051726b088SHidetoshi Seto * do is falling into kdump_cpu_freeze().
1061726b088SHidetoshi Seto *
1071726b088SHidetoshi Seto * If an INIT is asserted here:
1081726b088SHidetoshi Seto * - All receivers might be slaves, since some of cpus could already
1091726b088SHidetoshi Seto * be frozen and INIT might be masked on monarch. In this case,
1100cced40eSHidetoshi Seto * all slaves will be frozen soon since kdump_in_progress will let
1110cced40eSHidetoshi Seto * them into DIE_INIT_SLAVE_LEAVE.
1121726b088SHidetoshi Seto * - One might be a monarch, but INIT rendezvous will fail since
1131726b088SHidetoshi Seto * at least this cpu already have INIT masked so it never join
1141726b088SHidetoshi Seto * to the rendezvous. In this case, all slaves and monarch will
1150cced40eSHidetoshi Seto * be frozen soon with no wait since the INIT rendezvous is skipped
1160cced40eSHidetoshi Seto * by kdump_in_progress.
1171726b088SHidetoshi Seto */
118a7956113SZou Nan hai kdump_smp_send_stop();
1190ac1facaSSimon Horman /* not all cpu response to IPI, send INIT to freeze them */
1205959906eSHidetoshi Seto if (kdump_wait_cpu_freeze()) {
121a7956113SZou Nan hai kdump_smp_send_init();
1225959906eSHidetoshi Seto /* wait again, don't go ahead if possible */
1235959906eSHidetoshi Seto kdump_wait_cpu_freeze();
124a7956113SZou Nan hai }
125a7956113SZou Nan hai #endif
126a7956113SZou Nan hai }
127a7956113SZou Nan hai
128a7956113SZou Nan hai static void
machine_kdump_on_init(void)129a7956113SZou Nan hai machine_kdump_on_init(void)
130a7956113SZou Nan hai {
131072f042dSTakao Indoh crash_save_vmcoreinfo();
132a7956113SZou Nan hai local_irq_disable();
133a7956113SZou Nan hai kexec_disable_iosapic();
134a7956113SZou Nan hai machine_kexec(ia64_kimage);
135a7956113SZou Nan hai }
136a7956113SZou Nan hai
137a7956113SZou Nan hai void
kdump_cpu_freeze(struct unw_frame_info * info,void * arg)138a7956113SZou Nan hai kdump_cpu_freeze(struct unw_frame_info *info, void *arg)
139a7956113SZou Nan hai {
140a7956113SZou Nan hai int cpuid;
1414295ab34SHidetoshi Seto
142a7956113SZou Nan hai local_irq_disable();
143a7956113SZou Nan hai cpuid = smp_processor_id();
144a7956113SZou Nan hai crash_save_this_cpu();
145a7956113SZou Nan hai current->thread.ksp = (__u64)info->sw - 16;
1464295ab34SHidetoshi Seto
1474295ab34SHidetoshi Seto ia64_set_psr_mc(); /* mask MCA/INIT and stop reentrance */
1484295ab34SHidetoshi Seto
1490ac1facaSSimon Horman atomic_inc(&kdump_cpu_frozen);
150a7956113SZou Nan hai kdump_status[cpuid] = 1;
151a7956113SZou Nan hai mb();
152a7956113SZou Nan hai for (;;)
153a7956113SZou Nan hai cpu_relax();
154a7956113SZou Nan hai }
155a7956113SZou Nan hai
156a7956113SZou Nan hai static int
kdump_init_notifier(struct notifier_block * self,unsigned long val,void * data)157a7956113SZou Nan hai kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data)
158a7956113SZou Nan hai {
159a7956113SZou Nan hai struct ia64_mca_notify_die *nd;
160a7956113SZou Nan hai struct die_args *args = data;
161a7956113SZou Nan hai
1625959906eSHidetoshi Seto if (atomic_read(&kdump_in_progress)) {
1635959906eSHidetoshi Seto switch (val) {
1645959906eSHidetoshi Seto case DIE_INIT_MONARCH_LEAVE:
1655959906eSHidetoshi Seto if (!kdump_freeze_monarch)
1665959906eSHidetoshi Seto break;
167df561f66SGustavo A. R. Silva fallthrough;
1685959906eSHidetoshi Seto case DIE_INIT_SLAVE_LEAVE:
1690cced40eSHidetoshi Seto case DIE_INIT_MONARCH_ENTER:
1705959906eSHidetoshi Seto case DIE_MCA_RENDZVOUS_LEAVE:
1715959906eSHidetoshi Seto unw_init_running(kdump_cpu_freeze, NULL);
1725959906eSHidetoshi Seto break;
1735959906eSHidetoshi Seto }
1745959906eSHidetoshi Seto }
1755959906eSHidetoshi Seto
176b0247a55SHidetoshi Seto if (!kdump_on_init && !kdump_on_fatal_mca)
177a7956113SZou Nan hai return NOTIFY_DONE;
178a7956113SZou Nan hai
1792010d7feSKenji Kaneshige if (!ia64_kimage) {
1802010d7feSKenji Kaneshige if (val == DIE_INIT_MONARCH_LEAVE)
1812010d7feSKenji Kaneshige ia64_mca_printk(KERN_NOTICE
1822010d7feSKenji Kaneshige "%s: kdump not configured\n",
183d4ed8084SHarvey Harrison __func__);
1842010d7feSKenji Kaneshige return NOTIFY_DONE;
1852010d7feSKenji Kaneshige }
1862010d7feSKenji Kaneshige
187311f594dSJay Lan if (val != DIE_INIT_MONARCH_LEAVE &&
188311f594dSJay Lan val != DIE_INIT_MONARCH_PROCESS &&
189a7956113SZou Nan hai val != DIE_MCA_MONARCH_LEAVE)
190a7956113SZou Nan hai return NOTIFY_DONE;
191a7956113SZou Nan hai
192a7956113SZou Nan hai nd = (struct ia64_mca_notify_die *)args->err;
193a7956113SZou Nan hai
194a7956113SZou Nan hai switch (val) {
195311f594dSJay Lan case DIE_INIT_MONARCH_PROCESS:
1965959906eSHidetoshi Seto /* Reason code 1 means machine check rendezvous*/
1975959906eSHidetoshi Seto if (kdump_on_init && (nd->sos->rv_rc != 1)) {
1981726b088SHidetoshi Seto if (atomic_inc_return(&kdump_in_progress) != 1)
1991726b088SHidetoshi Seto kdump_freeze_monarch = 1;
200b0247a55SHidetoshi Seto }
201311f594dSJay Lan break;
202311f594dSJay Lan case DIE_INIT_MONARCH_LEAVE:
2035959906eSHidetoshi Seto /* Reason code 1 means machine check rendezvous*/
2045959906eSHidetoshi Seto if (kdump_on_init && (nd->sos->rv_rc != 1))
205a7956113SZou Nan hai machine_kdump_on_init();
206a7956113SZou Nan hai break;
207a7956113SZou Nan hai case DIE_MCA_MONARCH_LEAVE:
2084fa2f0e6SHidetoshi Seto /* *(nd->data) indicate if MCA is recoverable */
2094fa2f0e6SHidetoshi Seto if (kdump_on_fatal_mca && !(*(nd->data))) {
2100cced40eSHidetoshi Seto if (atomic_inc_return(&kdump_in_progress) == 1)
211a7956113SZou Nan hai machine_kdump_on_init();
2121726b088SHidetoshi Seto /* We got fatal MCA while kdump!? No way!! */
2131726b088SHidetoshi Seto }
214a7956113SZou Nan hai break;
215a7956113SZou Nan hai }
216a7956113SZou Nan hai return NOTIFY_DONE;
217a7956113SZou Nan hai }
218a7956113SZou Nan hai
219a7956113SZou Nan hai #ifdef CONFIG_SYSCTL
2202841efa6SJoe Perches static struct ctl_table kdump_ctl_table[] = {
221a7956113SZou Nan hai {
222a7956113SZou Nan hai .procname = "kdump_on_init",
223a7956113SZou Nan hai .data = &kdump_on_init,
224a7956113SZou Nan hai .maxlen = sizeof(int),
225a7956113SZou Nan hai .mode = 0644,
2266d456111SEric W. Biederman .proc_handler = proc_dointvec,
227a7956113SZou Nan hai },
228b0247a55SHidetoshi Seto {
229b0247a55SHidetoshi Seto .procname = "kdump_on_fatal_mca",
230b0247a55SHidetoshi Seto .data = &kdump_on_fatal_mca,
231b0247a55SHidetoshi Seto .maxlen = sizeof(int),
232b0247a55SHidetoshi Seto .mode = 0644,
2336d456111SEric W. Biederman .proc_handler = proc_dointvec,
234b0247a55SHidetoshi Seto },
235d00faf81SEric W. Biederman { }
236a7956113SZou Nan hai };
237a7956113SZou Nan hai #endif
238a7956113SZou Nan hai
239a7956113SZou Nan hai static int
machine_crash_setup(void)240a7956113SZou Nan hai machine_crash_setup(void)
241a7956113SZou Nan hai {
242311f594dSJay Lan /* be notified before default_monarch_init_process */
243a7956113SZou Nan hai static struct notifier_block kdump_init_notifier_nb = {
244a7956113SZou Nan hai .notifier_call = kdump_init_notifier,
245311f594dSJay Lan .priority = 1,
246a7956113SZou Nan hai };
247a7956113SZou Nan hai int ret;
248a7956113SZou Nan hai if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0)
249a7956113SZou Nan hai return ret;
250a7956113SZou Nan hai #ifdef CONFIG_SYSCTL
251*03860ef0SLuis Chamberlain register_sysctl("kernel", kdump_ctl_table);
252a7956113SZou Nan hai #endif
253a7956113SZou Nan hai return 0;
254a7956113SZou Nan hai }
255a7956113SZou Nan hai
256a7956113SZou Nan hai __initcall(machine_crash_setup);
257a7956113SZou Nan hai
258