Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3988

kernel-2.6.18-194.11.1.el5.src.rpm

From: Aristeu Rozanski <aris@redhat.com>
Date: Wed, 20 Aug 2008 13:17:02 -0400
Subject: [x86] nmi: introduce do_nmi_callback
Message-id: 20080820171650.316226000@redhat.com
O-Subject: [RHEL5.3 PATCH 16/25] nmi: introduce do_nmi_callback for i386
Bugzilla: 447618

https://bugzilla.redhat.com/show_bug.cgi?id=447618

Fix setup_apic_nmi_watchdog to use perfctr and introduce do_nmi_callback()
to be called to determine if there's a handler catching the NMIs.

Upstream: 3adbbcce9a49b900d4cc118cdccfdefa78bf1afb

diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index eb91d21..956ac01 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -369,41 +369,21 @@ static void write_watchdog_counter32(const char *descr)
 
 void setup_apic_nmi_watchdog (void)
 {
-	switch (boot_cpu_data.x86_vendor) {
-	case X86_VENDOR_AMD:
-		if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 && boot_cpu_data.x86 != 16)
-			return;
-		setup_k7_watchdog();
-		break;
-	case X86_VENDOR_INTEL:
-		if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
-			if (!setup_intel_arch_watchdog())
-				return;
-			break;
-		}
-		switch (boot_cpu_data.x86) {
-		case 6:
-			if (boot_cpu_data.x86_model > 0xd)
-				return;
-
-			setup_p6_watchdog();
-			break;
-		case 15:
-			if (boot_cpu_data.x86_model > 0x4)
-				return;
-
-			if (!setup_p4_watchdog())
-				return;
-			break;
-		default:
+	if (__get_cpu_var(wd_enabled) == 1)
+		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;
 		}
-		break;
-	default:
-		return;
+		/* FALL THROUGH */
+	case NMI_IO_APIC:
+		__get_cpu_var(wd_enabled) = 1;
+		atomic_inc(&nmi_active);
 	}
-	lapic_nmi_owner = LAPIC_NMI_WATCHDOG;
-	nmi_active = 1;
 }
 
 /*
@@ -499,6 +479,16 @@ void nmi_watchdog_tick (struct pt_regs * regs)
 	}
 }
 
+static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu);
+int do_nmi_callback(struct pt_regs *regs, int cpu)
+{
+#ifdef CONFIG_SYSCTL
+	if (unknown_nmi_panic)
+		unknown_nmi_panic_callback(regs, cpu);
+#endif
+	return 0;
+}
+
 #ifdef CONFIG_SYSCTL
 
 static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
@@ -506,10 +496,9 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
 	unsigned char reason = get_nmi_reason();
 	char buf[64];
 
-	if (!(reason & 0xc0)) {
-		sprintf(buf, "NMI received for unknown reason %02x\n", reason);
-		die_nmi(regs, buf);
-	}
+	sprintf(buf, "NMI received for unknown reason %02x\n", reason);
+	die_nmi(regs, buf);
+
 	return 0;
 }
 
@@ -530,12 +519,9 @@ int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file,
 		if (reserve_lapic_nmi() < 0) {
 			unknown_nmi_panic = 0;
 			return -EBUSY;
-		} else {
-			set_nmi_callback(unknown_nmi_panic_callback);
 		}
 	} else {
 		release_lapic_nmi();
-		unset_nmi_callback();
 	}
 	return 0;
 }
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 3217dc3..10fa3ea 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -811,9 +811,10 @@ void die_nmi (struct pt_regs *regs, const char *msg)
 static void default_do_nmi(struct pt_regs * regs)
 {
 	unsigned char reason = 0;
+	int cpu = smp_processor_id();
 
 	/* Only the BSP gets external NMIs from the system.  */
-	if (!smp_processor_id())
+	if (!cpu)
 		reason = get_nmi_reason();
  
 	if (!(reason & 0xc0)) {
@@ -830,7 +831,8 @@ static void default_do_nmi(struct pt_regs * regs)
 			return;
 		}
 #endif
-		unknown_nmi_error(reason, regs);
+		if (!do_nmi_callback(regs, cpu))
+			unknown_nmi_error(reason, regs);
 		return;
 	}
 	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index f127beb..4ff5761 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -11,6 +11,14 @@ struct pt_regs;
 typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
 
 /**
+ * do_nmi_callback
+ *
+ * Check to see if a callback exists and execute it. Return 1
+ * if the handler exists and was handled successfully.
+ */
+int do_nmi_callback(struct pt_regs *regs, int cpu);
+
+/**
  * set_nmi_callback
  *
  * Set a handler for an NMI. Only one handler may be