diff options
Diffstat (limited to 'arch/x86/kernel/crash.c')
| -rw-r--r-- | arch/x86/kernel/crash.c | 67 |
1 files changed, 8 insertions, 59 deletions
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 81e01f7b1d12..d84a852e4cd7 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c | |||
| @@ -29,34 +29,17 @@ | |||
| 29 | 29 | ||
| 30 | #include <mach_ipi.h> | 30 | #include <mach_ipi.h> |
| 31 | 31 | ||
| 32 | /* This keeps a track of which one is crashing cpu. */ | ||
| 33 | static int crashing_cpu; | ||
| 34 | 32 | ||
| 35 | #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) | 33 | #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) |
| 36 | static atomic_t waiting_for_crash_ipi; | ||
| 37 | 34 | ||
| 38 | static int crash_nmi_callback(struct notifier_block *self, | 35 | static void kdump_nmi_callback(int cpu, struct die_args *args) |
| 39 | unsigned long val, void *data) | ||
| 40 | { | 36 | { |
| 41 | struct pt_regs *regs; | 37 | struct pt_regs *regs; |
| 42 | #ifdef CONFIG_X86_32 | 38 | #ifdef CONFIG_X86_32 |
| 43 | struct pt_regs fixed_regs; | 39 | struct pt_regs fixed_regs; |
| 44 | #endif | 40 | #endif |
| 45 | int cpu; | ||
| 46 | 41 | ||
| 47 | if (val != DIE_NMI_IPI) | 42 | regs = args->regs; |
| 48 | return NOTIFY_OK; | ||
| 49 | |||
| 50 | regs = ((struct die_args *)data)->regs; | ||
| 51 | cpu = raw_smp_processor_id(); | ||
| 52 | |||
| 53 | /* Don't do anything if this handler is invoked on crashing cpu. | ||
| 54 | * Otherwise, system will completely hang. Crashing cpu can get | ||
| 55 | * an NMI if system was initially booted with nmi_watchdog parameter. | ||
| 56 | */ | ||
| 57 | if (cpu == crashing_cpu) | ||
| 58 | return NOTIFY_STOP; | ||
| 59 | local_irq_disable(); | ||
| 60 | 43 | ||
| 61 | #ifdef CONFIG_X86_32 | 44 | #ifdef CONFIG_X86_32 |
| 62 | if (!user_mode_vm(regs)) { | 45 | if (!user_mode_vm(regs)) { |
| @@ -65,51 +48,19 @@ static int crash_nmi_callback(struct notifier_block *self, | |||
| 65 | } | 48 | } |
| 66 | #endif | 49 | #endif |
| 67 | crash_save_cpu(regs, cpu); | 50 | crash_save_cpu(regs, cpu); |
| 68 | disable_local_APIC(); | ||
| 69 | atomic_dec(&waiting_for_crash_ipi); | ||
| 70 | /* Assume hlt works */ | ||
| 71 | halt(); | ||
| 72 | for (;;) | ||
| 73 | cpu_relax(); | ||
| 74 | |||
| 75 | return 1; | ||
| 76 | } | ||
| 77 | 51 | ||
| 78 | static void smp_send_nmi_allbutself(void) | 52 | disable_local_APIC(); |
| 79 | { | ||
| 80 | send_IPI_allbutself(NMI_VECTOR); | ||
| 81 | } | 53 | } |
| 82 | 54 | ||
| 83 | static struct notifier_block crash_nmi_nb = { | 55 | static void kdump_nmi_shootdown_cpus(void) |
| 84 | .notifier_call = crash_nmi_callback, | ||
| 85 | }; | ||
| 86 | |||
| 87 | static void nmi_shootdown_cpus(void) | ||
| 88 | { | 56 | { |
| 89 | unsigned long msecs; | 57 | nmi_shootdown_cpus(kdump_nmi_callback); |
| 90 | |||
| 91 | atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); | ||
| 92 | /* Would it be better to replace the trap vector here? */ | ||
| 93 | if (register_die_notifier(&crash_nmi_nb)) | ||
| 94 | return; /* return what? */ | ||
| 95 | /* Ensure the new callback function is set before sending | ||
| 96 | * out the NMI | ||
| 97 | */ | ||
| 98 | wmb(); | ||
| 99 | 58 | ||
| 100 | smp_send_nmi_allbutself(); | ||
| 101 | |||
| 102 | msecs = 1000; /* Wait at most a second for the other cpus to stop */ | ||
| 103 | while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { | ||
| 104 | mdelay(1); | ||
| 105 | msecs--; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* Leave the nmi callback set */ | ||
| 109 | disable_local_APIC(); | 59 | disable_local_APIC(); |
| 110 | } | 60 | } |
| 61 | |||
| 111 | #else | 62 | #else |
| 112 | static void nmi_shootdown_cpus(void) | 63 | static void kdump_nmi_shootdown_cpus(void) |
| 113 | { | 64 | { |
| 114 | /* There are no cpus to shootdown */ | 65 | /* There are no cpus to shootdown */ |
| 115 | } | 66 | } |
| @@ -128,9 +79,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs) | |||
| 128 | /* The kernel is broken so disable interrupts */ | 79 | /* The kernel is broken so disable interrupts */ |
| 129 | local_irq_disable(); | 80 | local_irq_disable(); |
| 130 | 81 | ||
| 131 | /* Make a note of crashing cpu. Will be used in NMI callback.*/ | 82 | kdump_nmi_shootdown_cpus(); |
| 132 | crashing_cpu = safe_smp_processor_id(); | ||
| 133 | nmi_shootdown_cpus(); | ||
| 134 | lapic_shutdown(); | 83 | lapic_shutdown(); |
| 135 | #if defined(CONFIG_X86_IO_APIC) | 84 | #if defined(CONFIG_X86_IO_APIC) |
| 136 | disable_IO_APIC(); | 85 | disable_IO_APIC(); |
