public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch 01/11] x86: nmi - unify die_nmi() interface
       [not found] <20080524153630.669797039@gmail.com>
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 02/11] x86: nmi - die_nmi() output message unification Cyrill Gorcunov
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: die-nmi-32-unify --]
[-- Type: text/plain, Size: 3140 bytes --]

By slightly changing 32bit mode die_nmi() we may unify the
interface and make it common for both (32/64bit) modes

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 19:22:41.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_32.c	2008-05-24 19:22:47.000000000 +0400
@@ -320,8 +320,6 @@ void touch_nmi_watchdog(void)
 }
 EXPORT_SYMBOL(touch_nmi_watchdog);
 
-extern void die_nmi(struct pt_regs *, const char *msg);
-
 notrace __kprobes int
 nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
 {
@@ -375,7 +373,8 @@ nmi_watchdog_tick(struct pt_regs *regs, 
 			/*
 			 * die_nmi will return ONLY if NOTIFY_STOP happens..
 			 */
-			die_nmi(regs, "BUG: NMI Watchdog detected LOCKUP");
+			die_nmi("BUG: NMI Watchdog detected LOCKUP",
+				regs, 0);
 	} else {
 		__get_cpu_var(last_irq_sum) = sum;
 		local_set(&__get_cpu_var(alert_counter), 0);
@@ -406,7 +405,7 @@ static int unknown_nmi_panic_callback(st
 	char buf[64];
 
 	sprintf(buf, "NMI received for unknown reason %02x\n", reason);
-	die_nmi(regs, buf);
+	die_nmi(buf, regs, 0);
 	return 0;
 }
 
Index: linux-2.6.git/arch/x86/kernel/traps_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/traps_32.c	2008-05-24 19:22:41.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/traps_32.c	2008-05-24 19:24:31.000000000 +0400
@@ -755,9 +755,9 @@ unknown_nmi_error(unsigned char reason, 
 
 static DEFINE_SPINLOCK(nmi_print_lock);
 
-void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg)
+void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
 {
-	if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
 		return;
 
 	spin_lock(&nmi_print_lock);
@@ -766,10 +766,12 @@ void notrace __kprobes die_nmi(struct pt
 	* to get a message out:
 	*/
 	bust_spinlocks(1);
-	printk(KERN_EMERG "%s", msg);
+	printk(KERN_EMERG "%s", str);
 	printk(" on CPU%d, ip %08lx, registers:\n",
 		smp_processor_id(), regs->ip);
 	show_registers(regs);
+	if (do_panic)
+		panic("Non maskable interrupt");
 	console_silent();
 	spin_unlock(&nmi_print_lock);
 	bust_spinlocks(0);
Index: linux-2.6.git/include/asm-x86/nmi.h
====================================================================
--- linux-2.6.git.orig/include/asm-x86/nmi.h	2008-05-24 19:22:41.000000000 +0400
+++ linux-2.6.git/include/asm-x86/nmi.h	2008-05-24 19:22:47.000000000 +0400
@@ -38,12 +38,12 @@ static inline void unset_nmi_pm_callback
 
 #ifdef CONFIG_X86_64
 extern void default_do_nmi(struct pt_regs *);
-extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern void nmi_watchdog_default(void);
 #else
 #define nmi_watchdog_default() do {} while (0)
 #endif
 
+extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern int check_nmi_watchdog(void);
 extern int nmi_watchdog_enabled;
 extern int unknown_nmi_panic;

-- 

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

* [patch 02/11] x86: nmi - die_nmi() output message unification
       [not found] <20080524153630.669797039@gmail.com>
  2008-05-24 15:36 ` [patch 01/11] x86: nmi - unify die_nmi() interface Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 03/11] x86: nmi_64.c - move do_nmi(), stop_nmi() and restart_nmi() implementation to traps_64.c Cyrill Gorcunov
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: traps-64-output-unify --]
[-- Type: text/plain, Size: 1495 bytes --]

Make 64bit die_nmi() to produce the same message as 32bit mode has

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_64.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_64.c	2008-05-24 12:07:40.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_64.c	2008-05-24 12:25:57.000000000 +0400
@@ -358,8 +358,8 @@ nmi_watchdog_tick(struct pt_regs *regs, 
 		 */
 		local_inc(&__get_cpu_var(alert_counter));
 		if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz)
-			die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs,
-				panic_on_timeout);
+			die_nmi("NMI Watchdog detected LOCKUP",
+				regs, panic_on_timeout);
 	} else {
 		__get_cpu_var(last_irq_sum) = sum;
 		local_set(&__get_cpu_var(alert_counter), 0);
Index: linux-2.6.git/arch/x86/kernel/traps_64.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/traps_64.c	2008-05-24 12:07:40.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/traps_64.c	2008-05-24 12:25:11.000000000 +0400
@@ -614,7 +614,9 @@ die_nmi(char *str, struct pt_regs *regs,
 	 * We are in trouble anyway, lets at least try
 	 * to get a message out.
 	 */
-	printk(str, smp_processor_id());
+	printk(KERN_EMERG "%s", str);
+	printk(" on CPU%d, ip %08lx, registers:\n",
+		smp_processor_id(), regs->ip);
 	show_registers(regs);
 	if (kexec_should_crash(current))
 		crash_kexec(regs);

-- 

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

* [patch 03/11] x86: nmi_64.c - move do_nmi(), stop_nmi() and restart_nmi() implementation to traps_64.c
       [not found] <20080524153630.669797039@gmail.com>
  2008-05-24 15:36 ` [patch 01/11] x86: nmi - unify die_nmi() interface Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 02/11] x86: nmi - die_nmi() output message unification Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 04/11] x86: nmi_32.c - add "panic" option Cyrill Gorcunov
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-64-move-spec-func-to-traps --]
[-- Type: text/plain, Size: 2225 bytes --]

traps_32.c already holds these functions so do the same for traps_64.c

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_64.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_64.c	2008-05-24 12:25:57.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_64.c	2008-05-24 12:38:09.000000000 +0400
@@ -30,7 +30,6 @@
 
 int unknown_nmi_panic;
 int nmi_watchdog_enabled;
-int panic_on_unrecovered_nmi;
 
 static cpumask_t backtrace_mask = CPU_MASK_NONE;
 
@@ -383,30 +382,6 @@ nmi_watchdog_tick(struct pt_regs *regs, 
 	return rc;
 }
 
-static unsigned ignore_nmis;
-
-asmlinkage notrace __kprobes void
-do_nmi(struct pt_regs *regs, long error_code)
-{
-	nmi_enter();
-	add_pda(__nmi_count,1);
-	if (!ignore_nmis)
-		default_do_nmi(regs);
-	nmi_exit();
-}
-
-void stop_nmi(void)
-{
-	acpi_nmi_disable();
-	ignore_nmis++;
-}
-
-void restart_nmi(void)
-{
-	ignore_nmis--;
-	acpi_nmi_enable();
-}
-
 #ifdef CONFIG_SYSCTL
 
 static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
Index: linux-2.6.git/arch/x86/kernel/traps_64.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/traps_64.c	2008-05-24 12:25:11.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/traps_64.c	2008-05-24 12:39:18.000000000 +0400
@@ -76,7 +76,9 @@ asmlinkage void alignment_check(void);
 asmlinkage void machine_check(void);
 asmlinkage void spurious_interrupt_bug(void);
 
+int panic_on_unrecovered_nmi;
 static unsigned int code_bytes = 64;
+static unsigned ignore_nmis;
 
 static inline void conditional_sti(struct pt_regs *regs)
 {
@@ -867,6 +869,28 @@ asmlinkage notrace  __kprobes void defau
 		io_check_error(reason, regs);
 }
 
+asmlinkage notrace __kprobes void
+do_nmi(struct pt_regs *regs, long error_code)
+{
+	nmi_enter();
+	add_pda(__nmi_count, 1);
+	if (!ignore_nmis)
+		default_do_nmi(regs);
+	nmi_exit();
+}
+
+void stop_nmi(void)
+{
+	acpi_nmi_disable();
+	ignore_nmis++;
+}
+
+void restart_nmi(void)
+{
+	ignore_nmis--;
+	acpi_nmi_enable();
+}
+
 /* runs on IST stack. */
 asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
 {

-- 

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

* [patch 04/11] x86: nmi_32.c - add "panic" option
       [not found] <20080524153630.669797039@gmail.com>
                   ` (2 preceding siblings ...)
  2008-05-24 15:36 ` [patch 03/11] x86: nmi_64.c - move do_nmi(), stop_nmi() and restart_nmi() implementation to traps_64.c Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 05/11] x86: nmi_32.c - add nmi_watchdog_default helper Cyrill Gorcunov
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-32-panic-on-timeout --]
[-- Type: text/plain, Size: 1285 bytes --]

Allow to pass "panic" option in 32bit mode

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 12:29:17.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_32.c	2008-05-24 12:45:30.000000000 +0400
@@ -42,6 +42,7 @@ static cpumask_t backtrace_mask = CPU_MA
  *  0: the lapic NMI watchdog is disabled, but can be enabled
  */
 atomic_t nmi_active = ATOMIC_INIT(0);		/* oprofile uses this */
+static int panic_on_timeout;
 
 unsigned int nmi_watchdog = NMI_DEFAULT;
 static unsigned int nmi_hz = HZ;
