All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86: Enable NMI on all cpus on UV
@ 2010-02-17 16:50 Russ Anderson
  2010-02-22 10:38 ` Ingo Molnar
  0 siblings, 1 reply; 8+ messages in thread
From: Russ Anderson @ 2010-02-17 16:50 UTC (permalink / raw)
  To: H. Peter Anvin, Ingo Molnar, tglx, linux-kernel; +Cc: Russ Anderson

Enable NMI on all cpus in UV system and add an NMI handler
to dump_stack on each cpu.

Signed-off-by: Russ Anderson <rja@sgi.com>

---

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.


 arch/x86/include/asm/uv/uv.h       |    1 
 arch/x86/kernel/apic/x2apic_uv_x.c |   49 +++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/smpboot.c          |    2 +
 3 files changed, 52 insertions(+)

Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
===================================================================
--- linux.orig/arch/x86/kernel/apic/x2apic_uv_x.c	2010-02-17 10:21:55.000000000 -0600
+++ linux/arch/x86/kernel/apic/x2apic_uv_x.c	2010-02-17 10:32:20.000000000 -0600
@@ -20,6 +20,7 @@
 #include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/kdebug.h>
 
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
@@ -39,6 +40,53 @@ static u64 gru_start_paddr, gru_end_padd
 int uv_min_hub_revision_id;
 EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
 
+int uv_handle_nmi(struct notifier_block *self,
+		  unsigned long reason, void *data)
+{
+	unsigned long flags;
+	static DEFINE_SPINLOCK(uv_nmi_lock);
+
+	if (reason != DIE_NMI_IPI)
+		return NOTIFY_OK;
+	/*
+	 * Use a lock so only one cpu prints at a time
+	 * to prevent intermixed output.
+	 */
+	spin_lock_irqsave(&uv_nmi_lock, flags);
+	printk(KERN_INFO "NMI stack dump cpu %u:\n",
+				smp_processor_id());
+	dump_stack();
+	spin_unlock_irqrestore(&uv_nmi_lock, flags);
+
+	return NOTIFY_STOP;
+}
+
+static struct notifier_block uv_dump_stack_nmi_nb = {
+  .notifier_call = uv_handle_nmi,
+  .next = NULL,
+  .priority = 0
+};
+
+void uv_register_nmi_notifier(void)
+{
+	if (register_die_notifier(&uv_dump_stack_nmi_nb))
+		printk(KERN_WARNING "UV NMI handler failed to register\n");
+}
+
+/*
+ * Called on each cpu to unmask NMI.
+ */
+void __cpuinit uv_nmi_init(void)
+{
+	unsigned int value;
+
+	/*
+	 * Unmask NMI on all cpus
+	 */
+	value = apic_read(APIC_LVT1) | APIC_DM_NMI;
+	value &= ~APIC_LVT_MASKED;
+	apic_write(APIC_LVT1, value);
+}
 
 static int is_GRU_range(u64 start, u64 end)
 {
@@ -718,5 +766,6 @@ void __init uv_system_init(void)
 
 	uv_cpu_init();
 	uv_scir_register_cpu_notifier();
+	uv_register_nmi_notifier();
 	proc_mkdir("sgi_uv", NULL);
 }
Index: linux/arch/x86/include/asm/uv/uv.h
===================================================================
--- linux.orig/arch/x86/include/asm/uv/uv.h	2010-02-17 10:21:55.000000000 -0600
+++ linux/arch/x86/include/asm/uv/uv.h	2010-02-17 10:32:20.000000000 -0600
@@ -11,6 +11,7 @@ struct mm_struct;
 extern enum uv_system_type get_uv_system_type(void);
 extern int is_uv_system(void);
 extern void uv_cpu_init(void);
+extern void uv_nmi_init(void);
 extern void uv_system_init(void);
 extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 						 struct mm_struct *mm,
Index: linux/arch/x86/kernel/smpboot.c
===================================================================
--- linux.orig/arch/x86/kernel/smpboot.c	2010-02-17 10:21:55.000000000 -0600
+++ linux/arch/x86/kernel/smpboot.c	2010-02-17 10:32:20.000000000 -0600
@@ -320,6 +320,8 @@ notrace static void __cpuinit start_seco
 	unlock_vector_lock();
 	ipi_call_unlock();
 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+	if (is_uv_system())
+		uv_nmi_init();
 
 	/* enable local interrupts */
 	local_irq_enable();
-- 
Russ Anderson, OS RAS/Partitioning Project Lead  
SGI - Silicon Graphics Inc          rja@sgi.com

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] x86: Enable NMI on all cpus on UV
  2010-02-17 16:50 [PATCH] x86: Enable NMI on all cpus on UV Russ Anderson
@ 2010-02-22 10:38 ` Ingo Molnar
  2010-02-22 22:24   ` Russ Anderson
  2010-02-25 17:24   ` Russ Anderson
  0 siblings, 2 replies; 8+ messages in thread
From: Ingo Molnar @ 2010-02-22 10:38 UTC (permalink / raw)
  To: Russ Anderson; +Cc: H. Peter Anvin, tglx, linux-kernel


* Russ Anderson <rja@sgi.com> wrote:

