
From: Philippe Elie <phil.el@wanadoo.fr>

Contributions from  Zarakin <zarakin@hotpop.com>

Intel removed two msrs: MSR_P4_IQ_ESCR_0|1 (0x3ba/0x3bb), P4 model >= 3.  See
Intel documentation Vol.  3 System Programming Guide Appendix B.

nmi_watchdog=2 oopsed at boot time and oprofile at driver load.

Avoid touching them when model >= 3.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/i386/kernel/nmi.c           |    8 ++++++
 25-akpm/arch/i386/oprofile/op_model_p4.c |   36 ++++++++++++++++++++++++++++---
 2 files changed, 40 insertions(+), 4 deletions(-)

diff -puN arch/i386/kernel/nmi.c~fix-oops-with-nmi_watchdog=2 arch/i386/kernel/nmi.c
--- 25/arch/i386/kernel/nmi.c~fix-oops-with-nmi_watchdog=2	2004-08-28 14:36:27.265947120 -0700
+++ 25-akpm/arch/i386/kernel/nmi.c	2004-08-28 14:36:27.270946360 -0700
@@ -380,7 +380,13 @@ static int setup_p4_watchdog(void)
 		clear_msr_range(0x3F1, 2);
 	/* MSR 0x3F0 seems to have a default value of 0xFC00, but current
 	   docs doesn't fully define it, so leave it alone for now. */
-	clear_msr_range(0x3A0, 31);
+	if (boot_cpu_data.x86_model >= 0x3) {
+		/* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */
+		clear_msr_range(0x3A0, 26);
+		clear_msr_range(0x3BC, 3);
+	} else {
+		clear_msr_range(0x3A0, 31);
+	}
 	clear_msr_range(0x3C0, 6);
 	clear_msr_range(0x3C8, 6);
 	clear_msr_range(0x3E0, 2);
diff -puN arch/i386/oprofile/op_model_p4.c~fix-oops-with-nmi_watchdog=2 arch/i386/oprofile/op_model_p4.c
--- 25/arch/i386/oprofile/op_model_p4.c~fix-oops-with-nmi_watchdog=2	2004-08-28 14:36:27.266946968 -0700
+++ 25-akpm/arch/i386/oprofile/op_model_p4.c	2004-08-28 14:36:27.271946208 -0700
@@ -419,9 +419,28 @@ static void p4_fill_in_addresses(struct 
 		msrs->controls[i].addr = addr;
 	}
 	
-	/* 43 ESCR registers in three discontiguous group */
+	/* 43 ESCR registers in three or four discontiguous group */
 	for (addr = MSR_P4_BSU_ESCR0 + stag;
-	     addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { 
+	     addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
+		msrs->controls[i].addr = addr;
+	}
+
+	/* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
+	 * to avoid special case in nmi_{save|restore}_registers() */
+	if (boot_cpu_data.x86_model >= 0x3) {
+		for (addr = MSR_P4_BSU_ESCR0 + stag;
+		     addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
+			msrs->controls[i].addr = addr;
+		}
+	} else {
+		for (addr = MSR_P4_IQ_ESCR0 + stag;
+		     addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
+			msrs->controls[i].addr = addr;
+		}
+	}
+
+	for (addr = MSR_P4_RAT_ESCR0 + stag;
+	     addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
 		msrs->controls[i].addr = addr;
 	}
 	
@@ -553,7 +572,18 @@ static void p4_setup_ctrs(struct op_msrs
 
 	/* clear all escrs (including those outside our concern) */
 	for (addr = MSR_P4_BSU_ESCR0 + stag;
-	     addr <= MSR_P4_SSU_ESCR0; addr += addr_increment()) { 
+	     addr <  MSR_P4_IQ_ESCR0; addr += addr_increment()) {
+		wrmsr(addr, 0, 0);
+	}
+
+	/* On older models clear also MSR_P4_IQ_ESCR0/1 */
+	if (boot_cpu_data.x86_model < 0x3) {
+		wrmsr(MSR_P4_IQ_ESCR0, 0, 0);
+		wrmsr(MSR_P4_IQ_ESCR1, 0, 0);
+	}
+
+	for (addr = MSR_P4_RAT_ESCR0 + stag;
+	     addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
 		wrmsr(addr, 0, 0);
 	}
 	
_