@@ -140,6 +141,14 @@ static int __init setup_nmi_watchdog(cha
 {
 	int nmi;
 
+	if (!strncmp(str, "panic", 5)) {
+		panic_on_timeout = 1;
+		str = strchr(str, ',');
+		if (!str)
+			return 1;
+		++str;
+	}
+
 	get_option(&str, &nmi);
 
 	if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
@@ -374,7 +383,7 @@ nmi_watchdog_tick(struct pt_regs *regs, 
 			 * die_nmi will return ONLY if NOTIFY_STOP happens..
 			 */
 			die_nmi("BUG: NMI Watchdog detected LOCKUP",
-				regs, 0);
+				regs, panic_on_timeout);
 	} else {
 		__get_cpu_var(last_irq_sum) = sum;
 		local_set(&__get_cpu_var(alert_counter), 0);

-- 

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

* [patch 05/11] x86: nmi_32.c - add nmi_watchdog_default helper
       [not found] <20080524153630.669797039@gmail.com>
                   ` (3 preceding siblings ...)
  2008-05-24 15:36 ` [patch 04/11] x86: nmi_32.c - add "panic" option Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write Cyrill Gorcunov
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-32-nmi-watchdog-default --]
[-- Type: text/plain, Size: 1929 bytes --]

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 13:01:21.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_32.c	2008-05-24 13:04:20.000000000 +0400
@@ -51,6 +51,17 @@ static DEFINE_PER_CPU(short, wd_enabled)
 
 static int endflag __initdata = 0;
 
+/* Run after command line and cpu_init init, but before all other checks */
+void nmi_watchdog_default(void)
+{
+	if (nmi_watchdog != NMI_DEFAULT)
+		return;
+	if (lapic_watchdog_ok())
+		nmi_watchdog = NMI_LOCAL_APIC;
+	else
+		nmi_watchdog = NMI_IO_APIC;
+}
+
 #ifdef CONFIG_SMP
 /* The performance counters used by NMI_LOCAL_APIC don't trigger when
  * the CPU is idle. To make sure the NMI watchdog really ticks on all
@@ -437,12 +448,8 @@ int proc_nmi_enabled(struct ctl_table *t
 		return -EIO;
 	}
 
-	if (nmi_watchdog == NMI_DEFAULT) {
-		if (lapic_watchdog_ok())
-			nmi_watchdog = NMI_LOCAL_APIC;
-		else
-			nmi_watchdog = NMI_IO_APIC;
-	}
+	/* if nmi_watchdog is not set yet, then set it */
+	nmi_watchdog_default();
 
 	if (nmi_watchdog == NMI_LOCAL_APIC) {
 		if (nmi_watchdog_enabled)
Index: linux-2.6.git/include/asm-x86/nmi.h
====================================================================
--- linux-2.6.git.orig/include/asm-x86/nmi.h	2008-05-24 13:00:50.000000000 +0400
+++ linux-2.6.git/include/asm-x86/nmi.h	2008-05-24 13:04:51.000000000 +0400
@@ -38,11 +38,9 @@ static inline void unset_nmi_pm_callback
 
 #ifdef CONFIG_X86_64
 extern void default_do_nmi(struct pt_regs *);
-extern void nmi_watchdog_default(void);
-#else
-#define nmi_watchdog_default() do {} while (0)
 #endif
 
+extern void nmi_watchdog_default(void);
 extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern int check_nmi_watchdog(void);
 extern int nmi_watchdog_enabled;

-- 

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

* [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
       [not found] <20080524153630.669797039@gmail.com>
                   ` (4 preceding siblings ...)
  2008-05-24 15:36 ` [patch 05/11] x86: nmi_32.c - add nmi_watchdog_default helper Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-28 15:35   ` Maciej W. Rozycki
  2008-05-24 15:36 ` [patch 07/11] x86: nmi_32.c - unknown_nmi_panic_callback should always panic on being called Cyrill Gorcunov
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-use-apic-write-around --]
[-- Type: text/plain, Size: 1503 bytes --]

apic_write_around will be expanded to apic_write in 64bit mode
anyway. Only a few CPUs (well, old CPUs to be precise) requires
such an action. In general it should not hurt and could be cleaned
up for apic_write (just in case)

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 13:04:20.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_32.c	2008-05-24 13:07:08.000000000 +0400
@@ -248,7 +248,7 @@ void acpi_nmi_enable(void)
 
 static void __acpi_nmi_disable(void *__unused)
 {
-	apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
+	apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
 }
 
 /*
Index: linux-2.6.git/arch/x86/kernel/nmi_64.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_64.c	2008-05-24 13:02:04.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_64.c	2008-05-24 13:07:44.000000000 +0400
@@ -215,7 +215,7 @@ late_initcall(init_lapic_nmi_sysfs);
 
 static void __acpi_nmi_enable(void *__unused)
 {
-	apic_write(APIC_LVT0, APIC_DM_NMI);
+	apic_write_around(APIC_LVT0, APIC_DM_NMI);
 }
 
 /*
@@ -229,7 +229,7 @@ void acpi_nmi_enable(void)
 
 static void __acpi_nmi_disable(void *__unused)
 {
-	apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
+	apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
 }
 
 /*

-- 

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

* [patch 07/11] x86: nmi_32.c - unknown_nmi_panic_callback should always panic on being called
       [not found] <20080524153630.669797039@gmail.com>
                   ` (5 preceding siblings ...)
  2008-05-24 15:36 ` [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 08/11] x86: nmi_64.c - use for_each_possible_cpu helper instead of for statement Cyrill Gorcunov
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-32-do-panic-on-unknown-nmi --]
[-- Type: text/plain, Size: 576 bytes --]

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 13:07:08.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_32.c	2008-05-24 13:10:10.000000000 +0400
@@ -425,7 +425,7 @@ static int unknown_nmi_panic_callback(st
 	char buf[64];
 
 	sprintf(buf, "NMI received for unknown reason %02x\n", reason);
-	die_nmi(buf, regs, 0);
+	die_nmi(buf, regs, 1); /* Always panic here */
 	return 0;
 }
 

-- 

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

* [patch 08/11] x86: nmi_64.c - use for_each_possible_cpu helper instead of for statement
       [not found] <20080524153630.669797039@gmail.com>
                   ` (6 preceding siblings ...)
  2008-05-24 15:36 ` [patch 07/11] x86: nmi_32.c - unknown_nmi_panic_callback should always panic on being called Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 09/11] x86: nmi_32.c cleanup - use for_each_online_cpu helper Cyrill Gorcunov
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-64-use-for-each-possible-cpu --]
[-- Type: text/plain, Size: 650 bytes --]

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_64.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_64.c	2008-05-24 13:09:27.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_64.c	2008-05-24 13:17:59.000000000 +0400
@@ -98,7 +98,7 @@ int __init check_nmi_watchdog(void)
 		smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
 #endif
 
-	for (cpu = 0; cpu < NR_CPUS; cpu++)
+	for_each_possible_cpu(cpu)
 		prev_nmi_count[cpu] = cpu_pda(cpu)->__nmi_count;
 	local_irq_enable();
 	mdelay((20*1000)/nmi_hz); // wait 20 ticks

-- 

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

* [patch 09/11] x86: nmi_32.c cleanup - use for_each_online_cpu helper
       [not found] <20080524153630.669797039@gmail.com>
                   ` (7 preceding siblings ...)
  2008-05-24 15:36 ` [patch 08/11] x86: nmi_64.c - use for_each_possible_cpu helper instead of for statement Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 10/11] x86: nmi_32/64.c - add helper functions to hide mode-specific data Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 11/11] x86: nmi_32/64.c - merge down nmi_32.c and nmi_64.c to nmi.c Cyrill Gorcunov
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-32-use-for-each-online-cpu --]
[-- Type: text/plain, Size: 943 bytes --]

Since cpu_online_map is touched (by for_each_online_cpu)
at moment when cpu_callin_map is already filled up we can
get rid of its checking at all

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 13:16:48.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_32.c	2008-05-24 13:20:13.000000000 +0400
@@ -108,13 +108,7 @@ int __init check_nmi_watchdog(void)
 	local_irq_enable();
 	mdelay((20*1000)/nmi_hz); // wait 20 ticks
 
