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 if (!ia64_kimage) { 122 printk(KERN_NOTICE "machine_kdump_on_init(): " 123 "kdump not configured\n"); 124 return; 125 } 126 local_irq_disable(); 127 kexec_disable_iosapic(); 128 machine_kexec(ia64_kimage); 129 } 130 131 void 132 kdump_cpu_freeze(struct unw_frame_info *info, void *arg) 133 { 134 int cpuid; 135 local_irq_disable(); 136 cpuid = smp_processor_id(); 137 crash_save_this_cpu(); 138 current->thread.ksp = (__u64)info->sw - 16; 139 atomic_inc(&kdump_cpu_frozen); 140 kdump_status[cpuid] = 1; 141 mb(); 142 #ifdef CONFIG_HOTPLUG_CPU 143 if (cpuid != 0) 144 ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]); 145 #endif 146 for (;;) 147 cpu_relax(); 148 } 149 150 static int 151 kdump_init_notifier(struct notifier_block *self, unsigned long val, void *data) 152 { 153 struct ia64_mca_notify_die *nd; 154 struct die_args *args = data; 155 156 if (!kdump_on_init) 157 return NOTIFY_DONE; 158 159 if (val != DIE_INIT_MONARCH_LEAVE && 160 val != DIE_INIT_SLAVE_LEAVE && 161 val != DIE_INIT_MONARCH_PROCESS && 162 val != DIE_MCA_RENDZVOUS_LEAVE && 163 val != DIE_MCA_MONARCH_LEAVE) 164 return NOTIFY_DONE; 165 166 nd = (struct ia64_mca_notify_die *)args->err; 167 /* Reason code 1 means machine check rendezvous*/ 168 if ((val == DIE_INIT_MONARCH_LEAVE || val == DIE_INIT_SLAVE_LEAVE 169 || val == DIE_INIT_MONARCH_PROCESS) && nd->sos->rv_rc == 1) 170 return NOTIFY_DONE; 171 172 switch (val) { 173 case DIE_INIT_MONARCH_PROCESS: 174 atomic_set(&kdump_in_progress, 1); 175 *(nd->monarch_cpu) = -1; 176 break; 177 case DIE_INIT_MONARCH_LEAVE: 178 machine_kdump_on_init(); 179 break; 180 case DIE_INIT_SLAVE_LEAVE: 181 if (atomic_read(&kdump_in_progress)) 182 unw_init_running(kdump_cpu_freeze, NULL); 183 break; 184 case DIE_MCA_RENDZVOUS_LEAVE: 185 if (atomic_read(&kdump_in_progress)) 186 unw_init_running(kdump_cpu_freeze, NULL); 187 break; 188 case DIE_MCA_MONARCH_LEAVE: 189 /* die_register->signr indicate if MCA is recoverable */ 190 if (!args->signr) 191 machine_kdump_on_init(); 192 break; 193 } 194 return NOTIFY_DONE; 195 } 196 197 #ifdef CONFIG_SYSCTL 198 static ctl_table kdump_on_init_table[] = { 199 { 200 .ctl_name = CTL_UNNUMBERED, 201 .procname = "kdump_on_init", 202 .data = &kdump_on_init, 203 .maxlen = sizeof(int), 204 .mode = 0644, 205 .proc_handler = &proc_dointvec, 206 }, 207 { .ctl_name = 0 } 208 }; 209 210 static ctl_table sys_table[] = { 211 { 212 .ctl_name = CTL_KERN, 213 .procname = "kernel", 214 .mode = 0555, 215 .child = kdump_on_init_table, 216 }, 217 { .ctl_name = 0 } 218 }; 219 #endif 220 221 static int 222 machine_crash_setup(void) 223 { 224 /* be notified before default_monarch_init_process */ 225 static struct notifier_block kdump_init_notifier_nb = { 226 .notifier_call = kdump_init_notifier, 227 .priority = 1, 228 }; 229 int ret; 230 if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0) 231 return ret; 232 #ifdef CONFIG_SYSCTL 233 register_sysctl_table(sys_table); 234 #endif 235 return 0; 236 } 237 238 __initcall(machine_crash_setup); 239 240