1 /* 2 * arch/ia64/kernel/crash.c 3 * 4 * Architecture specific (ia64) functions for kexec based crash dumps. 5 * 6 * Created by: Khalid Aziz <khalid.aziz@hp.com> 7 * Copyright (C) 2005 Hewlett-Packard Development Company, L.P. 8 * Copyright (C) 2005 Intel Corp Zou Nan hai <nanhai.zou@intel.com> 9 * 10 */ 11 #include <linux/smp.h> 12 #include <linux/delay.h> 13 #include <linux/crash_dump.h> 14 #include <linux/bootmem.h> 15 #include <linux/kexec.h> 16 #include <linux/elfcore.h> 17 #include <linux/sysctl.h> 18 #include <linux/init.h> 19 #include <linux/kdebug.h> 20 21 #include <asm/mca.h> 22 23 int kdump_status[NR_CPUS]; 24 static atomic_t kdump_cpu_frozen; 25 atomic_t kdump_in_progress; 26 static int kdump_on_init = 1; 27 28 static inline Elf64_Word 29 *append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data, 30 size_t data_len) 31 { 32 struct elf_note *note = (struct elf_note *)buf; 33 note->n_namesz = strlen(name) + 1; 34 note->n_descsz = data_len; 35 note->n_type = type; 36 buf += (sizeof(*note) + 3)/4; 37 memcpy(buf, name, note->n_namesz); 38 buf += (note->n_namesz + 3)/4; 39 memcpy(buf, data, data_len); 40 buf += (data_len + 3)/4; 41 return buf; 42 } 43 44 static void 45 final_note(void *buf) 46 { 47 memset(buf, 0, sizeof(struct elf_note)); 48 } 49 50 extern void ia64_dump_cpu_regs(void *); 51 52 static DEFINE_PER_CPU(struct elf_prstatus, elf_prstatus); 53 54 void 55 crash_save_this_cpu(void) 56 { 57 void *buf; 58 unsigned long cfm, sof, sol; 59 60 int cpu = smp_processor_id(); 61 struct elf_prstatus *prstatus = &per_cpu(elf_prstatus, cpu); 62 63 elf_greg_t *dst = (elf_greg_t *)&(prstatus->pr_reg); 64 memset(prstatus, 0, sizeof(*prstatus)); 65 prstatus->pr_pid = current->pid; 66 67 ia64_dump_cpu_regs(dst); 68 cfm = dst[43]; 69 sol = (cfm >> 7) & 0x7f; 70 sof = cfm & 0x7f; 71 dst[46] = (unsigned long)ia64_rse_skip_regs((unsigned long *)dst[46], 72 sof - sol); 73 74 buf = (u64 *) per_cpu_ptr(crash_notes, cpu); 75 if (!buf) 76 return; 77 buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, prstatus, 78 sizeof(*prstatus)); 79 final_note(buf); 80 } 81 82 #ifdef CONFIG_SMP 83 static int 84 kdump_wait_cpu_freeze(void) 85 { 86 int cpu_num = num_online_cpus() - 1; 87 int timeout = 1000; 88 while(timeout-- > 0) { 89 if (atomic_read(&kdump_cpu_frozen) == cpu_num) 90 return 0; 91 udelay(1000); 92 } 93 return 1; 94 } 95 #endif 96 97 void 98 machine_crash_shutdown(struct pt_regs *pt) 99 { 100 /* This function is only called after the system 101 * has paniced or is otherwise in a critical state. 102 * The minimum amount of code to allow a kexec'd kernel 103 * to run successfully needs to happen here. 104 * 105 * In practice this means shooting down the other cpus in 106 * an SMP system. 107 */ 108 kexec_disable_iosapic(); 109 #ifdef CONFIG_SMP 110 kdump_smp_send_stop(); 111 /* not all cpu response to IPI, send INIT to freeze them */ 112 if (kdump_wait_cpu_freeze() && kdump_on_init) { 113 kdump_smp_send_init(); 114 } 115 #endif 116 } 117 118 static void 119 machine_kdump_on_init(void) 120 { 121 local_irq_disable(); 122 kexec_disable_iosapic(); 123 machine_kexec(ia64_kimage); 124 } 125 126 void 127 kdump_cpu_freeze(struct unw_frame_info *info, void *arg) 128 { 129 int cpuid; 130 local_irq_disable(); 131 cpuid = smp_processor_id(); 132 crash_save_this_cpu(); 133 current->thread.ksp = (__u64)info->sw - 16; 134 atomic_inc(&kdump_cpu_frozen); 135 kdump_status[cpuid] = 1; 136 mb(); 137 #ifdef CONFIG_HOTPLUG_CPU 138 if (cpuid != 0) 139 ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]); 140 #endif 141 for (;;) 142 cpu_relax(); 143 } 144 145 static int 146 kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data) 147 { 148 struct ia64_mca_notify_die *nd; 149 struct die_args *args = data; 150 151 if (!kdump_on_init) 152 return NOTIFY_DONE; 153 154 if (!ia64_kimage) { 155 if (val == DIE_INIT_MONARCH_LEAVE) 156 ia64_mca_printk(KERN_NOTICE 157 "%s: kdump not configured\n", 158 __func__); 159 return NOTIFY_DONE; 160 } 161 162 if (val != DIE_INIT_MONARCH_LEAVE && 163 val != DIE_INIT_SLAVE_LEAVE && 164 val != DIE_INIT_MONARCH_PROCESS && 165 val != DIE_MCA_RENDZVOUS_LEAVE && 166 val != DIE_MCA_MONARCH_LEAVE) 167 return NOTIFY_DONE; 168 169 nd = (struct ia64_mca_notify_die *)args->err; 170 /* Reason code 1 means machine check rendezvous*/ 171 if ((val == DIE_INIT_MONARCH_LEAVE || val == DIE_INIT_SLAVE_LEAVE 172 || val == DIE_INIT_MONARCH_PROCESS) && nd->sos->rv_rc == 1) 173 return NOTIFY_DONE; 174 175 switch (val) { 176 case DIE_INIT_MONARCH_PROCESS: 177 atomic_set(&kdump_in_progress, 1); 178 *(nd->monarch_cpu) = -1; 179 break; 180 case DIE_INIT_MONARCH_LEAVE: 181 machine_kdump_on_init(); 182 break; 183 case DIE_INIT_SLAVE_LEAVE: 184 if (atomic_read(&kdump_in_progress)) 185 unw_init_running(kdump_cpu_freeze, NULL); 186 break; 187 case DIE_MCA_RENDZVOUS_LEAVE: 188 if (atomic_read(&kdump_in_progress)) 189 unw_init_running(kdump_cpu_freeze, NULL); 190 break; 191 case DIE_MCA_MONARCH_LEAVE: 192 /* die_register->signr indicate if MCA is recoverable */ 193 if (!args->signr) 194 machine_kdump_on_init(); 195 break; 196 } 197 return NOTIFY_DONE; 198 } 199 200 #ifdef CONFIG_SYSCTL 201 static ctl_table kdump_on_init_table[] = { 202 { 203 .ctl_name = CTL_UNNUMBERED, 204 .procname = "kdump_on_init", 205 .data = &kdump_on_init, 206 .maxlen = sizeof(int), 207 .mode = 0644, 208 .proc_handler = &proc_dointvec, 209 }, 210 { .ctl_name = 0 } 211 }; 212 213 static ctl_table sys_table[] = { 214 { 215 .ctl_name = CTL_KERN, 216 .procname = "kernel", 217 .mode = 0555, 218 .child = kdump_on_init_table, 219 }, 220 { .ctl_name = 0 } 221 }; 222 #endif 223 224 static int 225 machine_crash_setup(void) 226 { 227 /* be notified before default_monarch_init_process */ 228 static struct notifier_block kdump_init_notifier_nb = { 229 .notifier_call = kdump_init_notifier, 230 .priority = 1, 231 }; 232 int ret; 233 if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0) 234 return ret; 235 #ifdef CONFIG_SYSCTL 236 register_sysctl_table(sys_table); 237 #endif 238 return 0; 239 } 240 241 __initcall(machine_crash_setup); 242 243