-	for_each_possible_cpu(cpu) {
-#ifdef CONFIG_SMP
-		/* Check cpu_callin_map here because that is set
-		   after the timer is started. */
-		if (!cpu_isset(cpu, cpu_callin_map))
-			continue;
-#endif
+	for_each_online_cpu(cpu) {
 		if (!per_cpu(wd_enabled, cpu))
 			continue;
 		if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {

-- 

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

* [patch 10/11] x86: nmi_32/64.c - add helper functions to hide mode-specific data
       [not found] <20080524153630.669797039@gmail.com>
                   ` (8 preceding siblings ...)
  2008-05-24 15:36 ` [patch 09/11] x86: nmi_32.c cleanup - use for_each_online_cpu helper Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  2008-05-24 15:36 ` [patch 11/11] x86: nmi_32/64.c - merge down nmi_32.c and nmi_64.c to nmi.c Cyrill Gorcunov
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-add-helpers --]
[-- Type: text/plain, Size: 5282 bytes --]

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 13:20:13.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_32.c	2008-05-24 14:14:51.000000000 +0400
@@ -51,6 +51,26 @@ static DEFINE_PER_CPU(short, wd_enabled)
 
 static int endflag __initdata = 0;
 
+static inline unsigned int get_nmi_count(int cpu)
+{
+	return nmi_count(cpu);
+}
+
+static inline int mce_in_progress(void)
+{
+	return 0;
+}
+
+/*
+ * Take the local apic timer and PIT/HPET into account. We don't
+ * know which one is active, when we have highres/dyntick on
+ */
+static inline unsigned int get_timer_irqs(int cpu)
+{
+	return per_cpu(irq_stat, cpu).apic_timer_irqs +
+		per_cpu(irq_stat, cpu).irq0_irqs;
+}
+
 /* Run after command line and cpu_init init, but before all other checks */
 void nmi_watchdog_default(void)
 {
@@ -104,19 +124,19 @@ int __init check_nmi_watchdog(void)
 #endif
 
 	for_each_possible_cpu(cpu)
-		prev_nmi_count[cpu] = nmi_count(cpu);
+		prev_nmi_count[cpu] = get_nmi_count(cpu);
 	local_irq_enable();
 	mdelay((20*1000)/nmi_hz); // wait 20 ticks
 
 	for_each_online_cpu(cpu) {
 		if (!per_cpu(wd_enabled, cpu))
 			continue;
-		if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
+		if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
 			printk(KERN_WARNING "WARNING: CPU#%d: NMI "
 				"appears to be stuck (%d->%d)!\n",
 				cpu,
 				prev_nmi_count[cpu],
-				nmi_count(cpu));
+				get_nmi_count(cpu));
 			per_cpu(wd_enabled, cpu) = 0;
 			atomic_dec(&nmi_active);
 		}
@@ -355,6 +375,13 @@ nmi_watchdog_tick(struct pt_regs *regs, 
 		touched = 1;
 	}
 
+	sum = get_timer_irqs(cpu);
+
+	if (__get_cpu_var(nmi_touch)) {
+		__get_cpu_var(nmi_touch) = 0;
+		touched = 1;
+	}
+
 	if (cpu_isset(cpu, backtrace_mask)) {
 		static DEFINE_SPINLOCK(lock);	/* Serialise the printks */
 
@@ -365,16 +392,9 @@ nmi_watchdog_tick(struct pt_regs *regs, 
 		cpu_clear(cpu, backtrace_mask);
 	}
 
-	/*
-	 * Take the local apic timer and PIT/HPET into account. We don't
-	 * know which one is active, when we have highres/dyntick on
-	 */
-	sum = per_cpu(irq_stat, cpu).apic_timer_irqs +
-		per_cpu(irq_stat, cpu).irq0_irqs;
-	if (__get_cpu_var(nmi_touch)) {
-		__get_cpu_var(nmi_touch) = 0;
+	/* Could check oops_in_progress here too, but it's safer not to */
+	if (mce_in_progress())
 		touched = 1;
-	}
 
 	/* if the none of the timers isn't firing, this cpu isn't doing much */
 	if (!touched && __get_cpu_var(last_irq_sum) == sum) {
Index: linux-2.6.git/arch/x86/kernel/nmi_64.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_64.c	2008-05-24 13:19:23.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_64.c	2008-05-24 14:13:08.000000000 +0400
@@ -47,6 +47,30 @@ static unsigned int nmi_hz = HZ;
 
 static DEFINE_PER_CPU(short, wd_enabled);
 
+static int endflag __initdata = 0;
+
+static inline unsigned int get_nmi_count(int cpu)
+{
+	return cpu_pda(cpu)->__nmi_count;
+}
+
+static inline int mce_in_progress(void)
+{
+#ifdef CONFIG_X86_MCE
+	return atomic_read(&mce_entry) > 0;
+#endif
+	return 0;
+}
+
+/*
+ * Take the local apic timer and PIT/HPET into account. We don't
+ * know which one is active, when we have highres/dyntick on
+ */
+static inline unsigned int get_timer_irqs(int cpu)
+{
+	return read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
+}
+
 /* Run after command line and cpu_init init, but before all other checks */
 void nmi_watchdog_default(void)
 {
@@ -55,8 +79,6 @@ void nmi_watchdog_default(void)
 	nmi_watchdog = NMI_NONE;
 }
 
-static int endflag __initdata = 0;
-
 #ifdef CONFIG_SMP
 /* The performance counters used by NMI_LOCAL_APIC don't trigger when
  * the CPU is idle. To make sure the NMI watchdog really ticks on all
@@ -99,19 +121,19 @@ int __init check_nmi_watchdog(void)
 #endif
 
 	for_each_possible_cpu(cpu)
-		prev_nmi_count[cpu] = cpu_pda(cpu)->__nmi_count;
+		prev_nmi_count[cpu] = get_nmi_count(cpu);
 	local_irq_enable();
 	mdelay((20*1000)/nmi_hz); // wait 20 ticks
 
 	for_each_online_cpu(cpu) {
 		if (!per_cpu(wd_enabled, cpu))
 			continue;
-		if (cpu_pda(cpu)->__nmi_count - prev_nmi_count[cpu] <= 5) {
+		if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
 			printk(KERN_WARNING "WARNING: CPU#%d: NMI "
 			       "appears to be stuck (%d->%d)!\n",
 				cpu,
 				prev_nmi_count[cpu],
-				cpu_pda(cpu)->__nmi_count);
+				get_nmi_count(cpu));
 			per_cpu(wd_enabled, cpu) = 0;
 			atomic_dec(&nmi_active);
 		}
@@ -327,7 +349,8 @@ nmi_watchdog_tick(struct pt_regs *regs, 
 		touched = 1;
 	}
 
-	sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
+	sum = get_timer_irqs(cpu);
+
 	if (__get_cpu_var(nmi_touch)) {
 		__get_cpu_var(nmi_touch) = 0;
 		touched = 1;
@@ -343,12 +366,9 @@ nmi_watchdog_tick(struct pt_regs *regs, 
 		cpu_clear(cpu, backtrace_mask);
 	}
 
-#ifdef CONFIG_X86_MCE
-	/* Could check oops_in_progress here too, but it's safer
-	   not too */
-	if (atomic_read(&mce_entry) > 0)
+	if (mce_in_progress())
 		touched = 1;
-#endif
+
 	/* if the apic timer isn't firing, this cpu isn't doing much */
 	if (!touched && __get_cpu_var(last_irq_sum) == sum) {
 		/*

-- 

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

* [patch 11/11] x86: nmi_32/64.c - merge down nmi_32.c and nmi_64.c to nmi.c
       [not found] <20080524153630.669797039@gmail.com>
                   ` (9 preceding siblings ...)
  2008-05-24 15:36 ` [patch 10/11] x86: nmi_32/64.c - add helper functions to hide mode-specific data Cyrill Gorcunov
@ 2008-05-24 15:36 ` Cyrill Gorcunov
  10 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-24 15:36 UTC (permalink / raw)
  To: hpa, tglx, mingo, linux-kernel; +Cc: Cyrill Gorcunov

[-- Attachment #1: nmi-32-64-merge --]
[-- Type: text/plain, Size: 38611 bytes --]

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi.c
====================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.git/arch/x86/kernel/nmi.c	2008-05-24 17:23:04.000000000 +0400
@@ -0,0 +1,532 @@
+/*
+ *  NMI watchdog support on APIC systems
+ *
+ *  Started by Ingo Molnar <mingo@redhat.com>
+ *
+ *  Fixes:
+ *  Mikael Pettersson	: AMD K7 support for local APIC NMI watchdog.
+ *  Mikael Pettersson	: Power Management for local APIC NMI watchdog.
+ *  Mikael Pettersson	: Pentium 4 support for local APIC NMI watchdog.
+ *  Pavel Machek and
+ *  Mikael Pettersson	: PM converted to driver model. Disable/enable API.
+ */
+
+#include <linux/nmi.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/sysctl.h>
+#include <linux/percpu.h>
+#include <linux/kprobes.h>
+#include <linux/cpumask.h>
+#include <linux/kernel_stat.h>
+#include <linux/kdebug.h>
+
+#include <asm/smp.h>
+#include <asm/nmi.h>
+#include <asm/proto.h>
+#include <asm/timer.h>
+
+#include <asm/mce.h>
+
+#include <mach_traps.h>
+
+int unknown_nmi_panic;
+int nmi_watchdog_enabled;
+
+static cpumask_t backtrace_mask = CPU_MASK_NONE;
+
+/* nmi_active:
+ * >0: the lapic NMI watchdog is active, but can be disabled
+ * <0: the lapic NMI watchdog has not been set up, and cannot
+ *     be enabled
+ *  0: the lapic NMI watchdog is disabled, but can be enabled
+ */
+atomic_t nmi_active = ATOMIC_INIT(0);		/* oprofile uses this */
+static int panic_on_timeout;
+
+unsigned int nmi_watchdog = NMI_DEFAULT;
+
+static unsigned int nmi_hz = HZ;
+static DEFINE_PER_CPU(short, wd_enabled);
+static int endflag __initdata = 0;
+
+static inline unsigned int get_nmi_count(int cpu)
+{
+#ifdef CONFIG_X86_64
+	return cpu_pda(cpu)->__nmi_count;
+#else
+	return nmi_count(cpu);
+#endif
+}
+
+static inline int mce_in_progress(void)
+{
+#if defined(CONFIX_X86_64) && defined(CONFIG_X86_MCE)
+	return atomic_read(&mce_entry) > 0;
+#endif
+	return 0;
+}
+
+/*
+ * Take the local apic timer and PIT/HPET into account. We don't
+ * know which one is active, when we have highres/dyntick on
+ */
+static inline unsigned int get_timer_irqs(int cpu)
+{
+#ifdef CONFIG_X86_64
+	return read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
+#else
+	return per_cpu(irq_stat, cpu).apic_timer_irqs +
+		per_cpu(irq_stat, cpu).irq0_irqs;
+#endif
+}
+
+/* Run after command line and cpu_init init, but before all other checks */
+void nmi_watchdog_default(void)
+{
+	if (nmi_watchdog != NMI_DEFAULT)
+		return;
+#ifdef CONFIG_X86_64
+	nmi_watchdog = NMI_NONE;
+#else
+	if (lapic_watchdog_ok())
+		nmi_watchdog = NMI_LOCAL_APIC;
+	else
+		nmi_watchdog = NMI_IO_APIC;
+#endif
+}
+
+#ifdef CONFIG_SMP
+/*
+ * The performance counters used by NMI_LOCAL_APIC don't trigger when
+ * the CPU is idle. To make sure the NMI watchdog really ticks on all
+ * CPUs during the test make them busy.
+ */
+static __init void nmi_cpu_busy(void *data)
+{
+	local_irq_enable_in_hardirq();
+	/*
+	 * Intentionally don't use cpu_relax here. This is
+	 * to make sure that the performance counter really ticks,
+	 * even if there is a simulator or similar that catches the
+	 * pause instruction. On a real HT machine this is fine because
+	 * all other CPUs are busy with "useless" delay loops and don't
+	 * care if they get somewhat less cycles.
+	 */
+	while (endflag == 0)
+		mb();
+}
+#endif
+
+int __init check_nmi_watchdog(void)
+{
+	unsigned int *prev_nmi_count;
+	int cpu;
+
+	if (nmi_watchdog == NMI_NONE || nmi_watchdog == NMI_DISABLED)
+		return 0;
+
+	if (!atomic_read(&nmi_active))
+		return 0;
+
+	prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
+	if (!prev_nmi_count)
+		goto error;
+
+	printk(KERN_INFO "Testing NMI watchdog ... ");
+
+#ifdef CONFIG_SMP
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
+#endif
+
+	for_each_possible_cpu(cpu)
+		prev_nmi_count[cpu] = get_nmi_count(cpu);
+	local_irq_enable();
+	mdelay((20 * 1000) / nmi_hz); /* wait 20 ticks */
+
+	for_each_online_cpu(cpu) {
+		if (!per_cpu(wd_enabled, cpu))
+			continue;
+		if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
+			printk(KERN_WARNING "WARNING: CPU#%d: NMI "
+				"appears to be stuck (%d->%d)!\n",
+				cpu,
+				prev_nmi_count[cpu],
+				get_nmi_count(cpu));
+			per_cpu(wd_enabled, cpu) = 0;
+			atomic_dec(&nmi_active);
+		}
+	}
+	endflag = 1;
+	if (!atomic_read(&nmi_active)) {
+		kfree(prev_nmi_count);
+		atomic_set(&nmi_active, -1);
+		goto error;
+	}
+	printk("OK.\n");
+
+	/*
+	 * now that we know it works we can reduce NMI frequency to
+	 * something more reasonable; makes a difference in some configs
+	 */
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		nmi_hz = lapic_adjust_nmi_hz(1);
+
+	kfree(prev_nmi_count);
+	return 0;
+
+error:
+#ifdef CONFIG_X86_32
+	timer_ack = !cpu_has_tsc;
+#endif
+	return -1;
+}
+
+static int __init setup_nmi_watchdog(char *str)
+{
+	int nmi;
+
+	if (!strncmp(str, "panic", 5)) {
+		panic_on_timeout = 1;
+		str = strchr(str, ',');
+		if (!str)
+			return 1;
+		++str;
+	}
+
+	get_option(&str, &nmi);
+
+	if (nmi >= NMI_INVALID || nmi < NMI_NONE)
+		return 0;
+
+	nmi_watchdog = nmi;
+	return 1;
+}
+__setup("nmi_watchdog=", setup_nmi_watchdog);
+
+/*
+ * Suspend/resume support
+ */
+#ifdef CONFIG_PM
+
+static int nmi_pm_active; /* nmi_active before suspend */
+
+static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
+{
+	/* only CPU0 goes here, other CPUs should be offline */
+	nmi_pm_active = atomic_read(&nmi_active);
+	stop_apic_nmi_watchdog(NULL);
+	BUG_ON(atomic_read(&nmi_active) != 0);
+	return 0;
+}
+
+static int lapic_nmi_resume(struct sys_device *dev)
+{
+	/* only CPU0 goes here, other CPUs should be offline */
+	if (nmi_pm_active > 0) {
+		setup_apic_nmi_watchdog(NULL);
+		touch_nmi_watchdog();
+	}
+	return 0;
+}
+
+static struct sysdev_class nmi_sysclass = {
+	.name		= "lapic_nmi",
+	.resume		= lapic_nmi_resume,
+	.suspend	= lapic_nmi_suspend,
+};
+
+static struct sys_device device_lapic_nmi = {
+	.id	= 0,
+	.cls	= &nmi_sysclass,
+};
+
+static int __init init_lapic_nmi_sysfs(void)
+{
+	int error;
+
+	/*
+	 * should really be a BUG_ON but b/c this is an
+	 * init call, it just doesn't work.  -dcz
+	 */
+	if (nmi_watchdog != NMI_LOCAL_APIC)
+		return 0;
+
+	if (atomic_read(&nmi_active) < 0)
+		return 0;
+
+	error = sysdev_class_register(&nmi_sysclass);
+	if (!error)
+		error = sysdev_register(&device_lapic_nmi);
+	return error;
+}
+
+/* must come after the local APIC's device_initcall() */
+late_initcall(init_lapic_nmi_sysfs);
+
+#endif	/* CONFIG_PM */
+
+static void __acpi_nmi_enable(void *__unused)
+{
+	apic_write_around(APIC_LVT0, APIC_DM_NMI);
+}
+
+/*
+ * Enable timer based NMIs on all CPUs:
+ */
+void acpi_nmi_enable(void)
+{
+	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
+		on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
+}
+
+static void __acpi_nmi_disable(void *__unused)
+{
+	apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
+}
+
+/*
+ * Disable timer based NMIs on all CPUs:
+ */
+void acpi_nmi_disable(void)
+{
+	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
+		on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
+}
+
+void setup_apic_nmi_watchdog(void *unused)
+{
+	if (__get_cpu_var(wd_enabled))
+		return;
+
+	/* cheap hack to support suspend/resume */
+	/* if cpu0 is not active neither should the other cpus */
+	if (smp_processor_id() != 0 && atomic_read(&nmi_active) <= 0)
+		return;
+
+	switch (nmi_watchdog) {
+	case NMI_LOCAL_APIC:
+		__get_cpu_var(wd_enabled) = 1; /* enable it before to avoid race with handler */
+		if (lapic_watchdog_init(nmi_hz) < 0) {
+			__get_cpu_var(wd_enabled) = 0;
+			return;
+		}
+		/* FALL THROUGH */
+	case NMI_IO_APIC:
+		__get_cpu_var(wd_enabled) = 1;
+		atomic_inc(&nmi_active);
+	}
+}
+
+void stop_apic_nmi_watchdog(void *unused)
+{
+	/* only support LOCAL and IO APICs for now */
+	if (nmi_watchdog != NMI_LOCAL_APIC &&
+	    nmi_watchdog != NMI_IO_APIC)
+	    	return;
+	if (__get_cpu_var(wd_enabled) == 0)
+		return;
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		lapic_watchdog_stop();
+	__get_cpu_var(wd_enabled) = 0;
+	atomic_dec(&nmi_active);
+}
+
+/*
+ * the best way to detect whether a CPU has a 'hard lockup' problem
+ * is to check it's local APIC timer IRQ counts. If they are not
+ * changing then that CPU has some problem.
+ *
+ * as these watchdog NMI IRQs are generated on every CPU, we only
+ * have to check the current processor.
+ *
+ * since NMIs don't listen to _any_ locks, we have to be extremely
+ * careful not to rely on unsafe variables. The printk might lock
+ * up though, so we have to break up any console locks first ...
+ * [when there will be more tty-related locks, break them up here too!]
+ */
+
+static DEFINE_PER_CPU(unsigned, last_irq_sum);
+static DEFINE_PER_CPU(local_t, alert_counter);
+static DEFINE_PER_CPU(int, nmi_touch);
+
+void touch_nmi_watchdog(void)
+{
+	if (nmi_watchdog > 0) {
+		unsigned cpu;
+
+		/*
+		 * Tell other CPUs to reset their alert counters. We cannot
+		 * do it ourselves because the alert count increase is not
+		 * atomic.
+		 */
+		for_each_present_cpu(cpu) {
+			if (per_cpu(nmi_touch, cpu) != 1)
+				per_cpu(nmi_touch, cpu) = 1;
+		}
+	}
+
+	/*
+	 * Tickle the softlockup detector too:
+	 */
+	touch_softlockup_watchdog();
+}
+EXPORT_SYMBOL(touch_nmi_watchdog);
+
+notrace __kprobes int
+nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
+{
+	/*
+	 * Since current_thread_info()-> is always on the stack, and we
+	 * always switch the stack NMI-atomically, it's safe to use
+	 * smp_processor_id().
+	 */
+	unsigned int sum;
+	int touched = 0;
+	int cpu = smp_processor_id();
+	int rc = 0;
+
+	/* check for other users first */
+	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
+			== NOTIFY_STOP) {
+		rc = 1;
+		touched = 1;
+	}
+
+	sum = get_timer_irqs(cpu);
+
+	if (__get_cpu_var(nmi_touch)) {
+		__get_cpu_var(nmi_touch) = 0;
+		touched = 1;
+	}
+
+	if (cpu_isset(cpu, backtrace_mask)) {
+		static DEFINE_SPINLOCK(lock);	/* Serialise the printks */
+
+		spin_lock(&lock);
+		printk("NMI backtrace for cpu %d\n", cpu);
+		dump_stack();
+		spin_unlock(&lock);
+		cpu_clear(cpu, backtrace_mask);
+	}
+
+	/* Could check oops_in_progress here too, but it's safer not to */
+	if (mce_in_progress())
+		touched = 1;
+
+	/* if the none of the timers isn't firing, this cpu isn't doing much */
+	if (!touched && __get_cpu_var(last_irq_sum) == sum) {
+		/*
+		 * Ayiee, looks like this CPU is stuck ...
+		 * wait a few IRQs (5 seconds) before doing the oops ...
+		 */
+		local_inc(&__get_cpu_var(alert_counter));
+		if (local_read(&__get_cpu_var(alert_counter)) == 5 * nmi_hz)
+			/*
+			 * die_nmi will return ONLY if NOTIFY_STOP happens..
+			 */
+			die_nmi("BUG: NMI Watchdog detected LOCKUP",
+				regs, panic_on_timeout);
+	} else {
+		__get_cpu_var(last_irq_sum) = sum;
+		local_set(&__get_cpu_var(alert_counter), 0);
+	}
+
+	/* see if the nmi watchdog went off */
+	if (!__get_cpu_var(wd_enabled))
+		return rc;
+	switch (nmi_watchdog) {
+	case NMI_LOCAL_APIC:
+		rc |= lapic_wd_event(nmi_hz);
+		break;
+	case NMI_IO_APIC:
+		/*
+		 * don't know how to accurately check for this.
+		 * just assume it was a watchdog timer interrupt
+		 * This matches the old behaviour.
+		 */
+		rc = 1;
+		break;
+	}
+	return rc;
+}
+
+#ifdef CONFIG_SYSCTL
+
+static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
+{
+	unsigned char reason = get_nmi_reason();
+	char buf[64];
+
+	sprintf(buf, "NMI received for unknown reason %02x\n", reason);
+	die_nmi(buf, regs, 1); /* Always panic here */
+	return 0;
+}
+
+/*
+ * proc handler for /proc/sys/kernel/nmi
+ */
+int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
+			void __user *buffer, size_t *length, loff_t *ppos)
+{
+	int old_state;
+
+	nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
+	old_state = nmi_watchdog_enabled;
+	proc_dointvec(table, write, file, buffer, length, ppos);
+	if (!!old_state == !!nmi_watchdog_enabled)
+		return 0;
+
+	if (atomic_read(&nmi_active) < 0 || nmi_watchdog == NMI_DISABLED) {
+		printk(KERN_WARNING
+			"NMI watchdog is permanently disabled\n");
+		return -EIO;
+	}
+
+	/* if nmi_watchdog is not set yet, then set it */
+	nmi_watchdog_default();
+
+	if (nmi_watchdog == NMI_LOCAL_APIC) {
+		if (nmi_watchdog_enabled)
+			enable_lapic_nmi_watchdog();
+		else
+			disable_lapic_nmi_watchdog();
+	} else {
+		printk(KERN_WARNING
+			"NMI watchdog doesn't know what hardware to touch\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+#endif /* CONFIG_SYSCTL */
+
+int do_nmi_callback(struct pt_regs *regs, int cpu)
+{
+#ifdef CONFIG_SYSCTL
+	if (unknown_nmi_panic)
+		return unknown_nmi_panic_callback(regs, cpu);
+#endif
+	return 0;
+}
+
+void __trigger_all_cpu_backtrace(void)
+{
+	int i;
+
+	backtrace_mask = cpu_online_map;
+	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
+	for (i = 0; i < 10 * 1000; i++) {
+		if (cpus_empty(backtrace_mask))
+			break;
+		mdelay(1);
+	}
+}
+
+EXPORT_SYMBOL(nmi_active);
+EXPORT_SYMBOL(nmi_watchdog);
+
Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 14:15:53.000000000 +0400
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,506 +0,0 @@
-/*
- *  NMI watchdog support on APIC systems
- *
- *  Started by Ingo Molnar <mingo@redhat.com>
- *
- *  Fixes:
- *  Mikael Pettersson	: AMD K7 support for local APIC NMI watchdog.
- *  Mikael Pettersson	: Power Management for local APIC NMI watchdog.
- *  Mikael Pettersson	: Pentium 4 support for local APIC NMI watchdog.
- *  Pavel Machek and
- *  Mikael Pettersson	: PM converted to driver model. Disable/enable API.
- */
-
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/nmi.h>
-#include <linux/sysdev.h>
-#include <linux/sysctl.h>
-#include <linux/percpu.h>
-#include <linux/kprobes.h>
-#include <linux/cpumask.h>
-#include <linux/kernel_stat.h>
-#include <linux/kdebug.h>
-#include <linux/slab.h>
-
-#include <asm/smp.h>
-#include <asm/nmi.h>
-#include <asm/timer.h>
-
-#include "mach_traps.h"
-
-int unknown_nmi_panic;
-int nmi_watchdog_enabled;
-
-static cpumask_t backtrace_mask = CPU_MASK_NONE;
-
-/* nmi_active:
- * >0: the lapic NMI watchdog is active, but can be disabled
- * <0: the lapic NMI watchdog has not been set up, and cannot
- *     be enabled
- *  0: the lapic NMI watchdog is disabled, but can be enabled
- */
-atomic_t nmi_active = ATOMIC_INIT(0);		/* oprofile uses this */
-static int panic_on_timeout;
-
-unsigned int nmi_watchdog = NMI_DEFAULT;
-static unsigned int nmi_hz = HZ;
-
-static DEFINE_PER_CPU(short, wd_enabled);
-
-static int endflag __initdata = 0;
-
-static inline unsigned int get_nmi_count(int cpu)
-{
-	return nmi_count(cpu);
-}
-
-static inline int mce_in_progress(void)
-{
-	return 0;
-}
-
-/*
- * Take the local apic timer and PIT/HPET into account. We don't
- * know which one is active, when we have highres/dyntick on
- */
-static inline unsigned int get_timer_irqs(int cpu)
-{
-	return per_cpu(irq_stat, cpu).apic_timer_irqs +
-		per_cpu(irq_stat, cpu).irq0_irqs;
-}
-
-/* Run after command line and cpu_init init, but before all other checks */
-void nmi_watchdog_default(void)
-{
-	if (nmi_watchdog != NMI_DEFAULT)
-		return;
-	if (lapic_watchdog_ok())
-		nmi_watchdog = NMI_LOCAL_APIC;
-	else
-		nmi_watchdog = NMI_IO_APIC;
-}
-
-#ifdef CONFIG_SMP
-/* The performance counters used by NMI_LOCAL_APIC don't trigger when
- * the CPU is idle. To make sure the NMI watchdog really ticks on all
- * CPUs during the test make them busy.
- */
-static __init void nmi_cpu_busy(void *data)
-{
-	local_irq_enable_in_hardirq();
-	/* Intentionally don't use cpu_relax here. This is
-	   to make sure that the performance counter really ticks,
-	   even if there is a simulator or similar that catches the
-	   pause instruction. On a real HT machine this is fine because
-	   all other CPUs are busy with "useless" delay loops and don't
-	   care if they get somewhat less cycles. */
-	while (endflag == 0)
-		mb();
-}
-#endif
-
-int __init check_nmi_watchdog(void)
-{
-	unsigned int *prev_nmi_count;
-	int cpu;
-
-	if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DISABLED))
-		return 0;
-
-	if (!atomic_read(&nmi_active))
-		return 0;
-
-	prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
-	if (!prev_nmi_count)
-		goto error;
-
-	printk(KERN_INFO "Testing NMI watchdog ... ");
-
-#ifdef CONFIG_SMP
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
-#endif
-
-	for_each_possible_cpu(cpu)
-		prev_nmi_count[cpu] = get_nmi_count(cpu);
-	local_irq_enable();
-	mdelay((20*1000)/nmi_hz); // wait 20 ticks
-
-	for_each_online_cpu(cpu) {
-		if (!per_cpu(wd_enabled, cpu))
-			continue;
-		if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
-			printk(KERN_WARNING "WARNING: CPU#%d: NMI "
-				"appears to be stuck (%d->%d)!\n",
-				cpu,
-				prev_nmi_count[cpu],
-				get_nmi_count(cpu));
-			per_cpu(wd_enabled, cpu) = 0;
-			atomic_dec(&nmi_active);
-		}
-	}
-	endflag = 1;
-	if (!atomic_read(&nmi_active)) {
-		kfree(prev_nmi_count);
-		atomic_set(&nmi_active, -1);
-		goto error;
-	}
-	printk("OK.\n");
-
-	/* now that we know it works we can reduce NMI frequency to
-	   something more reasonable; makes a difference in some configs */
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		nmi_hz = lapic_adjust_nmi_hz(1);
-
-	kfree(prev_nmi_count);
-	return 0;
-error:
-	timer_ack = !cpu_has_tsc;
-
-	return -1;
-}
-
-static int __init setup_nmi_watchdog(char *str)
-{
-	int nmi;
-
-	if (!strncmp(str, "panic", 5)) {
-		panic_on_timeout = 1;
-		str = strchr(str, ',');
-		if (!str)
-			return 1;
-		++str;
-	}
-
-	get_option(&str, &nmi);
-
-	if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
-		return 0;
-
-	nmi_watchdog = nmi;
-	return 1;
-}
-
-__setup("nmi_watchdog=", setup_nmi_watchdog);
-
-
-/* Suspend/resume support */
-
-#ifdef CONFIG_PM
-
-static int nmi_pm_active; /* nmi_active before suspend */
-
-static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
-{
-	/* only CPU0 goes here, other CPUs should be offline */
-	nmi_pm_active = atomic_read(&nmi_active);
-	stop_apic_nmi_watchdog(NULL);
-	BUG_ON(atomic_read(&nmi_active) != 0);
-	return 0;
-}
-
-static int lapic_nmi_resume(struct sys_device *dev)
-{
-	/* only CPU0 goes here, other CPUs should be offline */
-	if (nmi_pm_active > 0) {
-		setup_apic_nmi_watchdog(NULL);
-		touch_nmi_watchdog();
-	}
-	return 0;
-}
-
-
-static struct sysdev_class nmi_sysclass = {
-	.name		= "lapic_nmi",
-	.resume		= lapic_nmi_resume,
-	.suspend	= lapic_nmi_suspend,
-};
-
-static struct sys_device device_lapic_nmi = {
-	.id	= 0,
-	.cls	= &nmi_sysclass,
-};
-
-static int __init init_lapic_nmi_sysfs(void)
-{
-	int error;
-
-	/* should really be a BUG_ON but b/c this is an
-	 * init call, it just doesn't work.  -dcz
-	 */
-	if (nmi_watchdog != NMI_LOCAL_APIC)
-		return 0;
-
-	if (atomic_read(&nmi_active) < 0)
-		return 0;
-
-	error = sysdev_class_register(&nmi_sysclass);
-	if (!error)
-		error = sysdev_register(&device_lapic_nmi);
-	return error;
-}
-/* must come after the local APIC's device_initcall() */
-late_initcall(init_lapic_nmi_sysfs);
-
-#endif	/* CONFIG_PM */
-
-static void __acpi_nmi_enable(void *__unused)
-{
-	apic_write_around(APIC_LVT0, APIC_DM_NMI);
-}
-
-/*
- * Enable timer based NMIs on all CPUs:
- */
-void acpi_nmi_enable(void)
-{
-	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
-		on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
-}
-
-static void __acpi_nmi_disable(void *__unused)
-{
-	apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
-}
-
-/*
- * Disable timer based NMIs on all CPUs:
- */
-void acpi_nmi_disable(void)
-{
-	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
-		on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
-}
-
-void setup_apic_nmi_watchdog(void *unused)
-{
-	if (__get_cpu_var(wd_enabled))
-		return;
-
-	/* cheap hack to support suspend/resume */
-	/* if cpu0 is not active neither should the other cpus */
-	if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0))
-		return;
-
-	switch (nmi_watchdog) {
-	case NMI_LOCAL_APIC:
-		__get_cpu_var(wd_enabled) = 1; /* enable it before to avoid race with handler */
-		if (lapic_watchdog_init(nmi_hz) < 0) {
-			__get_cpu_var(wd_enabled) = 0;
-			return;
-		}
-		/* FALL THROUGH */
-	case NMI_IO_APIC:
-		__get_cpu_var(wd_enabled) = 1;
-		atomic_inc(&nmi_active);
-	}
-}
-
-void stop_apic_nmi_watchdog(void *unused)
-{
-	/* only support LOCAL and IO APICs for now */
-	if ((nmi_watchdog != NMI_LOCAL_APIC) &&
-	    (nmi_watchdog != NMI_IO_APIC))
-	    	return;
-	if (__get_cpu_var(wd_enabled) == 0)
-		return;
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		lapic_watchdog_stop();
-	__get_cpu_var(wd_enabled) = 0;
-	atomic_dec(&nmi_active);
-}
-
-/*
- * the best way to detect whether a CPU has a 'hard lockup' problem
- * is to check it's local APIC timer IRQ counts. If they are not
- * changing then that CPU has some problem.
- *
- * as these watchdog NMI IRQs are generated on every CPU, we only
- * have to check the current processor.
- *
- * since NMIs don't listen to _any_ locks, we have to be extremely
- * careful not to rely on unsafe variables. The printk might lock
- * up though, so we have to break up any console locks first ...
- * [when there will be more tty-related locks, break them up
- *  here too!]
- */
-
-static DEFINE_PER_CPU(unsigned, last_irq_sum);
-static DEFINE_PER_CPU(local_t, alert_counter);
-static DEFINE_PER_CPU(int, nmi_touch);
-
-void touch_nmi_watchdog(void)
-{
-	if (nmi_watchdog > 0) {
-		unsigned cpu;
-
-		/*
-		 * Tell other CPUs to reset their alert counters. We cannot
-		 * do it ourselves because the alert count increase is not
-		 * atomic.
-		 */
-		for_each_present_cpu(cpu) {
-			if (per_cpu(nmi_touch, cpu) != 1)
-				per_cpu(nmi_touch, cpu) = 1;
-		}
-	}
-
-	/*
-	 * Tickle the softlockup detector too:
-	 */
-	touch_softlockup_watchdog();
-}
-EXPORT_SYMBOL(touch_nmi_watchdog);
-
-notrace __kprobes int
-nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
-{
-
-	/*
-	 * Since current_thread_info()-> is always on the stack, and we
-	 * always switch the stack NMI-atomically, it's safe to use
-	 * smp_processor_id().
-	 */
-	unsigned int sum;
-	int touched = 0;
-	int cpu = smp_processor_id();
-	int rc = 0;
-
-	/* check for other users first */
-	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
-			== NOTIFY_STOP) {
-		rc = 1;
-		touched = 1;
-	}
-
-	sum = get_timer_irqs(cpu);
-
-	if (__get_cpu_var(nmi_touch)) {
-		__get_cpu_var(nmi_touch) = 0;
-		touched = 1;
-	}
-
-	if (cpu_isset(cpu, backtrace_mask)) {
-		static DEFINE_SPINLOCK(lock);	/* Serialise the printks */
-
-		spin_lock(&lock);
-		printk("NMI backtrace for cpu %d\n", cpu);
-		dump_stack();
-		spin_unlock(&lock);
-		cpu_clear(cpu, backtrace_mask);
-	}
-
-	/* Could check oops_in_progress here too, but it's safer not to */
-	if (mce_in_progress())
-		touched = 1;
-
-	/* if the none of the timers isn't firing, this cpu isn't doing much */
-	if (!touched && __get_cpu_var(last_irq_sum) == sum) {
-		/*
-		 * Ayiee, looks like this CPU is stuck ...
-		 * wait a few IRQs (5 seconds) before doing the oops ...
-		 */
-		local_inc(&__get_cpu_var(alert_counter));
-		if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz)
-			/*
-			 * die_nmi will return ONLY if NOTIFY_STOP happens..
-			 */
-			die_nmi("BUG: NMI Watchdog detected LOCKUP",
-				regs, panic_on_timeout);
-	} else {
-		__get_cpu_var(last_irq_sum) = sum;
-		local_set(&__get_cpu_var(alert_counter), 0);
-	}
-	/* see if the nmi watchdog went off */
-	if (!__get_cpu_var(wd_enabled))
-		return rc;
-	switch (nmi_watchdog) {
-	case NMI_LOCAL_APIC:
-		rc |= lapic_wd_event(nmi_hz);
-		break;
-	case NMI_IO_APIC:
-		/* don't know how to accurately check for this.
-		 * just assume it was a watchdog timer interrupt
-		 * This matches the old behaviour.
-		 */
-		rc = 1;
-		break;
-	}
-	return rc;
-}
-
-#ifdef CONFIG_SYSCTL
-
-static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
-{
-	unsigned char reason = get_nmi_reason();
-	char buf[64];
-
-	sprintf(buf, "NMI received for unknown reason %02x\n", reason);
-	die_nmi(buf, regs, 1); /* Always panic here */
-	return 0;
-}
-
-/*
- * proc handler for /proc/sys/kernel/nmi
- */
-int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
-			void __user *buffer, size_t *length, loff_t *ppos)
-{
-	int old_state;
-
-	nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
-	old_state = nmi_watchdog_enabled;
-	proc_dointvec(table, write, file, buffer, length, ppos);
-	if (!!old_state == !!nmi_watchdog_enabled)
-		return 0;
-
-	if (atomic_read(&nmi_active) < 0 || nmi_watchdog == NMI_DISABLED) {
-		printk( KERN_WARNING "NMI watchdog is permanently disabled\n");
-		return -EIO;
-	}
-
-	/* if nmi_watchdog is not set yet, then set it */
-	nmi_watchdog_default();
-
-	if (nmi_watchdog == NMI_LOCAL_APIC) {
-		if (nmi_watchdog_enabled)
-			enable_lapic_nmi_watchdog();
-		else
-			disable_lapic_nmi_watchdog();
-	} else {
-		printk( KERN_WARNING
-			"NMI watchdog doesn't know what hardware to touch\n");
-		return -EIO;
-	}
-	return 0;
-}
-
-#endif
-
-int do_nmi_callback(struct pt_regs *regs, int cpu)
-{
-#ifdef CONFIG_SYSCTL
-	if (unknown_nmi_panic)
-		return unknown_nmi_panic_callback(regs, cpu);
-#endif
-	return 0;
-}
-
-void __trigger_all_cpu_backtrace(void)
-{
-	int i;
-
-	backtrace_mask = cpu_online_map;
-	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
-	for (i = 0; i < 10 * 1000; i++) {
-		if (cpus_empty(backtrace_mask))
-			break;
-		mdelay(1);
-	}
-}
-
-EXPORT_SYMBOL(nmi_active);
-EXPORT_SYMBOL(nmi_watchdog);
Index: linux-2.6.git/arch/x86/kernel/nmi_64.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_64.c	2008-05-24 14:13:08.000000000 +0400
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,477 +0,0 @@
-/*
- *  NMI watchdog support on APIC systems
- *
- *  Started by Ingo Molnar <mingo@redhat.com>
- *
- *  Fixes:
- *  Mikael Pettersson	: AMD K7 support for local APIC NMI watchdog.
- *  Mikael Pettersson	: Power Management for local APIC NMI watchdog.
- *  Pavel Machek and
- *  Mikael Pettersson	: PM converted to driver model. Disable/enable API.
- */
-
-#include <linux/nmi.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/sysdev.h>
-#include <linux/sysctl.h>
-#include <linux/kprobes.h>
-#include <linux/cpumask.h>
-#include <linux/kdebug.h>
-
-#include <asm/smp.h>
-#include <asm/nmi.h>
-#include <asm/proto.h>
-#include <asm/mce.h>
-
-#include <mach_traps.h>
-
-int unknown_nmi_panic;
-int nmi_watchdog_enabled;
-
-static cpumask_t backtrace_mask = CPU_MASK_NONE;
-
-/* nmi_active:
- * >0: the lapic NMI watchdog is active, but can be disabled
- * <0: the lapic NMI watchdog has not been set up, and cannot
- *     be enabled
- *  0: the lapic NMI watchdog is disabled, but can be enabled
- */
-atomic_t nmi_active = ATOMIC_INIT(0);		/* oprofile uses this */
-static int panic_on_timeout;
-
-unsigned int nmi_watchdog = NMI_DEFAULT;
-static unsigned int nmi_hz = HZ;
-
-static DEFINE_PER_CPU(short, wd_enabled);
-
-static int endflag __initdata = 0;
-
-static inline unsigned int get_nmi_count(int cpu)
-{
-	return cpu_pda(cpu)->__nmi_count;
-}
-
-static inline int mce_in_progress(void)
-{
-#ifdef CONFIG_X86_MCE
-	return atomic_read(&mce_entry) > 0;
-#endif
-	return 0;
-}
-
-/*
- * Take the local apic timer and PIT/HPET into account. We don't
- * know which one is active, when we have highres/dyntick on
- */
-static inline unsigned int get_timer_irqs(int cpu)
-{
-	return read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
-}
-
-/* Run after command line and cpu_init init, but before all other checks */
-void nmi_watchdog_default(void)
-{
-	if (nmi_watchdog != NMI_DEFAULT)
-		return;
-	nmi_watchdog = NMI_NONE;
-}
-
-#ifdef CONFIG_SMP
-/* The performance counters used by NMI_LOCAL_APIC don't trigger when
- * the CPU is idle. To make sure the NMI watchdog really ticks on all
- * CPUs during the test make them busy.
- */
-static __init void nmi_cpu_busy(void *data)
-{
-	local_irq_enable_in_hardirq();
-	/* Intentionally don't use cpu_relax here. This is
-	   to make sure that the performance counter really ticks,
-	   even if there is a simulator or similar that catches the
-	   pause instruction. On a real HT machine this is fine because
-	   all other CPUs are busy with "useless" delay loops and don't
-	   care if they get somewhat less cycles. */
-	while (endflag == 0)
-		mb();
-}
-#endif
-
-int __init check_nmi_watchdog(void)
-{
-	unsigned int *prev_nmi_count;
-	int cpu;
-
-	if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DISABLED))
-		return 0;
-
-	if (!atomic_read(&nmi_active))
-		return 0;
-
-	prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
-	if (!prev_nmi_count)
-		return -1;
-
-	printk(KERN_INFO "Testing NMI watchdog ... ");
-
-#ifdef CONFIG_SMP
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
-#endif
-
-	for_each_possible_cpu(cpu)
-		prev_nmi_count[cpu] = get_nmi_count(cpu);
-	local_irq_enable();
-	mdelay((20*1000)/nmi_hz); // wait 20 ticks
-
-	for_each_online_cpu(cpu) {
-		if (!per_cpu(wd_enabled, cpu))
-			continue;
-		if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
-			printk(KERN_WARNING "WARNING: CPU#%d: NMI "
-			       "appears to be stuck (%d->%d)!\n",
-				cpu,
-				prev_nmi_count[cpu],
-				get_nmi_count(cpu));
-			per_cpu(wd_enabled, cpu) = 0;
-			atomic_dec(&nmi_active);
-		}
-	}
-	endflag = 1;
-	if (!atomic_read(&nmi_active)) {
-		kfree(prev_nmi_count);
-		atomic_set(&nmi_active, -1);
-		return -1;
-	}
-	printk("OK.\n");
-
-	/* now that we know it works we can reduce NMI frequency to
-	   something more reasonable; makes a difference in some configs */
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		nmi_hz = lapic_adjust_nmi_hz(1);
-
-	kfree(prev_nmi_count);
-	return 0;
-}
-
-static int __init setup_nmi_watchdog(char *str)
-{
-	int nmi;
-
-	if (!strncmp(str,"panic",5)) {
-		panic_on_timeout = 1;
-		str = strchr(str, ',');
-		if (!str)
-			return 1;
-		++str;
-	}
-
-	get_option(&str, &nmi);
-
-	if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
-		return 0;
-
-	nmi_watchdog = nmi;
-	return 1;
-}
-
-__setup("nmi_watchdog=", setup_nmi_watchdog);
-
-#ifdef CONFIG_PM
-
-static int nmi_pm_active; /* nmi_active before suspend */
-
-static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
-{
-	/* only CPU0 goes here, other CPUs should be offline */
-	nmi_pm_active = atomic_read(&nmi_active);
-	stop_apic_nmi_watchdog(NULL);
-	BUG_ON(atomic_read(&nmi_active) != 0);
-	return 0;
-}
-
-static int lapic_nmi_resume(struct sys_device *dev)
-{
-	/* only CPU0 goes here, other CPUs should be offline */
-	if (nmi_pm_active > 0) {
-		setup_apic_nmi_watchdog(NULL);
-		touch_nmi_watchdog();
-	}
-	return 0;
-}
-
-static struct sysdev_class nmi_sysclass = {
-	.name		= "lapic_nmi",
-	.resume		= lapic_nmi_resume,
-	.suspend	= lapic_nmi_suspend,
-};
-
-static struct sys_device device_lapic_nmi = {
-	.id	= 0,
-	.cls	= &nmi_sysclass,
-};
-
-static int __init init_lapic_nmi_sysfs(void)
-{
-	int error;
-
-	/* should really be a BUG_ON but b/c this is an
-	 * init call, it just doesn't work.  -dcz
-	 */
-	if (nmi_watchdog != NMI_LOCAL_APIC)
-		return 0;
-
-	if (atomic_read(&nmi_active) < 0)
-		return 0;
-
-	error = sysdev_class_register(&nmi_sysclass);
-	if (!error)
-		error = sysdev_register(&device_lapic_nmi);
-	return error;
-}
-/* must come after the local APIC's device_initcall() */
-late_initcall(init_lapic_nmi_sysfs);
-
-#endif	/* CONFIG_PM */
-
-static void __acpi_nmi_enable(void *__unused)
-{
-	apic_write_around(APIC_LVT0, APIC_DM_NMI);
-}
-
-/*
- * Enable timer based NMIs on all CPUs:
- */
-void acpi_nmi_enable(void)
-{
-	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
-		on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
-}
-
-static void __acpi_nmi_disable(void *__unused)
-{
-	apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
-}
-
-/*
- * Disable timer based NMIs on all CPUs:
- */
-void acpi_nmi_disable(void)
-{
-	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
-		on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
-}
-
-void setup_apic_nmi_watchdog(void *unused)
-{
-	if (__get_cpu_var(wd_enabled))
-		return;
-
-	/* cheap hack to support suspend/resume */
-	/* if cpu0 is not active neither should the other cpus */
-	if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0))
-		return;
-
-	switch (nmi_watchdog) {
-	case NMI_LOCAL_APIC:
-		__get_cpu_var(wd_enabled) = 1;
-		if (lapic_watchdog_init(nmi_hz) < 0) {
-			__get_cpu_var(wd_enabled) = 0;
-			return;
-		}
-		/* FALL THROUGH */
-	case NMI_IO_APIC:
-		__get_cpu_var(wd_enabled) = 1;
-		atomic_inc(&nmi_active);
-	}
-}
-
-void stop_apic_nmi_watchdog(void *unused)
-{
-	/* only support LOCAL and IO APICs for now */
-	if ((nmi_watchdog != NMI_LOCAL_APIC) &&
-	    (nmi_watchdog != NMI_IO_APIC))
-	    	return;
-	if (__get_cpu_var(wd_enabled) == 0)
-		return;
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		lapic_watchdog_stop();
-	__get_cpu_var(wd_enabled) = 0;
-	atomic_dec(&nmi_active);
-}
-
-/*
- * the best way to detect whether a CPU has a 'hard lockup' problem
- * is to check it's local APIC timer IRQ counts. If they are not
- * changing then that CPU has some problem.
- *
- * as these watchdog NMI IRQs are generated on every CPU, we only
- * have to check the current processor.
- */
-
-static DEFINE_PER_CPU(unsigned, last_irq_sum);
-static DEFINE_PER_CPU(local_t, alert_counter);
-static DEFINE_PER_CPU(int, nmi_touch);
-
-void touch_nmi_watchdog(void)
-{
-	if (nmi_watchdog > 0) {
-		unsigned cpu;
-
-		/*
- 		 * Tell other CPUs to reset their alert counters. We cannot
-		 * do it ourselves because the alert count increase is not
-		 * atomic.
-		 */
-		for_each_present_cpu(cpu) {
-			if (per_cpu(nmi_touch, cpu) != 1)
-				per_cpu(nmi_touch, cpu) = 1;
-		}
-	}
-
-	touch_softlockup_watchdog();
-}
-EXPORT_SYMBOL(touch_nmi_watchdog);
-
-notrace __kprobes int
-nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
-{
-	unsigned int sum;
-	int touched = 0;
-	int cpu = smp_processor_id();
-	int rc = 0;
-
-	/* check for other users first */
-	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
-			== NOTIFY_STOP) {
-		rc = 1;
-		touched = 1;
-	}
-
-	sum = get_timer_irqs(cpu);
-
-	if (__get_cpu_var(nmi_touch)) {
-		__get_cpu_var(nmi_touch) = 0;
-		touched = 1;
-	}
-
-	if (cpu_isset(cpu, backtrace_mask)) {
-		static DEFINE_SPINLOCK(lock);	/* Serialise the printks */
-
-		spin_lock(&lock);
-		printk("NMI backtrace for cpu %d\n", cpu);
-		dump_stack();
-		spin_unlock(&lock);
-		cpu_clear(cpu, backtrace_mask);
-	}
-
-	if (mce_in_progress())
-		touched = 1;
-
-	/* if the apic timer isn't firing, this cpu isn't doing much */
-	if (!touched && __get_cpu_var(last_irq_sum) == sum) {
-		/*
-		 * Ayiee, looks like this CPU is stuck ...
-		 * wait a few IRQs (5 seconds) before doing the oops ...
-		 */
-		local_inc(&__get_cpu_var(alert_counter));
-		if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz)
-			die_nmi("NMI Watchdog detected LOCKUP",
-				regs, panic_on_timeout);
-	} else {
-		__get_cpu_var(last_irq_sum) = sum;
-		local_set(&__get_cpu_var(alert_counter), 0);
-	}
-
-	/* see if the nmi watchdog went off */
-	if (!__get_cpu_var(wd_enabled))
-		return rc;
-	switch (nmi_watchdog) {
-	case NMI_LOCAL_APIC:
-		rc |= lapic_wd_event(nmi_hz);
-		break;
-	case NMI_IO_APIC:
-		/* don't know how to accurately check for this.
-		 * just assume it was a watchdog timer interrupt
-		 * This matches the old behaviour.
-		 */
-		rc = 1;
-		break;
-	}
-	return rc;
-}
-
-#ifdef CONFIG_SYSCTL
-
-static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
-{
-	unsigned char reason = get_nmi_reason();
-	char buf[64];
-
-	sprintf(buf, "NMI received for unknown reason %02x\n", reason);
-	die_nmi(buf, regs, 1);	/* Always panic here */
-	return 0;
-}
-
-/*
- * proc handler for /proc/sys/kernel/nmi
- */
-int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
-			void __user *buffer, size_t *length, loff_t *ppos)
-{
-	int old_state;
-
-	nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
-	old_state = nmi_watchdog_enabled;
-	proc_dointvec(table, write, file, buffer, length, ppos);
-	if (!!old_state == !!nmi_watchdog_enabled)
-		return 0;
-
-	if (atomic_read(&nmi_active) < 0 || nmi_watchdog == NMI_DISABLED) {
-		printk( KERN_WARNING "NMI watchdog is permanently disabled\n");
-		return -EIO;
-	}
-
-	/* if nmi_watchdog is not set yet, then set it */
-	nmi_watchdog_default();
-
-	if (nmi_watchdog == NMI_LOCAL_APIC) {
-		if (nmi_watchdog_enabled)
-			enable_lapic_nmi_watchdog();
-		else
-			disable_lapic_nmi_watchdog();
-	} else {
-		printk( KERN_WARNING
-			"NMI watchdog doesn't know what hardware to touch\n");
-		return -EIO;
-	}
-	return 0;
-}
-
-#endif
-
-int do_nmi_callback(struct pt_regs *regs, int cpu)
-{
-#ifdef CONFIG_SYSCTL
-	if (unknown_nmi_panic)
-		return unknown_nmi_panic_callback(regs, cpu);
-#endif
-	return 0;
-}
-
-void __trigger_all_cpu_backtrace(void)
-{
-	int i;
-
-	backtrace_mask = cpu_online_map;
-	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
-	for (i = 0; i < 10 * 1000; i++) {
-		if (cpus_empty(backtrace_mask))
-			break;
-		mdelay(1);
-	}
-}
-
-EXPORT_SYMBOL(nmi_active);
-EXPORT_SYMBOL(nmi_watchdog);
Index: linux-2.6.git/arch/x86/kernel/Makefile
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/Makefile	2008-05-24 10:27:49.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/Makefile	2008-05-24 14:59:03.000000000 +0400
@@ -53,7 +53,7 @@ obj-$(CONFIG_X86_32_SMP)	+= smpcommon.o
 obj-$(CONFIG_X86_64_SMP)	+= tsc_sync.o smpcommon.o
 obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline_$(BITS).o
 obj-$(CONFIG_X86_MPPARSE)	+= mpparse.o