> Enable NMI on all cpus in UV system and add an NMI handler
> to dump_stack on each cpu.
> 
> Signed-off-by: Russ Anderson <rja@sgi.com>
> 
> ---
> 
> 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.
> 
> 
>  arch/x86/include/asm/uv/uv.h       |    1 
>  arch/x86/kernel/apic/x2apic_uv_x.c |   49 +++++++++++++++++++++++++++++++++++++
>  arch/x86/kernel/smpboot.c          |    2 +
>  3 files changed, 52 insertions(+)
> 
> Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
> ===================================================================
> --- linux.orig/arch/x86/kernel/apic/x2apic_uv_x.c	2010-02-17 10:21:55.000000000 -0600
> +++ linux/arch/x86/kernel/apic/x2apic_uv_x.c	2010-02-17 10:32:20.000000000 -0600
> @@ -20,6 +20,7 @@
>  #include <linux/cpu.h>
>  #include <linux/init.h>
>  #include <linux/io.h>
> +#include <linux/kdebug.h>
>  
>  #include <asm/uv/uv_mmrs.h>
>  #include <asm/uv/uv_hub.h>
> @@ -39,6 +40,53 @@ static u64 gru_start_paddr, gru_end_padd
>  int uv_min_hub_revision_id;
>  EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
>  
> +int uv_handle_nmi(struct notifier_block *self,
> +		  unsigned long reason, void *data)
> +{
> +	unsigned long flags;
> +	static DEFINE_SPINLOCK(uv_nmi_lock);
> +
> +	if (reason != DIE_NMI_IPI)
> +		return NOTIFY_OK;
> +	/*
> +	 * Use a lock so only one cpu prints at a time
> +	 * to prevent intermixed output.
> +	 */
> +	spin_lock_irqsave(&uv_nmi_lock, flags);
> +	printk(KERN_INFO "NMI stack dump cpu %u:\n",
> +				smp_processor_id());
> +	dump_stack();
> +	spin_unlock_irqrestore(&uv_nmi_lock, flags);
> +
> +	return NOTIFY_STOP;
> +}
> +
> +static struct notifier_block uv_dump_stack_nmi_nb = {
> +  .notifier_call = uv_handle_nmi,
> +  .next = NULL,
> +  .priority = 0
> +};
> +
> +void uv_register_nmi_notifier(void)
> +{
> +	if (register_die_notifier(&uv_dump_stack_nmi_nb))
> +		printk(KERN_WARNING "UV NMI handler failed to register\n");
> +}
> +
> +/*
> + * Called on each cpu to unmask NMI.
> + */
> +void __cpuinit uv_nmi_init(void)
> +{
> +	unsigned int value;
> +
> +	/*
> +	 * Unmask NMI on all cpus
> +	 */
> +	value = apic_read(APIC_LVT1) | APIC_DM_NMI;
> +	value &= ~APIC_LVT_MASKED;
> +	apic_write(APIC_LVT1, value);
> +}
>  
>  static int is_GRU_range(u64 start, u64 end)
>  {
> @@ -718,5 +766,6 @@ void __init uv_system_init(void)
>  
>  	uv_cpu_init();
>  	uv_scir_register_cpu_notifier();
> +	uv_register_nmi_notifier();
>  	proc_mkdir("sgi_uv", NULL);
>  }
> Index: linux/arch/x86/include/asm/uv/uv.h
> ===================================================================
> --- linux.orig/arch/x86/include/asm/uv/uv.h	2010-02-17 10:21:55.000000000 -0600
> +++ linux/arch/x86/include/asm/uv/uv.h	2010-02-17 10:32:20.000000000 -0600
> @@ -11,6 +11,7 @@ struct mm_struct;
>  extern enum uv_system_type get_uv_system_type(void);
>  extern int is_uv_system(void);
>  extern void uv_cpu_init(void);
> +extern void uv_nmi_init(void);
>  extern void uv_system_init(void);
>  extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
>  						 struct mm_struct *mm,
> Index: linux/arch/x86/kernel/smpboot.c
> ===================================================================
> --- linux.orig/arch/x86/kernel/smpboot.c	2010-02-17 10:21:55.000000000 -0600
> +++ linux/arch/x86/kernel/smpboot.c	2010-02-17 10:32:20.000000000 -0600
> @@ -320,6 +320,8 @@ notrace static void __cpuinit start_seco
>  	unlock_vector_lock();
>  	ipi_call_unlock();
>  	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
> +	if (is_uv_system())
> +		uv_nmi_init();

