From a7d41820f683c35b53af719210a51f6aa0f86a6a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 12 Nov 2008 11:34:37 -0200 Subject: x86 kdump: extract kdump-specific code from crash_nmi_callback() Impact: cleanup The NMI CPU-halting code will be used on non-kdump cases, also (e.g. emergency_reboot when virtualization is enabled). Signed-off-by: Eduardo Habkost Signed-off-by: Ingo Molnar --- arch/x86/kernel/crash.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'arch/x86/kernel/crash.c') diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 26855381790..60475422a51 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -35,19 +35,34 @@ static int crashing_cpu; #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) static atomic_t waiting_for_crash_ipi; -static int crash_nmi_callback(struct notifier_block *self, - unsigned long val, void *data) +static void kdump_nmi_callback(int cpu, struct die_args *args) { struct pt_regs *regs; #ifdef CONFIG_X86_32 struct pt_regs fixed_regs; #endif + + regs = args->regs; + +#ifdef CONFIG_X86_32 + if (!user_mode_vm(regs)) { + crash_fixup_ss_esp(&fixed_regs, regs); + regs = &fixed_regs; + } +#endif + crash_save_cpu(regs, cpu); + + disable_local_APIC(); +} + +static int crash_nmi_callback(struct notifier_block *self, + unsigned long val, void *data) +{ int cpu; if (val != DIE_NMI_IPI) return NOTIFY_OK; - regs = ((struct die_args *)data)->regs; cpu = raw_smp_processor_id(); /* Don't do anything if this handler is invoked on crashing cpu. @@ -58,14 +73,8 @@ static int crash_nmi_callback(struct notifier_block *self, return NOTIFY_STOP; local_irq_disable(); -#ifdef CONFIG_X86_32 - if (!user_mode_vm(regs)) { - crash_fixup_ss_esp(&fixed_regs, regs); - regs = &fixed_regs; - } -#endif - crash_save_cpu(regs, cpu); - disable_local_APIC(); + kdump_nmi_callback(cpu, (struct die_args *)data); + atomic_dec(&waiting_for_crash_ipi); /* Assume hlt works */ halt(); -- cgit v1.2.3-70-g09d2 From b2bbe71b829564fb65a6bc7e1e25e02d70cffce8 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 12 Nov 2008 11:34:38 -0200 Subject: x86 kdump: move crashing_cpu assignment to nmi_shootdown_cpus() Impact: cleanup This variable will be moved to non-kdump-specific code. Signed-off-by: Eduardo Habkost Signed-off-by: Ingo Molnar --- arch/x86/kernel/crash.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'arch/x86/kernel/crash.c') diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 60475422a51..ed2f0f9dc89 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -29,10 +29,11 @@ #include +#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) + /* This keeps a track of which one is crashing cpu. */ static int crashing_cpu; -#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) static atomic_t waiting_for_crash_ipi; static void kdump_nmi_callback(int cpu, struct die_args *args) @@ -100,6 +101,9 @@ static void nmi_shootdown_cpus(void) { unsigned long msecs; + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = safe_smp_processor_id(); + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); /* Would it be better to replace the trap vector here? */ if (register_die_notifier(&crash_nmi_nb)) @@ -140,8 +144,6 @@ void native_machine_crash_shutdown(struct pt_regs *regs) /* The kernel is broken so disable interrupts */ local_irq_disable(); - /* Make a note of crashing cpu. Will be used in NMI callback.*/ - crashing_cpu = safe_smp_processor_id(); nmi_shootdown_cpus(); lapic_shutdown(); #if defined(CONFIG_X86_IO_APIC) -- cgit v1.2.3-70-g09d2 From d1e7b91cfaa8fc5ed736dcfb8beb5134a2385228 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 12 Nov 2008 11:34:39 -0200 Subject: x86 kdump: create kdump_nmi_shootdown_cpus() Impact: cleanup For the kdump-specific code that was living on nmi_shootdown_cpus(). Signed-off-by: Eduardo Habkost Signed-off-by: Ingo Molnar --- arch/x86/kernel/crash.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/x86/kernel/crash.c') diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index ed2f0f9dc89..75c468cc7e5 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -122,10 +122,17 @@ static void nmi_shootdown_cpus(void) } /* Leave the nmi callback set */ +} + +static void kdump_nmi_shootdown_cpus(void) +{ + nmi_shootdown_cpus(); + disable_local_APIC(); } + #else -static void nmi_shootdown_cpus(void) +static void kdump_nmi_shootdown_cpus(void) { /* There are no cpus to shootdown */ } @@ -144,7 +151,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs) /* The kernel is broken so disable interrupts */ local_irq_disable(); - nmi_shootdown_cpus(); + kdump_nmi_shootdown_cpus(); lapic_shutdown(); #if defined(CONFIG_X86_IO_APIC) disable_IO_APIC(); -- cgit v1.2.3-70-g09d2 From 8e294786316aca41c66b8b73ba1ee74a4ae7d452 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 12 Nov 2008 11:34:40 -0200 Subject: x86 kdump: make kdump_nmi_callback() a function ptr on crash_nmi_callback() Impact: extend nmi_shootdown_cpus() with a callback The reboot code will use a different function on crash_nmi_callback(). Adding a function pointer parameter to nmi_shootdown_cpus() for that. Signed-off-by: Eduardo Habkost Signed-off-by: Ingo Molnar --- arch/x86/kernel/crash.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'arch/x86/kernel/crash.c') diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 75c468cc7e5..f23c2beeb37 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -29,10 +29,13 @@ #include +typedef void (*nmi_shootdown_cb)(int, struct die_args*); + #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) /* This keeps a track of which one is crashing cpu. */ static int crashing_cpu; +static nmi_shootdown_cb shootdown_callback; static atomic_t waiting_for_crash_ipi; @@ -74,7 +77,7 @@ static int crash_nmi_callback(struct notifier_block *self, return NOTIFY_STOP; local_irq_disable(); - kdump_nmi_callback(cpu, (struct die_args *)data); + shootdown_callback(cpu, (struct die_args *)data); atomic_dec(&waiting_for_crash_ipi); /* Assume hlt works */ @@ -97,13 +100,15 @@ static struct notifier_block crash_nmi_nb = { .notifier_call = crash_nmi_callback, }; -static void nmi_shootdown_cpus(void) +static void nmi_shootdown_cpus(nmi_shootdown_cb callback) { unsigned long msecs; /* Make a note of crashing cpu. Will be used in NMI callback.*/ crashing_cpu = safe_smp_processor_id(); + shootdown_callback = callback; + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); /* Would it be better to replace the trap vector here? */ if (register_die_notifier(&crash_nmi_nb)) @@ -126,7 +131,7 @@ static void nmi_shootdown_cpus(void) static void kdump_nmi_shootdown_cpus(void) { - nmi_shootdown_cpus(); + nmi_shootdown_cpus(kdump_nmi_callback); disable_local_APIC(); } -- cgit v1.2.3-70-g09d2 From c370e5e089adfd5b1b863f3464cccae9ebf33cca Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 12 Nov 2008 11:34:41 -0200 Subject: x86 kdump: make nmi_shootdown_cpus() non-static Impact: make API available to the rest of x86 platform code Add prototype to asm/reboot.h. Signed-off-by: Eduardo Habkost Signed-off-by: Ingo Molnar --- arch/x86/include/asm/reboot.h | 5 +++++ arch/x86/kernel/crash.c | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/x86/kernel/crash.c') diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index df7710354f8..562d4fd31ba 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -1,6 +1,8 @@ #ifndef _ASM_X86_REBOOT_H #define _ASM_X86_REBOOT_H +#include + struct pt_regs; struct machine_ops { @@ -18,4 +20,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs); void native_machine_shutdown(void); void machine_real_restart(const unsigned char *code, int length); +typedef void (*nmi_shootdown_cb)(int, struct die_args*); +void nmi_shootdown_cpus(nmi_shootdown_cb callback); + #endif /* _ASM_X86_REBOOT_H */ diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index f23c2beeb37..fb298d1daac 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -29,7 +29,6 @@ #include -typedef void (*nmi_shootdown_cb)(int, struct die_args*); #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) @@ -100,7 +99,7 @@ static struct notifier_block crash_nmi_nb = { .notifier_call = crash_nmi_callback, }; -static void nmi_shootdown_cpus(nmi_shootdown_cb callback) +void nmi_shootdown_cpus(nmi_shootdown_cb callback) { unsigned long msecs; -- cgit v1.2.3-70-g09d2 From 2ddded213895e41b9cfe1c084127e6c01632ac1a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 12 Nov 2008 11:34:42 -0200 Subject: x86: move nmi_shootdown_cpus() to reboot.c Impact: make nmi_shootdown_cpus() available to the rest of the x86 platform Now nmi_shootdown_cpus() is ready to be used by non-kdump code also. Move it to reboot.c. Signed-off-by: Eduardo Habkost Signed-off-by: Ingo Molnar --- arch/x86/kernel/crash.c | 76 -------------------------------------------- arch/x86/kernel/reboot.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 76 deletions(-) (limited to 'arch/x86/kernel/crash.c') diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index fb298d1daac..d84a852e4cd 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -32,12 +32,6 @@ #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) -/* This keeps a track of which one is crashing cpu. */ -static int crashing_cpu; -static nmi_shootdown_cb shootdown_callback; - -static atomic_t waiting_for_crash_ipi; - static void kdump_nmi_callback(int cpu, struct die_args *args) { struct pt_regs *regs; @@ -58,76 +52,6 @@ static void kdump_nmi_callback(int cpu, struct die_args *args) disable_local_APIC(); } -static int crash_nmi_callback(struct notifier_block *self, - unsigned long val, void *data) -{ - int cpu; - - if (val != DIE_NMI_IPI) - return NOTIFY_OK; - - cpu = raw_smp_processor_id(); - - /* Don't do anything if this handler is invoked on crashing cpu. - * Otherwise, system will completely hang. Crashing cpu can get - * an NMI if system was initially booted with nmi_watchdog parameter. - */ - if (cpu == crashing_cpu) - return NOTIFY_STOP; - local_irq_disable(); - - shootdown_callback(cpu, (struct die_args *)data); - - atomic_dec(&waiting_for_crash_ipi); - /* Assume hlt works */ - halt(); - for (;;) - cpu_relax(); - - return 1; -} - -static void smp_send_nmi_allbutself(void) -{ - cpumask_t mask = cpu_online_map; - cpu_clear(safe_smp_processor_id(), mask); - if (!cpus_empty(mask)) - send_IPI_mask(mask, NMI_VECTOR); -} - -static struct notifier_block crash_nmi_nb = { - .notifier_call = crash_nmi_callback, -}; - -void nmi_shootdown_cpus(nmi_shootdown_cb callback) -{ - unsigned long msecs; - - /* Make a note of crashing cpu. Will be used in NMI callback.*/ - crashing_cpu = safe_smp_processor_id(); - - shootdown_callback = callback; - - atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); - /* Would it be better to replace the trap vector here? */ - if (register_die_notifier(&crash_nmi_nb)) - return; /* return what? */ - /* Ensure the new callback function is set before sending - * out the NMI - */ - wmb(); - - smp_send_nmi_allbutself(); - - msecs = 1000; /* Wait at most a second for the other cpus to stop */ - while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { - mdelay(1); - msecs--; - } - - /* Leave the nmi callback set */ -} - static void kdump_nmi_shootdown_cpus(void) { nmi_shootdown_cpus(kdump_nmi_callback); diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 724adfc63cb..364edeecc23 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -21,6 +21,9 @@ # include #endif +#include + + /* * Power off function, if any */ @@ -514,3 +517,83 @@ void machine_crash_shutdown(struct pt_regs *regs) machine_ops.crash_shutdown(regs); } #endif + + +#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) + +/* This keeps a track of which one is crashing cpu. */ +static int crashing_cpu; +static nmi_shootdown_cb shootdown_callback; + +static atomic_t waiting_for_crash_ipi; + +static int crash_nmi_callback(struct notifier_block *self, + unsigned long val, void *data) +{ + int cpu; + + if (val != DIE_NMI_IPI) + return NOTIFY_OK; + + cpu = raw_smp_processor_id(); + + /* Don't do anything if this handler is invoked on crashing cpu. + * Otherwise, system will completely hang. Crashing cpu can get + * an NMI if system was initially booted with nmi_watchdog parameter. + */ + if (cpu == crashing_cpu) + return NOTIFY_STOP; + local_irq_disable(); + + shootdown_callback(cpu, (struct die_args *)data); + + atomic_dec(&waiting_for_crash_ipi); + /* Assume hlt works */ + halt(); + for (;;) + cpu_relax(); + + return 1; +} + +static void smp_send_nmi_allbutself(void) +{ + cpumask_t mask = cpu_online_map; + cpu_clear(safe_smp_processor_id(), mask); + if (!cpus_empty(mask)) + send_IPI_mask(mask, NMI_VECTOR); +} + +static struct notifier_block crash_nmi_nb = { + .notifier_call = crash_nmi_callback, +}; + +void nmi_shootdown_cpus(nmi_shootdown_cb callback) +{ + unsigned long msecs; + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = safe_smp_processor_id(); + + shootdown_callback = callback; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + /* Would it be better to replace the trap vector here? */ + if (register_die_notifier(&crash_nmi_nb)) + return; /* return what? */ + /* Ensure the new callback function is set before sending + * out the NMI + */ + wmb(); + + smp_send_nmi_allbutself(); + + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + + /* Leave the nmi callback set */ +} +#endif -- cgit v1.2.3-70-g09d2