]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - arch/powerpc/kernel/crash.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6.git] / arch / powerpc / kernel / crash.c
1 /*
2  * Architecture specific (PPC64) functions for kexec based crash dumps.
3  *
4  * Copyright (C) 2005, IBM Corp.
5  *
6  * Created by: Haren Myneni
7  *
8  * This source code is licensed under the GNU General Public License,
9  * Version 2.  See the file COPYING for more details.
10  *
11  */
12
13 #undef DEBUG
14
15 #include <linux/kernel.h>
16 #include <linux/smp.h>
17 #include <linux/reboot.h>
18 #include <linux/kexec.h>
19 #include <linux/bootmem.h>
20 #include <linux/crash_dump.h>
21 #include <linux/delay.h>
22 #include <linux/elf.h>
23 #include <linux/elfcore.h>
24 #include <linux/init.h>
25 #include <linux/irq.h>
26 #include <linux/types.h>
27 #include <linux/irq.h>
28
29 #include <asm/processor.h>
30 #include <asm/machdep.h>
31 #include <asm/kexec.h>
32 #include <asm/kdump.h>
33 #include <asm/lmb.h>
34 #include <asm/firmware.h>
35 #include <asm/smp.h>
36
37 #ifdef DEBUG
38 #include <asm/udbg.h>
39 #define DBG(fmt...) udbg_printf(fmt)
40 #else
41 #define DBG(fmt...)
42 #endif
43
44 /* This keeps a track of which one is crashing cpu. */
45 int crashing_cpu = -1;
46 static cpumask_t cpus_in_crash = CPU_MASK_NONE;
47
48 static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
49                                                                size_t data_len)
50 {
51         struct elf_note note;
52
53         note.n_namesz = strlen(name) + 1;
54         note.n_descsz = data_len;
55         note.n_type   = type;
56         memcpy(buf, &note, sizeof(note));
57         buf += (sizeof(note) +3)/4;
58         memcpy(buf, name, note.n_namesz);
59         buf += (note.n_namesz + 3)/4;
60         memcpy(buf, data, note.n_descsz);
61         buf += (note.n_descsz + 3)/4;
62
63         return buf;
64 }
65
66 static void final_note(u32 *buf)
67 {
68         struct elf_note note;
69
70         note.n_namesz = 0;
71         note.n_descsz = 0;
72         note.n_type   = 0;
73         memcpy(buf, &note, sizeof(note));
74 }
75
76 static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
77 {
78         struct elf_prstatus prstatus;
79         u32 *buf;
80
81         if ((cpu < 0) || (cpu >= NR_CPUS))
82                 return;
83
84         /* Using ELF notes here is opportunistic.
85          * I need a well defined structure format
86          * for the data I pass, and I need tags
87          * on the data to indicate what information I have
88          * squirrelled away.  ELF notes happen to provide
89          * all of that that no need to invent something new.
90          */
91         buf = (u32*)per_cpu_ptr(crash_notes, cpu);
92         if (!buf) 
93                 return;
94
95         memset(&prstatus, 0, sizeof(prstatus));
96         prstatus.pr_pid = current->pid;
97         elf_core_copy_regs(&prstatus.pr_reg, regs);
98         buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
99                         sizeof(prstatus));
100         final_note(buf);
101 }
102
103 #ifdef CONFIG_SMP
104 static atomic_t enter_on_soft_reset = ATOMIC_INIT(0);
105
106 void crash_ipi_callback(struct pt_regs *regs)
107 {
108         int cpu = smp_processor_id();
109
110         if (!cpu_online(cpu))
111                 return;
112
113         local_irq_disable();
114         if (!cpu_isset(cpu, cpus_in_crash))
115                 crash_save_this_cpu(regs, cpu);
116         cpu_set(cpu, cpus_in_crash);
117
118         /*
119          * Entered via soft-reset - could be the kdump
120          * process is invoked using soft-reset or user activated
121          * it if some CPU did not respond to an IPI.
122          * For soft-reset, the secondary CPU can enter this func
123          * twice. 1 - using IPI, and 2. soft-reset.
124          * Tell the kexec CPU that entered via soft-reset and ready
125          * to go down.
126          */
127         if (cpu_isset(cpu, cpus_in_sr)) {
128                 cpu_clear(cpu, cpus_in_sr);
129                 atomic_inc(&enter_on_soft_reset);
130         }
131
132         /*
133          * Starting the kdump boot.
134          * This barrier is needed to make sure that all CPUs are stopped.
135          * If not, soft-reset will be invoked to bring other CPUs.
136          */
137         while (!cpu_isset(crashing_cpu, cpus_in_crash))
138                 cpu_relax();
139
140         if (ppc_md.kexec_cpu_down)
141                 ppc_md.kexec_cpu_down(1, 1);
142         kexec_smp_wait();
143         /* NOTREACHED */
144 }
145
146 /*
147  * Wait until all CPUs are entered via soft-reset.
148  */
149 static void crash_soft_reset_check(int cpu)
150 {
151         unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
152
153         cpu_clear(cpu, cpus_in_sr);
154         while (atomic_read(&enter_on_soft_reset) != ncpus)
155                 cpu_relax();
156 }
157
158
159 static void crash_kexec_prepare_cpus(int cpu)
160 {
161         unsigned int msecs;
162
163         unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
164
165         crash_send_ipi(crash_ipi_callback);
166         smp_wmb();
167
168         /*
169          * FIXME: Until we will have the way to stop other CPUSs reliabally,
170          * the crash CPU will send an IPI and wait for other CPUs to
171          * respond.
172          * Delay of at least 10 seconds.
173          */
174         printk(KERN_EMERG "Sending IPI to other cpus...\n");
175         msecs = 10000;
176         while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) {
177                 cpu_relax();
178                 mdelay(1);
179         }
180
181         /* Would it be better to replace the trap vector here? */
182
183         /*
184          * FIXME: In case if we do not get all CPUs, one possibility: ask the
185          * user to do soft reset such that we get all.
186          * Soft-reset will be used until better mechanism is implemented.
187          */
188         if (cpus_weight(cpus_in_crash) < ncpus) {
189                 printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n",
190                         ncpus - cpus_weight(cpus_in_crash));
191                 printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n");
192                 cpus_in_sr = CPU_MASK_NONE;
193                 atomic_set(&enter_on_soft_reset, 0);
194                 while (cpus_weight(cpus_in_crash) < ncpus)
195                         cpu_relax();
196         }
197         /*
198          * Make sure all CPUs are entered via soft-reset if the kdump is
199          * invoked using soft-reset.
200          */
201         if (cpu_isset(cpu, cpus_in_sr))
202                 crash_soft_reset_check(cpu);
203         /* Leave the IPI callback set */
204 }
205
206 /*
207  * This function will be called by secondary cpus or by kexec cpu
208  * if soft-reset is activated to stop some CPUs.
209  */
210 void crash_kexec_secondary(struct pt_regs *regs)
211 {
212         int cpu = smp_processor_id();
213         unsigned long flags;
214         int msecs = 5;
215
216         local_irq_save(flags);
217         /* Wait 5ms if the kexec CPU is not entered yet. */
218         while (crashing_cpu < 0) {
219                 if (--msecs < 0) {
220                         /*
221                          * Either kdump image is not loaded or
222                          * kdump process is not started - Probably xmon
223                          * exited using 'x'(exit and recover) or
224                          * kexec_should_crash() failed for all running tasks.
225                          */
226                         cpu_clear(cpu, cpus_in_sr);
227                         local_irq_restore(flags);
228                         return;
229                 }
230                 mdelay(1);
231                 cpu_relax();
232         }
233         if (cpu == crashing_cpu) {
234                 /*
235                  * Panic CPU will enter this func only via soft-reset.
236                  * Wait until all secondary CPUs entered and
237                  * then start kexec boot.
238                  */
239                 crash_soft_reset_check(cpu);
240                 cpu_set(crashing_cpu, cpus_in_crash);
241                 if (ppc_md.kexec_cpu_down)
242                         ppc_md.kexec_cpu_down(1, 0);
243                 machine_kexec(kexec_crash_image);
244                 /* NOTREACHED */
245         }
246         crash_ipi_callback(regs);
247 }
248
249 #else
250 static void crash_kexec_prepare_cpus(int cpu)
251 {
252         /*
253          * move the secondarys to us so that we can copy
254          * the new kernel 0-0x100 safely
255          *
256          * do this if kexec in setup.c ?
257          */
258         smp_release_cpus();
259 }
260
261 void crash_kexec_secondary(struct pt_regs *regs)
262 {
263         cpus_in_sr = CPU_MASK_NONE;
264 }
265 #endif
266
267 void default_machine_crash_shutdown(struct pt_regs *regs)
268 {
269         unsigned int irq;
270
271         /*
272          * This function is only called after the system
273          * has panicked or is otherwise in a critical state.
274          * The minimum amount of code to allow a kexec'd kernel
275          * to run successfully needs to happen here.
276          *
277          * In practice this means stopping other cpus in
278          * an SMP system.
279          * The kernel is broken so disable interrupts.
280          */
281         local_irq_disable();
282
283         for_each_irq(irq) {
284                 struct irq_desc *desc = irq_desc + irq;
285
286                 if (desc->status & IRQ_INPROGRESS)
287                         desc->chip->end(irq);
288
289                 if (!(desc->status & IRQ_DISABLED))
290                         desc->chip->disable(irq);
291         }
292
293         /*
294          * Make a note of crashing cpu. Will be used in machine_kexec
295          * such that another IPI will not be sent.
296          */
297         crashing_cpu = smp_processor_id();
298         crash_save_this_cpu(regs, crashing_cpu);
299         crash_kexec_prepare_cpus(crashing_cpu);
300         cpu_set(crashing_cpu, cpus_in_crash);
301         if (ppc_md.kexec_cpu_down)
302                 ppc_md.kexec_cpu_down(1, 0);
303 }