Linus, please apply.
Regards,
	Zwane Mwaikambo
--- linux-2.5.19/arch/i386/kernel/bluesmoke.c	Sun Jun  2 22:27:39 2002
+++ linux-2.5-dj/arch/i386/kernel/bluesmoke.c	Thu May 30 09:50:13 2002
@@ -18,8 +18,24 @@
 
 #ifdef CONFIG_X86_MCE
 
+/* as supported by the P4/Xeon family */
+struct intel_mce_extended_msrs {
+	u32 eax;
+	u32 ebx;
+	u32 ecx;
+	u32 edx;
+	u32 esi;
+	u32 edi;
+	u32 ebp;
+	u32 esp;
+	u32 eflags;
+	u32 eip;
+	/* u32 *reserved[]; */
+};
+
 static int mce_disabled __initdata = 0;
 
+static int mce_num_extended_msrs = 0;
 static int banks;
 
 
@@ -75,47 +91,73 @@
 	if (!cpu_has(c, X86_FEATURE_ACC))
 		return;	/* -ENODEV */
 
-	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
 	/* first check if its enabled already, in which case there might
 	 * be some SMM goo which handles it, so we can't even put a handler
 	 * since it might be delivered via SMI already -zwanem.
 	 */
-
-	if (l & (1<<3)) {
-		printk(KERN_DEBUG "CPU#%d: Thermal monitoring already enabled\n", cpu);
-	} else {
-		wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
-		printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
+	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+	h = apic_read(APIC_LVTTHMR);
+	if ((l & (1<<3)) && (h & APIC_DM_SMI)) {
+		printk(KERN_DEBUG "CPU#%d: Thermal monitoring handled by SMI\n", cpu);
+		return; /* -EBUSY */
 	}
 
-	/* check whether a vector already exists */	
-	l = apic_read(APIC_LVTTHMR);
-	if (l & 0xff) {
-		printk(KERN_DEBUG "CPU#%d: Thermal LVT already handled\n", cpu);
+	/* check whether a vector already exists, temporarily masked? */	
+	if (h & APIC_VECTOR_MASK) {
+		printk(KERN_DEBUG "CPU#%d: Thermal LVT vector (%#x) already installed\n",
+			cpu, (h & APIC_VECTOR_MASK));
 		return; /* -EBUSY */
 	}
 
-	wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
-	printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
-
 	/* The temperature transition interrupt handler setup */
-	l = THERMAL_APIC_VECTOR;		/* our delivery vector */
-	l |= (APIC_DM_FIXED | APIC_LVT_MASKED);	/* we'll mask till we're ready */
-	apic_write_around(APIC_LVTTHMR, l);
+	h = THERMAL_APIC_VECTOR;		/* our delivery vector */
+	h |= (APIC_DM_FIXED | APIC_LVT_MASKED);	/* we'll mask till we're ready */
+	apic_write_around(APIC_LVTTHMR, h);
 
 	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x3 , h);
+	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03 , h);
 
 	/* ok we're good to go... */
 	vendor_thermal_interrupt = intel_thermal_interrupt;
+	
+	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+	wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+	
 	l = apic_read(APIC_LVTTHMR);
 	apic_write_around(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
-
+	printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
 	return;
 }
 #endif /* CONFIG_X86_MCE_P4THERMAL */
 
 
+/* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
+
+static int inline intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
+{
+	u32 h;
+
+	if (mce_num_extended_msrs == 0)
+		goto done;
+
+	rdmsr(MSR_IA32_MCG_EAX, r->eax, h);
+	rdmsr(MSR_IA32_MCG_EBX, r->ebx, h);
+	rdmsr(MSR_IA32_MCG_ECX, r->ecx, h);
+	rdmsr(MSR_IA32_MCG_EDX, r->edx, h);
+	rdmsr(MSR_IA32_MCG_ESI, r->esi, h);
+	rdmsr(MSR_IA32_MCG_EDI, r->edi, h);
+	rdmsr(MSR_IA32_MCG_EBP, r->ebp, h);
+	rdmsr(MSR_IA32_MCG_ESP, r->esp, h);
+	rdmsr(MSR_IA32_MCG_EFLAGS, r->eflags, h);
+	rdmsr(MSR_IA32_MCG_EIP, r->eip, h);
+
+	/* can we rely on kmalloc to do a dynamic
+	 * allocation for the reserved registers?
+	 */
+done:
+	return mce_num_extended_msrs;
+}
+
 /*
  *	Machine Check Handler For PII/PIII
  */
