Subject: port-amd64/36633: Enhanced Speedstep is not enabled for Intel EM64T CPUs
To: None <port-amd64-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: Pierre Pronchery <khorben@defora.org>
List: netbsd-bugs
Date: 07/11/2007 15:50:00
>Number:         36633
>Category:       port-amd64
>Synopsis:       Enhanced Speedstep is not enabled for Intel EM64T CPUs
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-amd64-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Jul 11 15:50:00 +0000 2007
>Originator:     Pierre Pronchery
>Release:        NetBSD 4.0_BETA2
>Organization:
khorben
>Environment:
System: NetBSD syn.defora.rom 4.0_BETA2 NetBSD 4.0_BETA2 (GENERIC.MP) #26: Tue Jul 10 14:44:16 CEST 2007 khorben@syn.defora.rom:/usr/obj/sys/arch/amd64/compile/GENERIC.MP amd64
Architecture: x86_64
Machine: amd64
>Description:

Generally speaking, the amd64 port's default kernel is not very friendly
to laptops. Enhanced Speedstep in particular is not supported for Intel
machines featuring this instruction set (eg Core 2 Duo "Merom").

>How-To-Repeat:

Boot an amd64 kernel on an EM64T machine.

>Fix:

The following patch works for me (Intel Core 2 Duo). It applies against
4.0_BETA2. It will certainly require additional cosmetics (estd.c moved
to arch/x86, etc).

It also contains my GENERIC.local file, which could be made separate in
a GENERIC_LAPTOP file.

Index: arch/amd64/amd64/identcpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/identcpu.c,v
retrieving revision 1.7.2.2
diff -u -r1.7.2.2 identcpu.c
--- arch/amd64/amd64/identcpu.c	15 Jun 2007 10:27:36 -0000	1.7.2.2
+++ arch/amd64/amd64/identcpu.c	11 Jul 2007 11:03:46 -0000
@@ -52,6 +52,104 @@
 /* sysctl wants this. */
 char cpu_model[48];
 
