patch-2.4.5 linux/arch/i386/kernel/bluesmoke.c

Next file: linux/arch/i386/kernel/i386_ksyms.c
Previous file: linux/arch/i386/defconfig
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c
@@ -1,16 +1,18 @@
-/*
- *	Machine Check Handler For PII/PIII
- */
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <asm/processor.h> 
 #include <asm/msr.h>
 
+/*
+ *	Machine Check Handler For PII/PIII
+ */
+
 static int banks;
 
-void do_machine_check(struct pt_regs * regs, long error_code)
+static void intel_machine_check(struct pt_regs * regs, long error_code)
 {
 	int recover=1;
 	u32 alow, ahigh, high, low;
@@ -62,28 +64,101 @@
 	wrmsr(0x17a,mcgstl, mcgsth);
 }
 
+/*
+ *	Machine check handler for Pentium class Intel
+ */
+ 
+static void pentium_machine_check(struct pt_regs * regs, long error_code)
+{
+	u32 loaddr, hi, lotype;
+	rdmsr(0x0, loaddr, hi);
+	rdmsr(0x1, lotype, hi);
+	printk(KERN_EMERG "CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype);
+	if(lotype&(1<<5))
+		printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id());
+}
 
 /*
- *	This has to be run for each processor
+ *	Machine check handler for WinChip C6
+ */
+ 
+static void winchip_machine_check(struct pt_regs * regs, long error_code)
+{
+	printk(KERN_EMERG "CPU#%d: Machine Check Exception.\n", smp_processor_id());
+}
+
+/*
+ *	Handle unconfigured int18 (should never happen)
  */
+
+static void unexpected_machine_check(struct pt_regs * regs, long error_code)
+{	
+	printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
+}
+
+/*
+ *	Call the installed machine check handler for this CPU setup.
+ */ 
  
-void mcheck_init(struct cpuinfo_x86 *c)
+static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
+
+void do_machine_check(struct pt_regs * regs, long error_code)
+{
+	machine_check_vector(regs, error_code);
+}
+
+/*
+ *	Set up machine check reporting for Intel processors
+ */
+
+void __init intel_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
 	int i;
 	static int done;
-
-	if( c->x86_vendor != X86_VENDOR_INTEL )
-		return;
 	
+	/*
+	 *	Check for MCE support
+	 */
+
 	if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) )
+		return;	
+	
+	/*
+	 *	Pentium machine check
+	 */
+	
+	if(c->x86 == 5)
+	{
+		machine_check_vector = pentium_machine_check;
+		wmb();
+		/* Read registers before enabling */
+		rdmsr(0x0, l, h);
+		rdmsr(0x1, l, h);
+		if(done==0)
+			printk(KERN_INFO "Intel old style machine check architecture supported.\n");
+		/* Enable MCE */		
+		__asm__ __volatile__ (
+			"movl %%cr4, %%eax\n\t"
+			"orl $0x40, %%eax\n\t"
+			"movl %%eax, %%cr4\n\t" : : : "eax");
+		printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
 		return;
-		
+	}
+	
+
+	/*
+	 *	Check for PPro style MCA
+	 */
+	 		
 	if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
 		return;
 		
 	/* Ok machine check is available */
 	
+	machine_check_vector = intel_machine_check;
+	wmb();
+	
 	if(done==0)
 		printk(KERN_INFO "Intel machine check architecture supported.\n");
 	rdmsr(0x179, l, h);
@@ -98,10 +173,56 @@
 	{
 		wrmsr(0x401+4*i, 0x0, 0x0); 
 	}
+	set_in_cr4(X86_CR4_MCE);
+	printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+	done=1;
+}
+
+/*
+ *	Set up machine check reporting on the Winchip C6 series
+ */
+ 
+static void winchip_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u32 lo, hi;
+	/* Not supported on C3 */
+	if(c->x86 != 5)
+		return;
+	/* Winchip C6 */
+	machine_check_vector = winchip_machine_check;
+	wmb();
+	rdmsr(0x107, lo, hi);
+	lo|= (1<<2);	/* Enable EIERRINT (int 18 MCE) */
+	lo&= ~(1<<4);	/* Enable MCE */
+	wrmsr(0x107, lo, hi);
 	__asm__ __volatile__ (
 		"movl %%cr4, %%eax\n\t"
 		"orl $0x40, %%eax\n\t"
 		"movl %%eax, %%cr4\n\t" : : : "eax");
-	printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
-	done=1;
+	printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+}
+
+
+/*
+ *	This has to be run for each processor
+ */
+
+void __init mcheck_init(struct cpuinfo_x86 *c)
+{
+	switch(c->x86_vendor)
+	{
+		case X86_VENDOR_AMD:
+			/*
+			 *	AMD K7 machine check is Intel like
+			 */
+			if(c->x86 == 6)
+				intel_mcheck_init(c);
+			break;
+		case X86_VENDOR_INTEL:
+			intel_mcheck_init(c);
+			break;
+		case X86_VENDOR_CENTAUR:
+			winchip_mcheck_init(c);
+			break;
+	}
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)