-obj-$(CONFIG_X86_LOCAL_APIC)	+= apic_$(BITS).o nmi_$(BITS).o
+obj-$(CONFIG_X86_LOCAL_APIC)	+= apic_$(BITS).o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic_$(BITS).o
 obj-$(CONFIG_X86_REBOOTFIXUPS)	+= reboot_fixups_32.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec_$(BITS).o

-- 

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

* Re: [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
  2008-05-24 15:36 ` [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write Cyrill Gorcunov
@ 2008-05-28 15:35   ` Maciej W. Rozycki
  2008-05-28 16:04     ` Cyrill Gorcunov
  0 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2008-05-28 15:35 UTC (permalink / raw)
  To: Cyrill Gorcunov; +Cc: hpa, tglx, mingo, linux-kernel

On Sat, 24 May 2008, Cyrill Gorcunov wrote:

> apic_write_around will be expanded to apic_write in 64bit mode
> anyway. Only a few CPUs (well, old CPUs to be precise) requires
> such an action. In general it should not hurt and could be cleaned
> up for apic_write (just in case)
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
> ---

Acked-by: Maciej W. Rozycki <macro@linux-mips.org>

 Almost all local APIC write accesses must use apic_write_around().  The
notable exceptions are appropriately guarded accesses to the ESR (there is
no need ever to write to this register on Pentium processors and a read of
the register has side-effects) and pieces of code known never to run on
original Pentium processors.

  Maciej

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

* Re: [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
  2008-05-28 15:35   ` Maciej W. Rozycki
@ 2008-05-28 16:04     ` Cyrill Gorcunov
  2008-05-28 16:13       ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-28 16:04 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: hpa, tglx, mingo, linux-kernel

[Maciej W. Rozycki - Wed, May 28, 2008 at 04:35:14PM +0100]
| On Sat, 24 May 2008, Cyrill Gorcunov wrote:
| 
| > apic_write_around will be expanded to apic_write in 64bit mode
| > anyway. Only a few CPUs (well, old CPUs to be precise) requires
| > such an action. In general it should not hurt and could be cleaned
| > up for apic_write (just in case)
| > 
| > Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
| > ---
| 
| Acked-by: Maciej W. Rozycki <macro@linux-mips.org>
| 
|  Almost all local APIC write accesses must use apic_write_around().  The
| notable exceptions are appropriately guarded accesses to the ESR (there is
| no need ever to write to this register on Pentium processors and a read of
| the register has side-effects) and pieces of code known never to run on
| original Pentium processors.
| 
|   Maciej
| 

Thanks Maciej!

Could you take a look please on

http://lkml.org/lkml/2008/5/26/146

i'm investigateting what is happening (Adrian pointed on
main reason I think) but can't understand why is that.

		- Cyrill -

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

* Re: [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
  2008-05-28 16:04     ` Cyrill Gorcunov
@ 2008-05-28 16:13       ` Maciej W. Rozycki
  2008-05-28 16:25         ` Cyrill Gorcunov
  0 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2008-05-28 16:13 UTC (permalink / raw)
  To: Cyrill Gorcunov; +Cc: hpa, tglx, mingo, linux-kernel

On Wed, 28 May 2008, Cyrill Gorcunov wrote:

> Could you take a look please on
> 
> http://lkml.org/lkml/2008/5/26/146
> 
> i'm investigateting what is happening (Adrian pointed on
> main reason I think) but can't understand why is that.

 Do you have a link with the patch included?

  Maciej

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