+#ifdef ENHANCED_SPEEDSTEP
+void p3_get_bus_clock(struct cpu_info *ci);
+void p3_get_bus_clock(struct cpu_info *ci)
+{
+	uint64_t msr;
+	int model, bus;
+	char *cpuname = ci->ci_dev->dv_xname;
+
+	model = (ci->ci_signature >> 4) & 15;
+	switch (model) {
+	case 0x9: /* Pentium M (130 nm, Banias) */
+		bus_clock = 10000;
+		break;
+	case 0xd: /* Pentium M (90 nm, Dothan) */
+		msr = rdmsr(MSR_FSB_FREQ);
+		bus = (msr >> 0) & 0x7;
+		switch (bus) {
+		case 0:
+			bus_clock = 10000;
+			break;
+		case 1:
+			bus_clock = 13333;
+			break;
+		default:
+			aprint_debug("%s: unknown Pentium M FSB_FREQ "
+			    "value %d", cpuname, bus);
+			goto print_msr;
+		}
+		break;
+	case 0xe: /* Core Duo/Solo */
+	case 0xf: /* Core Xeon */
+		msr = rdmsr(MSR_FSB_FREQ);
+		bus = (msr >> 0) & 0x7;
+		switch (bus) {
+		case 5:
+			bus_clock = 10000;
+			break;
+		case 1:
+			bus_clock = 13333;
+			break;
+		case 3:
+			bus_clock = 16667;
+			break;
+		case 2:
+			bus_clock = 20000;
+			break;
+		case 0:
+			bus_clock = 26667;
+			break;
+		case 4:
+			bus_clock = 33333;
+			break;
+		default:
+			aprint_debug("%s: unknown Core FSB_FREQ value %d",
+			    cpuname, bus);
+			goto print_msr;
+		}
+		break;
+	case 0x1: /* Pentium Pro, model 1 */
+	case 0x3: /* Pentium II, model 3 */
+	case 0x5: /* Pentium II, II Xeon, Celeron, model 5 */
+	case 0x6: /* Celeron, model 6 */
+	case 0x7: /* Pentium III, III Xeon, model 7 */
+	case 0x8: /* Pentium III, III Xeon, Celeron, model 8 */
+	case 0xa: /* Pentium III Xeon, model A */
+	case 0xb: /* Pentium III, model B */
+		msr = rdmsr(MSR_EBL_CR_POWERON);
+		bus = (msr >> 18) & 0x3;
+		switch (bus) {
+		case 0:
+			bus_clock = 6666;
+			break;
+		case 1:
+			bus_clock = 13333;
+			break;
+		case 2:
+			bus_clock = 10000;
+			break;
+		default:
+			aprint_debug("%s: unknown i686 EBL_CR_POWERON "
+			    "value %d ", cpuname, bus);
+			goto print_msr;
+		}
+		break;
+	default:
+		aprint_debug("%s: unknown i686 model %d, can't get bus clock",
+		    cpuname, model);
+print_msr:
+		/*
+		 * Show the EBL_CR_POWERON MSR, so we'll at least have
+		 * some extra information, such as clock ratio, etc.
+		 */
+		aprint_debug(" (0x%lx)\n", rdmsr(MSR_EBL_CR_POWERON));
+		break;
+	}
+}
+#endif
+
 void
 identifycpu(struct cpu_info *ci)
 {
@@ -139,6 +237,24 @@
 
 	x86_print_cacheinfo(ci);
 
+#ifdef ENHANCED_SPEEDSTEP
+	aprint_verbose("%s: probing Enhanced SpeedStep\n",
+			ci->ci_dev->dv_xname);
+	if (ci->ci_feature2_flags & CPUID2_EST) {
+		if (rdmsr(MSR_MISC_ENABLE) & (1 << 16))
+		{
+			p3_get_bus_clock(ci);
+			est_init(CPUVENDOR_INTEL);
+		}
+		else
+			aprint_verbose("%s: Enhanced SpeedStep disabled by BIOS\n",
+					ci->ci_dev->dv_xname);
+	}
+	else
+		aprint_verbose("%s: Enhanced SpeedStep not found\n",
+				ci->ci_dev->dv_xname);
+#endif /* ENHANCED_SPEEDSTEP */
+
 #ifdef POWERNOW_K8
 	if (CPUID2FAMILY(ci->ci_signature) == 15 &&
 	    (cpu_model[0] == 'A' || cpu_model[0] == 'O') &&
Index: arch/amd64/conf/GENERIC.local
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/conf/GENERIC.local,v
retrieving revision 1.1
diff -u -r1.1 GENERIC.local
--- arch/amd64/conf/GENERIC.local	26 Apr 2003 18:39:34 -0000	1.1
+++ arch/amd64/conf/GENERIC.local	11 Jul 2007 11:03:46 -0000
@@ -3,3 +3,46 @@
 #	GENERIC.local -- local additions to the GENERIC configuration
 #
 
+acpiacad* 	at acpi?
+acpibat* 	at acpi?
+acpibut* 	at acpi?
+acpiec* 	at acpi?
+acpilid* 	at acpi?
+acpitz* 	at acpi?
+
+com*		at acpi?
+fdc*		at acpi?
+joy*		at acpi?
+lpt*		at acpi?
+mpu*		at acpi?
+pckbc*		at acpi?
+attimer*	at acpi?
+pcppi*		at acpi?
+ug*		at acpi?
+wss*		at acpi?
+
+#agp*		at pchb?
+
+cbb*		at pci? dev ? function ?
+cardslot*	at cbb?
+
+cardbus*	at cardslot?
+pcmcia*		at cardslot?
+
+com*		at pcmcia? function ?
+
+com*		at cardbus? function ?
+
+wdc*		at pcmcia? function ?
+
+wi*		at pcmcia? function ?
+
+ehci*		at cardbus? function ?
+ohci*		at cardbus? function ?
+
+cdce*	at uhub? port ?
+wpi*	at pci? dev ? function ?
+
+options		ENHANCED_SPEEDSTEP
+
+pseudo-device	cgd		4	# cryptographic disk devices
Index: arch/amd64/conf/files.amd64
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/conf/files.amd64,v
retrieving revision 1.29
diff -u -r1.29 files.amd64
--- arch/amd64/conf/files.amd64	10 Sep 2006 19:50:48 -0000	1.29
+++ arch/amd64/conf/files.amd64	11 Jul 2007 11:03:47 -0000
@@ -201,4 +201,8 @@
 include "dev/acpi/files.acpi"
 file	arch/amd64/acpi/acpi_wakeup.c	acpi
 
+# Enhanced SpeedStep
+file	arch/i386/i386/est.c		enhanced_speedstep
+defflag	opt_est.h	EST_FREQ_USERWRITE
+
 include	"arch/amd64/conf/majors.amd64"
Index: arch/amd64/include/cpu.h
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/include/cpu.h,v
retrieving revision 1.12.8.1
diff -u -r1.12.8.1 cpu.h
--- arch/amd64/include/cpu.h	5 Jun 2007 20:28:11 -0000	1.12.8.1
+++ arch/amd64/include/cpu.h	11 Jul 2007 11:03:47 -0000
@@ -244,6 +244,7 @@
 /*
  * pull in #defines for kinds of processors
  */
+#include <machine/cputypes.h>
 
 extern int biosbasemem;
 extern int biosextmem;
@@ -255,6 +256,9 @@
 
 /* identcpu.c */
 
+#ifdef ENHANCED_SPEEDSTEP
+extern int bus_clock;
+#endif
 void	identifycpu __P((struct cpu_info *));
 void cpu_probe_features __P((struct cpu_info *));
 
@@ -302,6 +306,9 @@
 /* powernow_k8.c */
 void k8_powernow_init(void);
 
+/* est.c */
+void	est_init(int);
+
 #endif /* _KERNEL */
 
 #include <machine/psl.h>
Index: arch/i386/i386/est.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/Attic/est.c,v
retrieving revision 1.31.2.2
diff -u -r1.31.2.2 est.c
--- arch/i386/i386/est.c	20 Apr 2007 20:31:25 -0000	1.31.2.2
+++ arch/i386/i386/est.c	11 Jul 2007 11:04:06 -0000
@@ -952,7 +952,7 @@
 	if (idhi == 0 || idlo == 0 || cur == 0 ||
 	    ((cur >> 8) & 0xff) < ((idlo >> 8) & 0xff) ||
 	    ((cur >> 8) & 0xff) > ((idhi >> 8) & 0xff)) {
-		aprint_debug("%s: strange msr value 0x%016llx\n", __func__, msr);
+		aprint_debug("%s: strange msr value 0x%016lx\n", __func__, msr);
 		return;
 	}