Instead of cramming it into the init sequence open-coded, shouldnt this be 
done via the x86_platform driver mechanism?

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] x86: Enable NMI on all cpus on UV
  2010-02-22 10:38 ` Ingo Molnar
@ 2010-02-22 22:24   ` Russ Anderson
  2010-02-25 17:24   ` Russ Anderson
  1 sibling, 0 replies; 8+ messages in thread
From: Russ Anderson @ 2010-02-22 22:24 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: H. Peter Anvin, tglx, linux-kernel, rja

On Mon, Feb 22, 2010 at 11:38:53AM +0100, Ingo Molnar wrote:
> 
> * Russ Anderson <rja@sgi.com> wrote:
> 
> > Index: linux/arch/x86/kernel/smpboot.c
> > ===================================================================
> > --- linux.orig/arch/x86/kernel/smpboot.c	2010-02-17 10:21:55.000000000 -0600
> > +++ linux/arch/x86/kernel/smpboot.c	2010-02-17 10:32:20.000000000 -0600
> > @@ -320,6 +320,8 @@ notrace static void __cpuinit start_seco
> >  	unlock_vector_lock();
> >  	ipi_call_unlock();
> >  	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
> > +	if (is_uv_system())
> > +		uv_nmi_init();
> 
> Instead of cramming it into the init sequence open-coded, shouldnt this be 
> done via the x86_platform driver mechanism?

OK, I'm working on it.

> Thanks,
> 
> 	Ingo

Thanks,
-- 
Russ Anderson, OS RAS/Partitioning Project Lead  
SGI - Silicon Graphics Inc          rja@sgi.com

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] x86: Enable NMI on all cpus on UV
  2010-02-22 10:38 ` Ingo Molnar
  2010-02-22 22:24   ` Russ Anderson
@ 2010-02-25 17:24   ` Russ Anderson
  2010-02-26  9:22     ` Ingo Molnar
  1 sibling, 1 reply; 8+ messages in thread
From: Russ Anderson @ 2010-02-25 17:24 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: H. Peter Anvin, tglx, linux-kernel, rja

[-- Attachment #1: Type: text/plain, Size: 1133 bytes --]

On Mon, Feb 22, 2010 at 11:38:53AM +0100, Ingo Molnar wrote:
> 
> * Russ Anderson <rja@sgi.com> wrote:
> 
> > Enable NMI on all cpus in UV system and add an NMI handler
> > to dump_stack on each cpu.
> > 
> > Signed-off-by: Russ Anderson <rja@sgi.com>
[...]
> >  						 struct mm_struct *mm,
> > Index: linux/arch/x86/kernel/smpboot.c
> > ===================================================================
> > --- linux.orig/arch/x86/kernel/smpboot.c	2010-02-17 10:21:55.000000000 -0600
> > +++ linux/arch/x86/kernel/smpboot.c	2010-02-17 10:32:20.000000000 -0600
> > @@ -320,6 +320,8 @@ notrace static void __cpuinit start_seco
> >  	unlock_vector_lock();
> >  	ipi_call_unlock();
> >  	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
> > +	if (is_uv_system())
> > +		uv_nmi_init();
> 
> Instead of cramming it into the init sequence open-coded, shouldnt this be 
> done via the x86_platform driver mechanism?

Attached is the updated patch with the x86_platform driver mechanism
used for uv_nmi_init.

> Thanks,
> 
> 	Ingo

-- 
Russ Anderson, OS RAS/Partitioning Project Lead  
SGI - Silicon Graphics Inc          rja@sgi.com

[-- Attachment #2: uv_nmi_handler --]
[-- Type: text/plain, Size: 6377 bytes --]

Enable NMI on all cpus in UV system and add an NMI handler
to dump_stack on each cpu.

Signed-off-by: Russ Anderson <rja@sgi.com>

---

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.


 arch/x86/include/asm/nmi.h         |    1 
 arch/x86/include/asm/uv/uv.h       |    1 
 arch/x86/include/asm/x86_init.h    |    2 +
 arch/x86/kernel/apic/x2apic_uv_x.c |   50 +++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/smpboot.c          |    6 ++++
 arch/x86/kernel/x86_init.c         |    2 +
 6 files changed, 62 insertions(+)

Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
===================================================================
--- linux.orig/arch/x86/kernel/apic/x2apic_uv_x.c	2010-02-25 11:01:50.929770347 -0600
+++ linux/arch/x86/kernel/apic/x2apic_uv_x.c	2010-02-25 11:02:17.622069711 -0600
@@ -20,6 +20,7 @@
 #include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/kdebug.h>
 
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
@@ -71,6 +72,7 @@ static int __init uv_acpi_madt_oem_check
 	if (!strcmp(oem_id, "SGI")) {
 		nodeid = early_get_nodeid();
 		x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
+		x86_platform.nmi_init =  uv_nmi_init;
 		if (!strcmp(oem_table_id, "UVL"))
 			uv_system_type = UV_LEGACY_APIC;
 		else if (!strcmp(oem_table_id, "UVX"))
@@ -569,6 +571,53 @@ void __cpuinit uv_cpu_init(void)
 		set_x2apic_extra_bits(uv_hub_info->pnode);
 }
 
+/*
+ * When NMI is received, print a stack trace.
+ */
+int uv_handle_nmi(struct notifier_block *self,
+		  unsigned long reason, void *data)
+{
+	unsigned long flags;
+	static DEFINE_SPINLOCK(uv_nmi_lock);
+
+	if (reason != DIE_NMI_IPI)
+		return NOTIFY_OK;
+	/*
+	 * Use a lock so only one cpu prints at a time
+	 * to prevent intermixed output.
+	 */
+	spin_lock_irqsave(&uv_nmi_lock, flags);
+	printk(KERN_INFO "NMI stack dump cpu %u:\n",
+				smp_processor_id());
+	dump_stack();
+	spin_unlock_irqrestore(&uv_nmi_lock, flags);
+
+	return NOTIFY_STOP;
+}
+
+static struct notifier_block uv_dump_stack_nmi_nb = {
+  .notifier_call = uv_handle_nmi,
+  .next = NULL,
+  .priority = 0
+};
+
+void uv_register_nmi_notifier(void)
+{
+	if (register_die_notifier(&uv_dump_stack_nmi_nb))
+		printk(KERN_WARNING "UV NMI handler failed to register\n");
+}
+
+void uv_nmi_init(void)
+{
+	unsigned int value;
+
+	/*
+	 * Unmask NMI on all cpus
+	 */
+	value = apic_read(APIC_LVT1) | APIC_DM_NMI;
+	value &= ~APIC_LVT_MASKED;
+	apic_write(APIC_LVT1, value);
+}
 
 void __init uv_system_init(void)
 {
@@ -690,5 +739,6 @@ void __init uv_system_init(void)
 
 	uv_cpu_init();
 	uv_scir_register_cpu_notifier();
+	uv_register_nmi_notifier();
 	proc_mkdir("sgi_uv", NULL);
 }
Index: linux/arch/x86/include/asm/uv/uv.h
===================================================================
--- linux.orig/arch/x86/include/asm/uv/uv.h	2010-02-25 11:01:48.131694174 -0600
+++ linux/arch/x86/include/asm/uv/uv.h	2010-02-25 11:02:17.622069711 -0600
@@ -11,6 +11,7 @@ struct mm_struct;
 extern enum uv_system_type get_uv_system_type(void);
 extern int is_uv_system(void);
 extern void uv_cpu_init(void);
+extern void uv_nmi_init(void);
 extern void uv_system_init(void);
 extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 						 struct mm_struct *mm,
Index: linux/arch/x86/kernel/smpboot.c
===================================================================
--- linux.orig/arch/x86/kernel/smpboot.c	2010-02-25 11:01:50.929770347 -0600
+++ linux/arch/x86/kernel/smpboot.c	2010-02-25 11:02:17.664720876 -0600
@@ -263,6 +263,11 @@ static void __cpuinit smp_callin(void)
 	cpumask_set_cpu(cpuid, cpu_callin_mask);
 }
 
+void default_nmi_init(void)
+{
+	return;
+}
+
 /*
  * Activate a secondary processor.
  */
@@ -320,6 +325,7 @@ notrace static void __cpuinit start_seco
 	unlock_vector_lock();
 	ipi_call_unlock();
 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+	x86_platform.nmi_init();
 
 	/* enable local interrupts */
 	local_irq_enable();
Index: linux/arch/x86/include/asm/x86_init.h
===================================================================
--- linux.orig/arch/x86/include/asm/x86_init.h	2010-02-25 11:01:48.131694174 -0600
+++ linux/arch/x86/include/asm/x86_init.h	2010-02-25 11:02:17.696714616 -0600
@@ -126,6 +126,7 @@ struct x86_cpuinit_ops {
  * @get_wallclock:		get time from HW clock like RTC etc.
  * @set_wallclock:		set time back to HW clock
  * @is_untracked_pat_range	exclude from PAT logic
+ * @nmi_init			enable NMI on cpus
  */
 struct x86_platform_ops {
 	unsigned long (*calibrate_tsc)(void);
@@ -133,6 +134,7 @@ struct x86_platform_ops {
 	int (*set_wallclock)(unsigned long nowtime);
 	void (*iommu_shutdown)(void);
 	bool (*is_untracked_pat_range)(u64 start, u64 end);
+	void (*nmi_init)(void);
 };
 
 extern struct x86_init_ops x86_init;
Index: linux/arch/x86/kernel/x86_init.c
===================================================================
--- linux.orig/arch/x86/kernel/x86_init.c	2010-02-25 11:01:47.848760574 -0600
+++ linux/arch/x86/kernel/x86_init.c	2010-02-25 11:02:17.732996103 -0600
@@ -13,6 +13,7 @@
 #include <asm/e820.h>
 #include <asm/time.h>
 #include <asm/irq.h>
+#include <asm/nmi.h>
 #include <asm/pat.h>
 #include <asm/tsc.h>
 #include <asm/iommu.h>
@@ -82,4 +83,5 @@ struct x86_platform_ops x86_platform = {
 	.set_wallclock			= mach_set_rtc_mmss,
 	.iommu_shutdown			= iommu_shutdown_noop,
 	.is_untracked_pat_range		= is_ISA_range,
+	.nmi_init			= default_nmi_init
 };
Index: linux/arch/x86/include/asm/nmi.h
===================================================================
--- linux.orig/arch/x86/include/asm/nmi.h	2010-02-25 11:01:48.131694174 -0600
+++ linux/arch/x86/include/asm/nmi.h	2010-02-25 11:02:17.756721420 -0600
@@ -24,6 +24,7 @@ extern int reserve_perfctr_nmi(unsigned 
 extern void release_perfctr_nmi(unsigned int);
 extern int reserve_evntsel_nmi(unsigned int);
 extern void release_evntsel_nmi(unsigned int);
+extern void default_nmi_init(void);
 
 extern void setup_apic_nmi_watchdog(void *);
 extern void stop_apic_nmi_watchdog(void *);

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] x86: Enable NMI on all cpus on UV
  2010-02-25 17:24   ` Russ Anderson
