diff options
Diffstat (limited to 'arch/i386/kernel/crash.c')
-rw-r--r-- | arch/i386/kernel/crash.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c index 5b96f038367f..67d297dc1003 100644 --- a/arch/i386/kernel/crash.c +++ b/arch/i386/kernel/crash.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <asm/nmi.h> | 22 | #include <asm/nmi.h> |
23 | #include <asm/hw_irq.h> | 23 | #include <asm/hw_irq.h> |
24 | #include <asm/apic.h> | 24 | #include <asm/apic.h> |
25 | #include <asm/kdebug.h> | ||
26 | |||
25 | #include <mach_ipi.h> | 27 | #include <mach_ipi.h> |
26 | 28 | ||
27 | 29 | ||
@@ -93,16 +95,25 @@ static void crash_save_self(struct pt_regs *regs) | |||
93 | #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) | 95 | #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) |
94 | static atomic_t waiting_for_crash_ipi; | 96 | static atomic_t waiting_for_crash_ipi; |
95 | 97 | ||
96 | static int crash_nmi_callback(struct pt_regs *regs, int cpu) | 98 | static int crash_nmi_callback(struct notifier_block *self, |
99 | unsigned long val, void *data) | ||
97 | { | 100 | { |
101 | struct pt_regs *regs; | ||
98 | struct pt_regs fixed_regs; | 102 | struct pt_regs fixed_regs; |
103 | int cpu; | ||
104 | |||
105 | if (val != DIE_NMI_IPI) | ||
106 | return NOTIFY_OK; | ||
107 | |||
108 | regs = ((struct die_args *)data)->regs; | ||
109 | cpu = raw_smp_processor_id(); | ||
99 | 110 | ||
100 | /* Don't do anything if this handler is invoked on crashing cpu. | 111 | /* Don't do anything if this handler is invoked on crashing cpu. |
101 | * Otherwise, system will completely hang. Crashing cpu can get | 112 | * Otherwise, system will completely hang. Crashing cpu can get |
102 | * an NMI if system was initially booted with nmi_watchdog parameter. | 113 | * an NMI if system was initially booted with nmi_watchdog parameter. |
103 | */ | 114 | */ |
104 | if (cpu == crashing_cpu) | 115 | if (cpu == crashing_cpu) |
105 | return 1; | 116 | return NOTIFY_STOP; |
106 | local_irq_disable(); | 117 | local_irq_disable(); |
107 | 118 | ||
108 | if (!user_mode_vm(regs)) { | 119 | if (!user_mode_vm(regs)) { |
@@ -125,13 +136,18 @@ static void smp_send_nmi_allbutself(void) | |||
125 | send_IPI_allbutself(NMI_VECTOR); | 136 | send_IPI_allbutself(NMI_VECTOR); |
126 | } | 137 | } |
127 | 138 | ||
139 | static struct notifier_block crash_nmi_nb = { | ||
140 | .notifier_call = crash_nmi_callback, | ||
141 | }; | ||
142 | |||
128 | static void nmi_shootdown_cpus(void) | 143 | static void nmi_shootdown_cpus(void) |
129 | { | 144 | { |
130 | unsigned long msecs; | 145 | unsigned long msecs; |
131 | 146 | ||
132 | atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); | 147 | atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); |
133 | /* Would it be better to replace the trap vector here? */ | 148 | /* Would it be better to replace the trap vector here? */ |
134 | set_nmi_callback(crash_nmi_callback); | 149 | if (register_die_notifier(&crash_nmi_nb)) |
150 | return; /* return what? */ | ||
135 | /* Ensure the new callback function is set before sending | 151 | /* Ensure the new callback function is set before sending |
136 | * out the NMI | 152 | * out the NMI |
137 | */ | 153 | */ |