* Re: [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
  2008-05-28 16:13       ` Maciej W. Rozycki
@ 2008-05-28 16:25         ` Cyrill Gorcunov
  2008-05-28 17:09           ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-28 16:25 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: hpa, tglx, mingo, linux-kernel

[Maciej W. Rozycki - Wed, May 28, 2008 at 05:13:08PM +0100]
| On Wed, 28 May 2008, Cyrill Gorcunov wrote:
| 
| > Could you take a look please on
| > 
| > http://lkml.org/lkml/2008/5/26/146
| > 
| > i'm investigateting what is happening (Adrian pointed on
| > main reason I think) but can't understand why is that.
| 
|  Do you have a link with the patch included?
| 
|   Maciej
| 

Here is the patch itself:

---
x86: nmi_32.c - add nmi_watchdog_default helper

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---

Index: linux-2.6.git/arch/x86/kernel/nmi_32.c
====================================================================
--- linux-2.6.git.orig/arch/x86/kernel/nmi_32.c	2008-05-24 13:01:21.000000000 +0400
+++ linux-2.6.git/arch/x86/kernel/nmi_32.c	2008-05-24 13:04:20.000000000 +0400
@@ -51,6 +51,17 @@ static DEFINE_PER_CPU(short, wd_enabled)
 
 static int endflag __initdata = 0;
 