@ 2010-02-26  9:22     ` Ingo Molnar
  2010-02-26 16:49       ` Russ Anderson
  0 siblings, 1 reply; 8+ messages in thread
From: Ingo Molnar @ 2010-02-26  9:22 UTC (permalink / raw)
  To: Russ Anderson; +Cc: H. Peter Anvin, tglx, linux-kernel


* Russ Anderson <rja@sgi.com> wrote:

> On Mon, Feb 22, 2010 at 11:38:53AM +0100, Ingo Molnar wrote:
> > 
> > * Russ Anderson <rja@sgi.com> wrote:
> > 
> > > Enable NMI on all cpus in UV system and add an NMI handler
> > > to dump_stack on each cpu.
> > > 
> > > Signed-off-by: Russ Anderson <rja@sgi.com>
> [...]
> > >  						 struct mm_struct *mm,
> > > Index: linux/arch/x86/kernel/smpboot.c
> > > ===================================================================
> > > --- linux.orig/arch/x86/kernel/smpboot.c	2010-02-17 10:21:55.000000000 -0600
> > > +++ linux/arch/x86/kernel/smpboot.c	2010-02-17 10:32:20.000000000 -0600
> > > @@ -320,6 +320,8 @@ notrace static void __cpuinit start_seco
> > >  	unlock_vector_lock();
> > >  	ipi_call_unlock();
> > >  	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
> > > +	if (is_uv_system())
> > > +		uv_nmi_init();
> > 
> > Instead of cramming it into the init sequence open-coded, shouldnt this be 
> > done via the x86_platform driver mechanism?
> 
> Attached is the updated patch with the x86_platform driver mechanism
> used for uv_nmi_init.

ok, this looks far cleaner. A few nits:

> + * When NMI is received, print a stack trace.
> + */
> +int uv_handle_nmi(struct notifier_block *self,
> +		  unsigned long reason, void *data)

Please put prototypes on a single line if it's still below 100 cols or so.

> +{
> +	unsigned long flags;
> +	static DEFINE_SPINLOCK(uv_nmi_lock);

Please dont hide locks amongst local variables. (even if they are only used by 
that function)

> +
> +	if (reason != DIE_NMI_IPI)
> +		return NOTIFY_OK;
> +	/*
> +	 * Use a lock so only one cpu prints at a time
> +	 * to prevent intermixed output.
> +	 */
> +	spin_lock_irqsave(&uv_nmi_lock, flags);
> +	printk(KERN_INFO "NMI stack dump cpu %u:\n",
> +				smp_processor_id());

Can be on a single line too.

Can use pr_info().

Should use a raw spinlock - this is NMI context.

> +	dump_stack();
> +	spin_unlock_irqrestore(&uv_nmi_lock, flags);
> +
> +	return NOTIFY_STOP;
> +}
> +
> +static struct notifier_block uv_dump_stack_nmi_nb = {
> +  .notifier_call = uv_handle_nmi,
> +  .next = NULL,
> +  .priority = 0
> +};

Please align structure initializations vertically.

Plus no need to open-code the setting of priority to 0 i guess.

> +
> +void uv_register_nmi_notifier(void)
> +{
> +	if (register_die_notifier(&uv_dump_stack_nmi_nb))
> +		printk(KERN_WARNING "UV NMI handler failed to register\n");
> +}
> +
> +void uv_nmi_init(void)
> +{
> +	unsigned int value;
> +
> +	/*
> +	 * Unmask NMI on all cpus
> +	 */
> +	value = apic_read(APIC_LVT1) | APIC_DM_NMI;
> +	value &= ~APIC_LVT_MASKED;
> +	apic_write(APIC_LVT1, value);
> +}
>  
>  void __init uv_system_init(void)
>  {
> @@ -690,5 +739,6 @@ void __init uv_system_init(void)
>  
>  	uv_cpu_init();
>  	uv_scir_register_cpu_notifier();
> +	uv_register_nmi_notifier();
>  	proc_mkdir("sgi_uv", NULL);
>  }
> Index: linux/arch/x86/include/asm/uv/uv.h
> ===================================================================
> --- linux.orig/arch/x86/include/asm/uv/uv.h	2010-02-25 11:01:48.131694174 -0600
> +++ linux/arch/x86/include/asm/uv/uv.h	2010-02-25 11:02:17.622069711 -0600
> @@ -11,6 +11,7 @@ struct mm_struct;
>  extern enum uv_system_type get_uv_system_type(void);
>  extern int is_uv_system(void);
>  extern void uv_cpu_init(void);
> +extern void uv_nmi_init(void);
>  extern void uv_system_init(void);
>  extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
>  						 struct mm_struct *mm,
> Index: linux/arch/x86/kernel/smpboot.c
> ===================================================================
> --- linux.orig/arch/x86/kernel/smpboot.c	2010-02-25 11:01:50.929770347 -0600
> +++ linux/arch/x86/kernel/smpboot.c	2010-02-25 11:02:17.664720876 -0600
> @@ -263,6 +263,11 @@ static void __cpuinit smp_callin(void)
>  	cpumask_set_cpu(cpuid, cpu_callin_mask);
>  }
>  
> +void default_nmi_init(void)
> +{
> +	return;
> +}

That return is not needed.