@@ -126,6 +168,7 @@
 	u32 alow, ahigh, high, low;
 	u32 mcgstl, mcgsth;
 	int i;
+	struct intel_mce_extended_msrs dbg;
 
 	rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 	if(mcgstl&(1<<0))	/* Recoverable ? */
@@ -133,6 +176,15 @@
 
 	printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl);
 
+	if (intel_get_extended_msrs(&dbg)) {
+		printk(KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n",
+			smp_processor_id(), dbg.eip, dbg.eflags);
+		printk(KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n",
+			dbg.eax, dbg.ebx, dbg.ecx, dbg.edx);
+		printk(KERN_DEBUG "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n",
+			dbg.esi, dbg.edi, dbg.ebp, dbg.esp);
+	}
+
 	for (i=0;i<banks;i++) {
 		rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high);
 		if(high&(1<<31)) {
@@ -334,11 +386,24 @@
 	set_in_cr4(X86_CR4_MCE);
 	printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
 
+	/*
+	 *	Check for P4/Xeon specific MCE extensions
+	 */
+
+	if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 15) {
+		/* Check for P4/Xeon extended MCE MSRs */
+		rdmsr(MSR_IA32_MCG_CAP, l, h);
+		if (l & (1<<9))	{/* MCG_EXT_P */
+			mce_num_extended_msrs = (l >> 16) & 0xff;
+			printk(KERN_INFO "CPU#%d: Intel P4/Xeon Extended MCE MSRs (%d) available\n",
+				smp_processor_id(), mce_num_extended_msrs);
+		}
+		
 #ifdef CONFIG_X86_MCE_P4THERMAL
-	/* Only enable thermal throttling warning on Pentium 4. */
-	if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 15)
+		/* Check for P4/Xeon Thermal monitor */
 		intel_init_thermal(c);
 #endif
+	}
 
 	done=1;
 }
--- linux-2.5.19/include/asm-i386/msr.h	Sun Jun  2 22:27:47 2002
+++ linux-2.5-dj/include/asm-i386/msr.h	Thu May 30 09:50:18 2002
@@ -57,8 +57,21 @@
 #define MSR_IA32_MCG_STATUS		0x17a
 #define MSR_IA32_MCG_CTL		0x17b
 
-#define MSR_P6_EVNTSEL0		0x186
-#define MSR_P6_EVNTSEL1		0x187
+/* P4/Xeon+ specific */
+#define MSR_IA32_MCG_EAX		0x180
+#define MSR_IA32_MCG_EBX		0x181
+#define MSR_IA32_MCG_ECX		0x182
+#define MSR_IA32_MCG_EDX		0x183
+#define MSR_IA32_MCG_ESI		0x184
+#define MSR_IA32_MCG_EDI		0x185
+#define MSR_IA32_MCG_EBP		0x186
+#define MSR_IA32_MCG_ESP		0x187
+#define MSR_IA32_MCG_EFLAGS		0x188
+#define MSR_IA32_MCG_EIP		0x189
+#define MSR_IA32_MCG_RESERVED		0x18A
+
+#define MSR_P6_EVNTSEL0			0x186
+#define MSR_P6_EVNTSEL1			0x187
 
 #define MSR_IA32_THERM_CONTROL		0x19a
 #define MSR_IA32_THERM_INTERRUPT	0x19b
--- linux-2.5.19/include/asm-i386/hw_irq.h.orig	Mon Jun  3 16:04:52 2002
+++ linux-2.5.19/include/asm-i386/hw_irq.h	Mon Jun  3 16:07:04 2002
@@ -28,9 +28,6 @@
 
 extern void (*interrupt[NR_IRQS])(void);
 
-extern asmlinkage void thermal_interrupt(void);
-extern asmlinkage void smp_thermal_interrupt(struct pt_regs);
-
 #ifdef CONFIG_SMP
 extern asmlinkage void reschedule_interrupt(void);
 extern asmlinkage void invalidate_interrupt(void);
@@ -41,6 +38,7 @@
 extern asmlinkage void apic_timer_interrupt(void);
 extern asmlinkage void error_interrupt(void);
 extern asmlinkage void spurious_interrupt(void);
+extern asmlinkage void thermal_interrupt(struct pt_regs);
 #endif
 
 extern void mask_irq(unsigned int irq);
-- http://function.linuxpower.ca
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/