]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/i386/kernel/crash.c
[PATCH] crashdump: x86: add NMI handler to capture other CPUs
[linux-2.6-omap-h63xx.git] / arch / i386 / kernel / crash.c
1 /*
2  * Architecture specific (i386) functions for kexec based crash dumps.
3  *
4  * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
5  *
6  * Copyright (C) IBM Corporation, 2004. All rights reserved.
7  *
8  */
9
10 #include <linux/init.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/smp.h>
14 #include <linux/irq.h>
15 #include <linux/reboot.h>
16 #include <linux/kexec.h>
17 #include <linux/irq.h>
18 #include <linux/delay.h>
19 #include <linux/elf.h>
20 #include <linux/elfcore.h>
21
22 #include <asm/processor.h>
23 #include <asm/hardirq.h>
24 #include <asm/nmi.h>
25 #include <asm/hw_irq.h>
26 #include <mach_ipi.h>
27
28 #define MAX_NOTE_BYTES 1024
29 typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
30
31 note_buf_t crash_notes[NR_CPUS];
32
33 #ifdef CONFIG_SMP
34 static atomic_t waiting_for_crash_ipi;
35
36 static int crash_nmi_callback(struct pt_regs *regs, int cpu)
37 {
38         local_irq_disable();
39         atomic_dec(&waiting_for_crash_ipi);
40         /* Assume hlt works */
41         __asm__("hlt");
42         for(;;);
43         return 1;
44 }
45
46 /*
47  * By using the NMI code instead of a vector we just sneak thru the
48  * word generator coming out with just what we want.  AND it does
49  * not matter if clustered_apic_mode is set or not.
50  */
51 static void smp_send_nmi_allbutself(void)
52 {
53         send_IPI_allbutself(APIC_DM_NMI);
54 }
55
56 static void nmi_shootdown_cpus(void)
57 {
58         unsigned long msecs;
59         atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
60
61         /* Would it be better to replace the trap vector here? */
62         set_nmi_callback(crash_nmi_callback);
63         /* Ensure the new callback function is set before sending
64          * out the NMI
65          */
66         wmb();
67
68         smp_send_nmi_allbutself();
69
70         msecs = 1000; /* Wait at most a second for the other cpus to stop */
71         while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
72                 mdelay(1);
73                 msecs--;
74         }
75
76         /* Leave the nmi callback set */
77 }
78 #else
79 static void nmi_shootdown_cpus(void)
80 {
81         /* There are no cpus to shootdown */
82 }
83 #endif
84
85 void machine_crash_shutdown(void)
86 {
87         /* This function is only called after the system
88          * has paniced or is otherwise in a critical state.
89          * The minimum amount of code to allow a kexec'd kernel
90          * to run successfully needs to happen here.
91          *
92          * In practice this means shooting down the other cpus in
93          * an SMP system.
94          */
95         /* The kernel is broken so disable interrupts */
96         local_irq_disable();
97         nmi_shootdown_cpus();
98 }