> +
>  /*
>   * Activate a secondary processor.
>   */
> @@ -320,6 +325,7 @@ notrace static void __cpuinit start_seco
>  	unlock_vector_lock();
>  	ipi_call_unlock();
>  	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
> +	x86_platform.nmi_init();
>  
>  	/* enable local interrupts */
>  	local_irq_enable();
> Index: linux/arch/x86/include/asm/x86_init.h
> ===================================================================
> --- linux.orig/arch/x86/include/asm/x86_init.h	2010-02-25 11:01:48.131694174 -0600
> +++ linux/arch/x86/include/asm/x86_init.h	2010-02-25 11:02:17.696714616 -0600
> @@ -126,6 +126,7 @@ struct x86_cpuinit_ops {
>   * @get_wallclock:		get time from HW clock like RTC etc.
>   * @set_wallclock:		set time back to HW clock
>   * @is_untracked_pat_range	exclude from PAT logic
> + * @nmi_init			enable NMI on cpus
>   */
>  struct x86_platform_ops {
>  	unsigned long (*calibrate_tsc)(void);
> @@ -133,6 +134,7 @@ struct x86_platform_ops {
>  	int (*set_wallclock)(unsigned long nowtime);
>  	void (*iommu_shutdown)(void);
>  	bool (*is_untracked_pat_range)(u64 start, u64 end);
> +	void (*nmi_init)(void);
>  };
>  
>  extern struct x86_init_ops x86_init;
> Index: linux/arch/x86/kernel/x86_init.c
> ===================================================================
> --- linux.orig/arch/x86/kernel/x86_init.c	2010-02-25 11:01:47.848760574 -0600
> +++ linux/arch/x86/kernel/x86_init.c	2010-02-25 11:02:17.732996103 -0600
> @@ -13,6 +13,7 @@
>  #include <asm/e820.h>
>  #include <asm/time.h>
>  #include <asm/irq.h>
> +#include <asm/nmi.h>
>  #include <asm/pat.h>
>  #include <asm/tsc.h>
>  #include <asm/iommu.h>
> @@ -82,4 +83,5 @@ struct x86_platform_ops x86_platform = {
>  	.set_wallclock			= mach_set_rtc_mmss,
>  	.iommu_shutdown			= iommu_shutdown_noop,
>  	.is_untracked_pat_range		= is_ISA_range,
> +	.nmi_init			= default_nmi_init
>  };

the default can be in this file too - then you can also make it 'static' and 
save some space and not touch smpboot.c.

> Index: linux/arch/x86/include/asm/nmi.h
> ===================================================================
> --- linux.orig/arch/x86/include/asm/nmi.h	2010-02-25 11:01:48.131694174 -0600
> +++ linux/arch/x86/include/asm/nmi.h	2010-02-25 11:02:17.756721420 -0600
> @@ -24,6 +24,7 @@ extern int reserve_perfctr_nmi(unsigned 
>  extern void release_perfctr_nmi(unsigned int);
>  extern int reserve_evntsel_nmi(unsigned int);
>  extern void release_evntsel_nmi(unsigned int);
> +extern void default_nmi_init(void);
>  
>  extern void setup_apic_nmi_watchdog(void *);
>  extern void stop_apic_nmi_watchdog(void *);

This will go away in that case as well.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] x86: Enable NMI on all cpus on UV
  2010-02-26  9:22     ` Ingo Molnar
@ 2010-02-26 16:49       ` Russ Anderson
  2010-02-27 11:35         ` Ingo Molnar
  2010-02-27 12:56         ` [tip:x86/pci] " tip-bot for Russ Anderson
  0 siblings, 2 replies; 8+ messages in thread
From: Russ Anderson @ 2010-02-26 16:49 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: H. Peter Anvin, tglx, linux-kernel, rja

[-- Attachment #1: Type: text/plain, Size: 7346 bytes --]

Attached is a patch that cleans up Ingo's nits.


On Fri, Feb 26, 2010 at 10:22:52AM +0100, Ingo Molnar wrote:
> 
> * Russ Anderson <rja@sgi.com> wrote:
> 
> > On Mon, Feb 22, 2010 at 11:38:53AM +0100, Ingo Molnar wrote:
> > > 
> > > * Russ Anderson <rja@sgi.com> wrote:
> > > 
> > > > Enable NMI on all cpus in UV system and add an NMI handler
> > > > to dump_stack on each cpu.
> > > > 
> > > > Signed-off-by: Russ Anderson <rja@sgi.com>
> > [...]
> > > >  						 struct mm_struct *mm,
> > > > Index: linux/arch/x86/kernel/smpboot.c
> > > > ===================================================================
> > > > --- linux.orig/arch/x86/kernel/smpboot.c	2010-02-17 10:21:55.000000000 -0600
> > > > +++ linux/arch/x86/kernel/smpboot.c	2010-02-17 10:32:20.000000000 -0600
> > > > @@ -320,6 +320,8 @@ notrace static void __cpuinit start_seco
> > > >  	unlock_vector_lock();
> > > >  	ipi_call_unlock();
> > > >  	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
> > > > +	if (is_uv_system())
> > > > +		uv_nmi_init();
> > > 
> > > Instead of cramming it into the init sequence open-coded, shouldnt this be 
> > > done via the x86_platform driver mechanism?
> > 
> > Attached is the updated patch with the x86_platform driver mechanism
> > used for uv_nmi_init.
> 
> ok, this looks far cleaner. A few nits:
> 
> > + * When NMI is received, print a stack trace.
> > + */
> > +int uv_handle_nmi(struct notifier_block *self,
> > +		  unsigned long reason, void *data)
> 
> Please put prototypes on a single line if it's still below 100 cols or so.

Done.

> > +{
> > +	unsigned long flags;
> > +	static DEFINE_SPINLOCK(uv_nmi_lock);
> 
> Please dont hide locks amongst local variables. (even if they are only used by 
> that function)

Done.

> > +
> > +	if (reason != DIE_NMI_IPI)
> > +		return NOTIFY_OK;
> > +	/*
> > +	 * Use a lock so only one cpu prints at a time
> > +	 * to prevent intermixed output.
> > +	 */
> > +	spin_lock_irqsave(&uv_nmi_lock, flags);
> > +	printk(KERN_INFO "NMI stack dump cpu %u:\n",
> > +				smp_processor_id());
> 
> Can be on a single line too.
> 
> Can use pr_info().
> 
> Should use a raw spinlock - this is NMI context.

Done.

> > +	dump_stack();
> > +	spin_unlock_irqrestore(&uv_nmi_lock, flags);
> > +
> > +	return NOTIFY_STOP;
> > +}
> > +
> > +static struct notifier_block uv_dump_stack_nmi_nb = {
> > +  .notifier_call = uv_handle_nmi,
> > +  .next = NULL,
> > +  .priority = 0
> > +};
> 
> Please align structure initializations vertically.
> 
> Plus no need to open-code the setting of priority to 0 i guess.

Done.

> > +
> > +void uv_register_nmi_notifier(void)
> > +{
> > +	if (register_die_notifier(&uv_dump_stack_nmi_nb))
> > +		printk(KERN_WARNING "UV NMI handler failed to register\n");
> > +}
> > +
> > +void uv_nmi_init(void)
> > +{
> > +	unsigned int value;
> > +
> > +	/*
> > +	 * Unmask NMI on all cpus
> > +	 */
> > +	value = apic_read(APIC_LVT1) | APIC_DM_NMI;
> > +	value &= ~APIC_LVT_MASKED;
> > +	apic_write(APIC_LVT1, value);
> > +}
> >  
> >  void __init uv_system_init(void)
> >  {
> > @@ -690,5 +739,6 @@ void __init uv_system_init(void)
> >  
> >  	uv_cpu_init();
> >  	uv_scir_register_cpu_notifier();
> > +	uv_register_nmi_notifier();
> >  	proc_mkdir("sgi_uv", NULL);
> >  }
> > Index: linux/arch/x86/include/asm/uv/uv.h
> > ===================================================================
> > --- linux.orig/arch/x86/include/asm/uv/uv.h	2010-02-25 11:01:48.131694174 -0600
> > +++ linux/arch/x86/include/asm/uv/uv.h	2010-02-25 11:02:17.622069711 -0600
> > @@ -11,6 +11,7 @@ struct mm_struct;
> >  extern enum uv_system_type get_uv_system_type(void);
> >  extern int is_uv_system(void);
> >  extern void uv_cpu_init(void);
> > +extern void uv_nmi_init(void);
> >  extern void uv_system_init(void);
> >  extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
> >  						 struct mm_struct *mm,
> > Index: linux/arch/x86/kernel/smpboot.c
> > ===================================================================
> > --- linux.orig/arch/x86/kernel/smpboot.c	2010-02-25 11:01:50.929770347 -0600
> > +++ linux/arch/x86/kernel/smpboot.c	2010-02-25 11:02:17.664720876 -0600
> > @@ -263,6 +263,11 @@ static void __cpuinit smp_callin(void)
> >  	cpumask_set_cpu(cpuid, cpu_callin_mask);
> >  }
> >  
> > +void default_nmi_init(void)
> > +{
> > +	return;
> > +}
> 
> That return is not needed.

Done and moved to x86_init.c.

> > +
> >  /*
> >   * Activate a secondary processor.
> >   */
> > @@ -320,6 +325,7 @@ notrace static void __cpuinit start_seco
> >  	unlock_vector_lock();
> >  	ipi_call_unlock();
> >  	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
> > +	x86_platform.nmi_init();
> >  
> >  	/* enable local interrupts */
> >  	local_irq_enable();
> > Index: linux/arch/x86/include/asm/x86_init.h
> > ===================================================================
> > --- linux.orig/arch/x86/include/asm/x86_init.h	2010-02-25 11:01:48.131694174 -0600
> > +++ linux/arch/x86/include/asm/x86_init.h	2010-02-25 11:02:17.696714616 -0600
> > @@ -126,6 +126,7 @@ struct x86_cpuinit_ops {
> >   * @get_wallclock:		get time from HW clock like RTC etc.
> >   * @set_wallclock:		set time back to HW clock
> >   * @is_untracked_pat_range	exclude from PAT logic
> > + * @nmi_init			enable NMI on cpus
> >   */
> >  struct x86_platform_ops {
> >  	unsigned long (*calibrate_tsc)(void);
> > @@ -133,6 +134,7 @@ struct x86_platform_ops {
> >  	int (*set_wallclock)(unsigned long nowtime);
> >  	void (*iommu_shutdown)(void);
> >  	bool (*is_untracked_pat_range)(u64 start, u64 end);
> > +	void (*nmi_init)(void);
> >  };
> >  
> >  extern struct x86_init_ops x86_init;
> > Index: linux/arch/x86/kernel/x86_init.c
> > ===================================================================
> > --- linux.orig/arch/x86/kernel/x86_init.c	2010-02-25 11:01:47.848760574 -0600
> > +++ linux/arch/x86/kernel/x86_init.c	2010-02-25 11:02:17.732996103 -0600
> > @@ -13,6 +13,7 @@
> >  #include <asm/e820.h>
> >  #include <asm/time.h>
> >  #include <asm/irq.h>
> > +#include <asm/nmi.h>
> >  #include <asm/pat.h>
> >  #include <asm/tsc.h>
> >  #include <asm/iommu.h>
> > @@ -82,4 +83,5 @@ struct x86_platform_ops x86_platform = {
> >  	.set_wallclock			= mach_set_rtc_mmss,
> >  	.iommu_shutdown			= iommu_shutdown_noop,
> >  	.is_untracked_pat_range		= is_ISA_range,
> > +	.nmi_init			= default_nmi_init
> >  };
> 
> the default can be in this file too - then you can also make it 'static' and 
> save some space and not touch smpboot.c.

Done.

> > Index: linux/arch/x86/include/asm/nmi.h
> > ===================================================================
> > --- linux.orig/arch/x86/include/asm/nmi.h	2010-02-25 11:01:48.131694174 -0600
> > +++ linux/arch/x86/include/asm/nmi.h	2010-02-25 11:02:17.756721420 -0600
> > @@ -24,6 +24,7 @@ extern int reserve_perfctr_nmi(unsigned 
> >  extern void release_perfctr_nmi(unsigned int);
> >  extern int reserve_evntsel_nmi(unsigned int);
> >  extern void release_evntsel_nmi(unsigned int);
> > +extern void default_nmi_init(void);
> >  
> >  extern void setup_apic_nmi_watchdog(void *);
> >  extern void stop_apic_nmi_watchdog(void *);
> 
> This will go away in that case as well.

Removed.

> Thanks,
> 
> 	Ingo

-- 
Russ Anderson, OS RAS/Partitioning Project Lead  
SGI - Silicon Graphics Inc          rja@sgi.com

[-- Attachment #2: uv_nmi_handler --]
[-- Type: text/plain, Size: 5749 bytes --]

Enable NMI on all cpus in UV system and add an NMI handler
to dump_stack on each cpu.

Signed-off-by: Russ Anderson <rja@sgi.com>

---

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.


 arch/x86/include/asm/uv/uv.h       |    1 
 arch/x86/include/asm/x86_init.h    |    2 +
 arch/x86/kernel/apic/x2apic_uv_x.c |   44 +++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/smpboot.c          |    1 
 arch/x86/kernel/x86_init.c         |    3 ++
 5 files changed, 51 insertions(+)

Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
===================================================================
--- linux.orig/arch/x86/kernel/apic/x2apic_uv_x.c	2010-02-26 09:46:02.424716224 -0600
+++ linux/arch/x86/kernel/apic/x2apic_uv_x.c	2010-02-26 09:46:06.932745200 -0600
@@ -20,6 +20,7 @@
 #include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/kdebug.h>
 
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
@@ -38,6 +39,7 @@ static enum uv_system_type uv_system_typ
 static u64 gru_start_paddr, gru_end_paddr;
 int uv_min_hub_revision_id;
 EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
+static DEFINE_SPINLOCK(uv_nmi_lock);
 
 static inline bool is_GRU_range(u64 start, u64 end)
 {
@@ -71,6 +73,7 @@ static int __init uv_acpi_madt_oem_check
 	if (!strcmp(oem_id, "SGI")) {
 		nodeid = early_get_nodeid();
 		x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
+		x86_platform.nmi_init =  uv_nmi_init;
 		if (!strcmp(oem_table_id, "UVL"))
 			uv_system_type = UV_LEGACY_APIC;
 		else if (!strcmp(oem_table_id, "UVX"))
@@ -569,6 +572,46 @@ void __cpuinit uv_cpu_init(void)
 		set_x2apic_extra_bits(uv_hub_info->pnode);
 }
 
+/*
+ * When NMI is received, print a stack trace.
+ */
+int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data)
+{
+	if (reason != DIE_NMI_IPI)
+		return NOTIFY_OK;
+	/*
+	 * Use a lock so only one cpu prints at a time
+	 * to prevent intermixed output.
+	 */
+	spin_lock(&uv_nmi_lock);
+	pr_info("NMI stack dump cpu %u:\n", smp_processor_id());
+	dump_stack();
+	spin_unlock(&uv_nmi_lock);
+
+	return NOTIFY_STOP;
+}
+
+static struct notifier_block uv_dump_stack_nmi_nb = {
+	.notifier_call	= uv_handle_nmi
+};
+
+void uv_register_nmi_notifier(void)
+{
+	if (register_die_notifier(&uv_dump_stack_nmi_nb))
+		printk(KERN_WARNING "UV NMI handler failed to register\n");
+}
+
+void uv_nmi_init(void)
+{
+	unsigned int value;
+
+	/*
+	 * Unmask NMI on all cpus
+	 */
+	value = apic_read(APIC_LVT1) | APIC_DM_NMI;
+	value &= ~APIC_LVT_MASKED;
+	apic_write(APIC_LVT1, value);
+}
 
 void __init uv_system_init(void)
 {
@@ -690,5 +733,6 @@ void __init uv_system_init(void)
 
 	uv_cpu_init();
 	uv_scir_register_cpu_notifier();
+	uv_register_nmi_notifier();
 	proc_mkdir("sgi_uv", NULL);
 }
Index: linux/arch/x86/include/asm/uv/uv.h
===================================================================
--- linux.orig/arch/x86/include/asm/uv/uv.h	2010-02-26 09:46:02.424716224 -0600
+++ linux/arch/x86/include/asm/uv/uv.h	2010-02-26 09:46:06.932745200 -0600
@@ -11,6 +11,7 @@ struct mm_struct;
 extern enum uv_system_type get_uv_system_type(void);
 extern int is_uv_system(void);
 extern void uv_cpu_init(void);
+extern void uv_nmi_init(void);
 extern void uv_system_init(void);
 extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 						 struct mm_struct *mm,
Index: linux/arch/x86/kernel/smpboot.c
===================================================================
--- linux.orig/arch/x86/kernel/smpboot.c	2010-02-26 09:46:02.424716224 -0600
+++ linux/arch/x86/kernel/smpboot.c	2010-02-26 09:46:06.962240641 -0600
@@ -320,6 +320,7 @@ notrace static void __cpuinit start_seco
 	unlock_vector_lock();
 	ipi_call_unlock();
 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+	x86_platform.nmi_init();
 
 	/* enable local interrupts */
 	local_irq_enable();
Index: linux/arch/x86/include/asm/x86_init.h
===================================================================
--- linux.orig/arch/x86/include/asm/x86_init.h	2010-02-26 09:46:02.428714989 -0600
+++ linux/arch/x86/include/asm/x86_init.h	2010-02-26 09:46:07.006220579 -0600
@@ -126,6 +126,7 @@ struct x86_cpuinit_ops {
  * @get_wallclock:		get time from HW clock like RTC etc.
  * @set_wallclock:		set time back to HW clock
  * @is_untracked_pat_range	exclude from PAT logic
+ * @nmi_init			enable NMI on cpus
  */
 struct x86_platform_ops {
 	unsigned long (*calibrate_tsc)(void);
@@ -133,6 +134,7 @@ struct x86_platform_ops {
 	int (*set_wallclock)(unsigned long nowtime);
 	void (*iommu_shutdown)(void);
 	bool (*is_untracked_pat_range)(u64 start, u64 end);
+	void (*nmi_init)(void);
 };
 
 extern struct x86_init_ops x86_init;
Index: linux/arch/x86/kernel/x86_init.c
===================================================================
--- linux.orig/arch/x86/kernel/x86_init.c	2010-02-26 09:46:02.424716224 -0600
+++ linux/arch/x86/kernel/x86_init.c	2010-02-26 09:47:05.377453462 -0600
@@ -76,10 +76,13 @@ struct x86_cpuinit_ops x86_cpuinit __cpu
 	.setup_percpu_clockev		= setup_secondary_APIC_clock,
 };
 
+static void default_nmi_init(void) { };
+
 struct x86_platform_ops x86_platform = {
 	.calibrate_tsc			= native_calibrate_tsc,
 	.get_wallclock			= mach_get_cmos_time,
 	.set_wallclock			= mach_set_rtc_mmss,
 	.iommu_shutdown			= iommu_shutdown_noop,
 	.is_untracked_pat_range		= is_ISA_range,
+	.nmi_init			= default_nmi_init
 };

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] x86: Enable NMI on all cpus on UV
  2010-02-26 16:49       ` Russ Anderson
@ 2010-02-27 11:35         ` Ingo Molnar
  2010-02-27 12:56         ` [tip:x86/pci] " tip-bot for Russ Anderson
  1 sibling, 0 replies; 8+ messages in thread
From: Ingo Molnar @ 2010-02-27 11:35 UTC (permalink / raw)
  To: Russ Anderson; +Cc: H. Peter Anvin, tglx, linux-kernel


* Russ Anderson <rja@sgi.com> wrote:

> Attached is a patch that cleans up Ingo's nits.

Applied, thanks Russ!

>  		nodeid = early_get_nodeid();
>  		x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
> +		x86_platform.nmi_init =  uv_nmi_init;

I did a "s/ / /" here.

	Ingo

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [tip:x86/pci] x86: Enable NMI on all cpus on UV
  2010-02-26 16:49       ` Russ Anderson
  2010-02-27 11:35         ` Ingo Molnar
@ 2010-02-27 12:56         ` tip-bot for Russ Anderson
  1 sibling, 0 replies; 8+ messages in thread
From: tip-bot for Russ Anderson @ 2010-02-27 12:56 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, rja, hpa, mingo, tglx, mingo

Commit-ID:  78c06176466cbd1b3f0f67709d3023c40dbebcbd
Gitweb:     http://git.kernel.org/tip/78c06176466cbd1b3f0f67709d3023c40dbebcbd
Author:     Russ Anderson <rja@sgi.com>
AuthorDate: Fri, 26 Feb 2010 10:49:12 -0600
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Sat, 27 Feb 2010 12:34:21 +0100

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>
---
 arch/x86/include/asm/uv/uv.h       |    1 +
 arch/x86/include/asm/x86_init.h    |    2 +
 arch/x86/kernel/apic/x2apic_uv_x.c |   44 ++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/smpboot.c          |    1 +
 arch/x86/kernel/x86_init.c         |    3 ++
 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 c0a01b5..3bb9491 100644
--- a/arch/x86/include/asm/uv/uv.h
+++ b/arch/x86/include/asm/uv/uv.h
@@ -11,6 +11,7 @@ struct mm_struct;
 extern enum uv_system_type get_uv_system_type(void);
 extern int is_uv_system(void);
 extern void uv_cpu_init(void);
+extern void uv_nmi_init(void);
 extern void uv_system_init(void);
 extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 						 struct mm_struct *mm,
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index ea0e8ea..60cc352 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 {
  * @get_wallclock:		get time from HW clock like RTC etc.
  * @set_wallclock:		set time back to HW clock
  * @is_untracked_pat_range	exclude from PAT logic
+ * @nmi_init			enable NMI on cpus
  */
 struct x86_platform_ops {
 	unsigned long (*calibrate_tsc)(void);
@@ -133,6 +134,7 @@ struct x86_platform_ops {
 	int (*set_wallclock)(unsigned long nowtime);
 	void (*iommu_shutdown)(void);
 	bool (*is_untracked_pat_range)(u64 start, u64 end);
+	void (*nmi_init)(void);
 };
 
 extern 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 6ef2899..4b8dbb2 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/pci.h>
+#include <linux/kdebug.h>
 
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
@@ -41,6 +42,7 @@ static enum uv_system_type uv_system_type;
 static u64 gru_start_paddr, gru_end_paddr;
 int uv_min_hub_revision_id;
 EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
+static DEFINE_SPINLOCK(uv_nmi_lock);
 
 static inline bool is_GRU_range(u64 start, u64 end)
 {
@@ -74,6 +76,7 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 	if (!strcmp(oem_id, "SGI")) {
 		nodeid = early_get_nodeid();
 		x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
+		x86_platform.nmi_init = uv_nmi_init;
 		if (!strcmp(oem_table_id, "UVL"))
 			uv_system_type = UV_LEGACY_APIC;
 		else if (!strcmp(oem_table_id, "UVX"))
@@ -596,6 +599,46 @@ void __cpuinit uv_cpu_init(void)
 		set_x2apic_extra_bits(uv_hub_info->pnode);
 }
 
+/*
+ * When NMI is received, print a stack trace.
+ */
+int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data)
+{
+	if (reason != DIE_NMI_IPI)
+		return NOTIFY_OK;
+	/*
+	 * Use a lock so only one cpu prints at a time
+	 * to prevent intermixed output.
+	 */
+	spin_lock(&uv_nmi_lock);
+	pr_info("NMI stack dump cpu %u:\n", smp_processor_id());
+	dump_stack();
+	spin_unlock(&uv_nmi_lock);
+
+	return NOTIFY_STOP;
+}
+
+static struct notifier_block uv_dump_stack_nmi_nb = {
+	.notifier_call	= uv_handle_nmi
+};
+
+void uv_register_nmi_notifier(void)
+{
+	if (register_die_notifier(&uv_dump_stack_nmi_nb))
+		printk(KERN_WARNING "UV NMI handler failed to register\n");
+}
+
+void uv_nmi_init(void)
+{
+	unsigned int value;
+
+	/*
+	 * Unmask NMI on all cpus
+	 */
+	value = apic_read(APIC_LVT1) | APIC_DM_NMI;
+	value &= ~APIC_LVT_MASKED;
+	apic_write(APIC_LVT1, value);
+}
 
 void __init uv_system_init(void)
 {
@@ -717,6 +760,7 @@ void __init uv_system_init(void)
 
 	uv_cpu_init();
 	uv_scir_register_cpu_notifier();
+	uv_register_nmi_notifier();
 	proc_mkdir("sgi_uv", NULL);
 
 	/* register Legacy VGA I/O redirection handler */
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 678d0b8..838a118 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)
 	unlock_vector_lock();
 	ipi_call_unlock();
 	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+	x86_platform.nmi_init();
 
 	/* enable local interrupts */
 	local_irq_enable();
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index ccd179d..ee5746c 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 = {
 	.setup_percpu_clockev		= setup_secondary_APIC_clock,
 };
 
+static void default_nmi_init(void) { };
+
 struct x86_platform_ops x86_platform = {
 	.calibrate_tsc			= native_calibrate_tsc,
 	.get_wallclock			= mach_get_cmos_time,
 	.set_wallclock			= mach_set_rtc_mmss,
 	.iommu_shutdown			= iommu_shutdown_noop,
 	.is_untracked_pat_range		= is_ISA_range,
+	.nmi_init			= default_nmi_init
 };

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-02-27 12:57 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-17 16:50 [PATCH] x86: Enable NMI on all cpus on UV Russ Anderson
2010-02-22 10:38 ` Ingo Molnar
2010-02-22 22:24   ` Russ Anderson
2010-02-25 17:24   ` Russ Anderson
2010-02-26  9:22     ` Ingo Molnar
2010-02-26 16:49       ` Russ Anderson
2010-02-27 11:35         ` Ingo Molnar
2010-02-27 12:56         ` [tip:x86/pci] " tip-bot for Russ Anderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.