+/* Run after command line and cpu_init init, but before all other checks */
+void nmi_watchdog_default(void)
+{
+	if (nmi_watchdog != NMI_DEFAULT)
+		return;
+	if (lapic_watchdog_ok())
+		nmi_watchdog = NMI_LOCAL_APIC;
+	else
+		nmi_watchdog = NMI_IO_APIC;
+}
+
 #ifdef CONFIG_SMP
 /* The performance counters used by NMI_LOCAL_APIC don't trigger when
  * the CPU is idle. To make sure the NMI watchdog really ticks on all
@@ -437,12 +448,8 @@ int proc_nmi_enabled(struct ctl_table *t
 		return -EIO;
 	}
 
-	if (nmi_watchdog == NMI_DEFAULT) {
-		if (lapic_watchdog_ok())
-			nmi_watchdog = NMI_LOCAL_APIC;
-		else
-			nmi_watchdog = NMI_IO_APIC;
-	}
+	/* if nmi_watchdog is not set yet, then set it */
+	nmi_watchdog_default();
 
 	if (nmi_watchdog == NMI_LOCAL_APIC) {
 		if (nmi_watchdog_enabled)
Index: linux-2.6.git/include/asm-x86/nmi.h
====================================================================
--- linux-2.6.git.orig/include/asm-x86/nmi.h	2008-05-24 13:00:50.000000000 +0400
+++ linux-2.6.git/include/asm-x86/nmi.h	2008-05-24 13:04:51.000000000 +0400
@@ -38,11 +38,9 @@ static inline void unset_nmi_pm_callback
 
 #ifdef CONFIG_X86_64
 extern void default_do_nmi(struct pt_regs *);
-extern void nmi_watchdog_default(void);
-#else
-#define nmi_watchdog_default() do {} while (0)
 #endif
 
+extern void nmi_watchdog_default(void);
 extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern int check_nmi_watchdog(void);
 extern int nmi_watchdog_enabled;
---

So I've moved a part of code (32bit) from proc_nmi_enabled() to
nmi_watchdog_default() BUT this nmi_watchdog_default() also called
from smpboot.c:native_smp_prepare_cpus() and before this patch
this call was just an empty call (and eliminated by gcc I think)
now it's not empy. But how it leads to hang I can't understand.
The only thing is done - nmi_watchdog is set to NMI_LOCAL_APIC
or NMI_IO_APIC and my only suspicious is that something happens
asynchronously and leads to machine hang. Let me know if I wrote
in obscure manner.

		- Cyrill -

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

* Re: [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
  2008-05-28 16:25         ` Cyrill Gorcunov
@ 2008-05-28 17:09           ` Maciej W. Rozycki
  2008-05-28 17:16             ` Cyrill Gorcunov
  0 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2008-05-28 17:09 UTC (permalink / raw)
  To: Cyrill Gorcunov; +Cc: hpa, tglx, mingo, linux-kernel

On Wed, 28 May 2008, Cyrill Gorcunov wrote:

> So I've moved a part of code (32bit) from proc_nmi_enabled() to
> nmi_watchdog_default() BUT this nmi_watchdog_default() also called
> from smpboot.c:native_smp_prepare_cpus() and before this patch
> this call was just an empty call (and eliminated by gcc I think)
> now it's not empy. But how it leads to hang I can't understand.
> The only thing is done - nmi_watchdog is set to NMI_LOCAL_APIC
> or NMI_IO_APIC and my only suspicious is that something happens
> asynchronously and leads to machine hang. Let me know if I wrote
> in obscure manner.

 The problem is the I/O APIC NMI watchdog which does not work correctly on
the reporter's machine.  Your patch makes the NMI watchdog be enabled by
default on 32-bit platforms (OTOH, proc_nmi_enabled() is only called by an
explicit request via sysctl).  Unfortunately many hardware vendors have
not fully recognised the existence of Linux yet and the NMI watchdog
frequently triggers breakage in SMM firmware even on modern equipment;  
actually it was less likely to break in the old days.

  Maciej

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

* Re: [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
  2008-05-28 17:09           ` Maciej W. Rozycki
@ 2008-05-28 17:16             ` Cyrill Gorcunov
  2008-05-28 17:47               ` Maciej W. Rozycki
  0 siblings, 1 reply; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-28 17:16 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: hpa, tglx, mingo, linux-kernel

[Maciej W. Rozycki - Wed, May 28, 2008 at 06:09:38PM +0100]
| On Wed, 28 May 2008, Cyrill Gorcunov wrote:
| 
| > So I've moved a part of code (32bit) from proc_nmi_enabled() to
| > nmi_watchdog_default() BUT this nmi_watchdog_default() also called
| > from smpboot.c:native_smp_prepare_cpus() and before this patch
| > this call was just an empty call (and eliminated by gcc I think)
| > now it's not empy. But how it leads to hang I can't understand.
| > The only thing is done - nmi_watchdog is set to NMI_LOCAL_APIC
| > or NMI_IO_APIC and my only suspicious is that something happens
| > asynchronously and leads to machine hang. Let me know if I wrote
| > in obscure manner.
| 
|  The problem is the I/O APIC NMI watchdog which does not work correctly on
| the reporter's machine.  Your patch makes the NMI watchdog be enabled by
| default on 32-bit platforms (OTOH, proc_nmi_enabled() is only called by an
| explicit request via sysctl).  Unfortunately many hardware vendors have
| not fully recognised the existence of Linux yet and the NMI watchdog
| frequently triggers breakage in SMM firmware even on modern equipment;  
| actually it was less likely to break in the old days.
| 
|   Maciej
| 

Thanks a lot, Maciej!!! Could you please explain me how did you find
that? 'cause reporter said that with nmi_watchdog=2 it works and with
nmi_watchdog=1 it stalls? Maybe I should better make this function
the same as 64bit version has? I.e. set nmi_watchdog = NMI_NONE by default?

		- Cyrill -

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

* Re: [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
  2008-05-28 17:16             ` Cyrill Gorcunov
@ 2008-05-28 17:47               ` Maciej W. Rozycki
  2008-05-28 18:32                 ` Cyrill Gorcunov
  0 siblings, 1 reply; 19+ messages in thread
From: Maciej W. Rozycki @ 2008-05-28 17:47 UTC (permalink / raw)
  To: Cyrill Gorcunov; +Cc: hpa, tglx, mingo, linux-kernel

On Wed, 28 May 2008, Cyrill Gorcunov wrote:

> Thanks a lot, Maciej!!! Could you please explain me how did you find
> that? 'cause reporter said that with nmi_watchdog=2 it works and with
> nmi_watchdog=1 it stalls? Maybe I should better make this function
> the same as 64bit version has? I.e. set nmi_watchdog = NMI_NONE by default?

 Well, nmi_watchdog=1 is the I/O APIC watchdog and if no watchdog has been
specified at the command line, the piece of code you have moved selects
between the local and the I/O APIC watchdog based on availability of the
former.  So in this case the local watchdog must have been unavailable as
it works if requested explicitly.

 No piece of code in nmi_watchdog_default() touches peripheral hardware
and native_smp_prepare_cpus() is called early enough the system is still
running UP and no APIC setup has happened yet, so any interference with
running hardware can be excluded.

 Random lock-ups are a typical symptom of the NMI watchdog interfering
with SMM firmware -- of course in the context of the watchdog being
suspected in the first place -- there may be plenty of other reasons of
random lock-ups.  Obviously this is the SMM firmware asking for trouble
explicitly, because NMIs are disabled by the processor upon entering the
SMM and it is the SMI handler that unmasks the NMI explicitly (with an
IRET, which shouldn't be used in the SMM mode at all) -- otherwise it
wouldn't even notice the watchdog running, but there you go.

 As a rule of thumb any piece of firmware that has a possibility to run
from an OS context should not use interrupts of any kind, because it is
quite likely it cannot handle them in the way the OS expects them to be
handled.  It is as simple as that, but perhaps too simple for some to
comprehend. :(

  Maciej

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

* Re: [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write
  2008-05-28 17:47               ` Maciej W. Rozycki
@ 2008-05-28 18:32                 ` Cyrill Gorcunov
  0 siblings, 0 replies; 19+ messages in thread
From: Cyrill Gorcunov @ 2008-05-28 18:32 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: hpa, tglx, mingo, linux-kernel

[Maciej W. Rozycki - Wed, May 28, 2008 at 06:47:56PM +0100]
| On Wed, 28 May 2008, Cyrill Gorcunov wrote:
| 
| > Thanks a lot, Maciej!!! Could you please explain me how did you find
| > that? 'cause reporter said that with nmi_watchdog=2 it works and with
| > nmi_watchdog=1 it stalls? Maybe I should better make this function
| > the same as 64bit version has? I.e. set nmi_watchdog = NMI_NONE by default?
| 
|  Well, nmi_watchdog=1 is the I/O APIC watchdog and if no watchdog has been
| specified at the command line, the piece of code you have moved selects
| between the local and the I/O APIC watchdog based on availability of the
| former.  So in this case the local watchdog must have been unavailable as
| it works if requested explicitly.
| 
|  No piece of code in nmi_watchdog_default() touches peripheral hardware
| and native_smp_prepare_cpus() is called early enough the system is still
| running UP and no APIC setup has happened yet, so any interference with
| running hardware can be excluded.
| 
|  Random lock-ups are a typical symptom of the NMI watchdog interfering
| with SMM firmware -- of course in the context of the watchdog being
| suspected in the first place -- there may be plenty of other reasons of
| random lock-ups.  Obviously this is the SMM firmware asking for trouble
| explicitly, because NMIs are disabled by the processor upon entering the
| SMM and it is the SMI handler that unmasks the NMI explicitly (with an
| IRET, which shouldn't be used in the SMM mode at all) -- otherwise it
| wouldn't even notice the watchdog running, but there you go.
| 
|  As a rule of thumb any piece of firmware that has a possibility to run
| from an OS context should not use interrupts of any kind, because it is
| quite likely it cannot handle them in the way the OS expects them to be
| handled.  It is as simple as that, but perhaps too simple for some to
| comprehend. :(
| 
|   Maciej
| 

oh... :( i think i just restore old behaviour for now. Thanks for explanation!

		- Cyrill -

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

end of thread, other threads:[~2008-05-28 18:32 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20080524153630.669797039@gmail.com>
2008-05-24 15:36 ` [patch 01/11] x86: nmi - unify die_nmi() interface Cyrill Gorcunov
2008-05-24 15:36 ` [patch 02/11] x86: nmi - die_nmi() output message unification Cyrill Gorcunov
2008-05-24 15:36 ` [patch 03/11] x86: nmi_64.c - move do_nmi(), stop_nmi() and restart_nmi() implementation to traps_64.c Cyrill Gorcunov
2008-05-24 15:36 ` [patch 04/11] x86: nmi_32.c - add "panic" option Cyrill Gorcunov
2008-05-24 15:36 ` [patch 05/11] x86: nmi_32.c - add nmi_watchdog_default helper Cyrill Gorcunov
2008-05-24 15:36 ` [patch 06/11] x86: nmi_32/64.c - use apic_write_around instead of apic_write Cyrill Gorcunov
2008-05-28 15:35   ` Maciej W. Rozycki
2008-05-28 16:04     ` Cyrill Gorcunov
2008-05-28 16:13       ` Maciej W. Rozycki
2008-05-28 16:25         ` Cyrill Gorcunov
2008-05-28 17:09           ` Maciej W. Rozycki
2008-05-28 17:16             ` Cyrill Gorcunov
2008-05-28 17:47               ` Maciej W. Rozycki
2008-05-28 18:32                 ` Cyrill Gorcunov
2008-05-24 15:36 ` [patch 07/11] x86: nmi_32.c - unknown_nmi_panic_callback should always panic on being called Cyrill Gorcunov
2008-05-24 15:36 ` [patch 08/11] x86: nmi_64.c - use for_each_possible_cpu helper instead of for statement Cyrill Gorcunov
2008-05-24 15:36 ` [patch 09/11] x86: nmi_32.c cleanup - use for_each_online_cpu helper Cyrill Gorcunov
2008-05-24 15:36 ` [patch 10/11] x86: nmi_32/64.c - add helper functions to hide mode-specific data Cyrill Gorcunov
2008-05-24 15:36 ` [patch 11/11] x86: nmi_32/64.c - merge down nmi_32.c and nmi_64.c to nmi.c Cyrill Gorcunov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox