aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRuss Anderson <rja@sgi.com>2010-02-26 11:49:12 -0500
committerIngo Molnar <mingo@elte.hu>2010-02-27 06:34:21 -0500
commit78c06176466cbd1b3f0f67709d3023c40dbebcbd (patch)
tree8cb56dc82cd9aa07adcdceeab09a493f717b50d4 /arch
parent36028f3383872eefb558a4aae4c12ec2b5fa640f (diff)
x86: Enable NMI on all cpus on UV
Enable NMI on all cpus in UV system and add an NMI handler to dump_stack on each cpu. By default on x86 all the cpus except the boot cpu have NMI masked off. This patch enables NMI on all cpus in UV system and adds an NMI handler to dump_stack on each cpu. This way if a system hangs we can NMI the machine and get a backtrace from all the cpus. Version 2: Use x86_platform driver mechanism for nmi init, per Ingo's suggestion. Version 3: Clean up Ingo's nits. Signed-off-by: Russ Anderson <rja@sgi.com> LKML-Reference: <20100226164912.GA24439@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/uv/uv.h1
-rw-r--r--arch/x86/include/asm/x86_init.h2
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c44
-rw-r--r--arch/x86/kernel/smpboot.c1
-rw-r--r--arch/x86/kernel/x86_init.c3
5 files changed, 51 insertions, 0 deletions
diff --git a/arch/x86/include/asm/uv/uv.h b/arch/x86/include/asm/uv/uv.h
index c0a01b5d985b..3bb9491b7659 100644
--- a/arch/x86/include/asm/uv/uv.h
+++ b/arch/x86/include/asm/uv/uv.h
@@ -11,6 +11,7 @@ struct mm_struct;
11extern enum uv_system_type get_uv_system_type(void); 11extern enum uv_system_type get_uv_system_type(void);
12extern int is_uv_system(void); 12extern int is_uv_system(void);
13extern void uv_cpu_init(void); 13extern void uv_cpu_init(void);
14extern void uv_nmi_init(void);
14extern void uv_system_init(void); 15extern void uv_system_init(void);
15extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, 16extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
16 struct mm_struct *mm, 17 struct mm_struct *mm,
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index ea0e8ea15e15..60cc35269083 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -126,6 +126,7 @@ struct x86_cpuinit_ops {
126 * @get_wallclock: get time from HW clock like RTC etc. 126 * @get_wallclock: get time from HW clock like RTC etc.
127 * @set_wallclock: set time back to HW clock 127 * @set_wallclock: set time back to HW clock
128 * @is_untracked_pat_range exclude from PAT logic 128 * @is_untracked_pat_range exclude from PAT logic
129 * @nmi_init enable NMI on cpus
129 */ 130 */
130struct x86_platform_ops { 131struct x86_platform_ops {
131 unsigned long (*calibrate_tsc)(void); 132 unsigned long (*calibrate_tsc)(void);
@@ -133,6 +134,7 @@ struct x86_platform_ops {
133 int (*set_wallclock)(unsigned long nowtime); 134 int (*set_wallclock)(unsigned long nowtime);
134 void (*iommu_shutdown)(void); 135 void (*iommu_shutdown)(void);
135 bool (*is_untracked_pat_range)(u64 start, u64 end); 136 bool (*is_untracked_pat_range)(u64 start, u64 end);
137 void (*nmi_init)(void);
136}; 138};
137 139
138extern struct x86_init_ops x86_init; 140extern struct x86_init_ops x86_init;
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 6ef2899eb861..4b8dbb256147 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -21,6 +21,7 @@
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/pci.h> 23#include <linux/pci.h>
24#include <linux/kdebug.h>
24 25
25#include <asm/uv/uv_mmrs.h> 26#include <asm/uv/uv_mmrs.h>
26#include <asm/uv/uv_hub.h> 27#include <asm/uv/uv_hub.h>
@@ -41,6 +42,7 @@ static enum uv_system_type uv_system_type;
41static u64 gru_start_paddr, gru_end_paddr; 42static u64 gru_start_paddr, gru_end_paddr;
42int uv_min_hub_revision_id; 43int uv_min_hub_revision_id;
43EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); 44EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
45static DEFINE_SPINLOCK(uv_nmi_lock);
44 46
45static inline bool is_GRU_range(u64 start, u64 end) 47static inline bool is_GRU_range(u64 start, u64 end)
46{ 48{
@@ -74,6 +76,7 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
74 if (!strcmp(oem_id, "SGI")) { 76 if (!strcmp(oem_id, "SGI")) {
75 nodeid = early_get_nodeid(); 77 nodeid = early_get_nodeid();
76 x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range; 78 x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range;
79 x86_platform.nmi_init = uv_nmi_init;
77 if (!strcmp(oem_table_id, "UVL")) 80 if (!strcmp(oem_table_id, "UVL"))
78 uv_system_type = UV_LEGACY_APIC; 81 uv_system_type = UV_LEGACY_APIC;
79 else if (!strcmp(oem_table_id, "UVX")) 82 else if (!strcmp(oem_table_id, "UVX"))
@@ -596,6 +599,46 @@ void __cpuinit uv_cpu_init(void)
596 set_x2apic_extra_bits(uv_hub_info->pnode); 599 set_x2apic_extra_bits(uv_hub_info->pnode);
597} 600}
598 601
602/*
603 * When NMI is received, print a stack trace.
604 */
605int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data)
606{
607 if (reason != DIE_NMI_IPI)
608 return NOTIFY_OK;
609 /*
610 * Use a lock so only one cpu prints at a time
611 * to prevent intermixed output.
612 */
613 spin_lock(&uv_nmi_lock);
614 pr_info("NMI stack dump cpu %u:\n", smp_processor_id());
615 dump_stack();
616 spin_unlock(&uv_nmi_lock);
617
618 return NOTIFY_STOP;
619}
620
621static struct notifier_block uv_dump_stack_nmi_nb = {
622 .notifier_call = uv_handle_nmi
623};
624
625void uv_register_nmi_notifier(void)
626{
627 if (register_die_notifier(&uv_dump_stack_nmi_nb))
628 printk(KERN_WARNING "UV NMI handler failed to register\n");
629}
630
631void uv_nmi_init(void)
632{
633 unsigned int value;
634
635 /*
636 * Unmask NMI on all cpus
637 */
638 value = apic_read(APIC_LVT1) | APIC_DM_NMI;
639 value &= ~APIC_LVT_MASKED;
640 apic_write(APIC_LVT1, value);
641}
599 642
600void __init uv_system_init(void) 643void __init uv_system_init(void)
601{ 644{
@@ -717,6 +760,7 @@ void __init uv_system_init(void)
717 760
718 uv_cpu_init(); 761 uv_cpu_init();
719 uv_scir_register_cpu_notifier(); 762 uv_scir_register_cpu_notifier();
763 uv_register_nmi_notifier();
720 proc_mkdir("sgi_uv", NULL); 764 proc_mkdir("sgi_uv", NULL);
721 765
722 /* register Legacy VGA I/O redirection handler */ 766 /* register Legacy VGA I/O redirection handler */
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 678d0b8c26f3..838a118876c0 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -320,6 +320,7 @@ notrace static void __cpuinit start_secondary(void *unused)
320 unlock_vector_lock(); 320 unlock_vector_lock();
321 ipi_call_unlock(); 321 ipi_call_unlock();
322 per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; 322 per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
323 x86_platform.nmi_init();
323 324
324 /* enable local interrupts */ 325 /* enable local interrupts */
325 local_irq_enable(); 326 local_irq_enable();
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index ccd179dec36e..ee5746c94628 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -76,10 +76,13 @@ struct x86_cpuinit_ops x86_cpuinit __cpuinitdata = {
76 .setup_percpu_clockev = setup_secondary_APIC_clock, 76 .setup_percpu_clockev = setup_secondary_APIC_clock,
77}; 77};
78 78
79static void default_nmi_init(void) { };
80
79struct x86_platform_ops x86_platform = { 81struct x86_platform_ops x86_platform = {
80 .calibrate_tsc = native_calibrate_tsc, 82 .calibrate_tsc = native_calibrate_tsc,
81 .get_wallclock = mach_get_cmos_time, 83 .get_wallclock = mach_get_cmos_time,
82 .set_wallclock = mach_set_rtc_mmss, 84 .set_wallclock = mach_set_rtc_mmss,
83 .iommu_shutdown = iommu_shutdown_noop, 85 .iommu_shutdown = iommu_shutdown_noop,
84 .is_untracked_pat_range = is_ISA_range, 86 .is_untracked_pat_range = is_ISA_range,
87 .nmi_init = default_nmi_init
85}; 88};