Module Name:    src
Committed By:   msaitoh
Date:           Sun Dec  8 04:07:38 UTC 2013

Modified Files:
        src/sys/arch/x86/x86: tsc.c

Log Message:
 Update invariant TSC detect code from both Intel and AMD documents.
The best way to check whether the TSC counter is invariant or not is to check
CPUID 80000007.


To generate a diff of this commit:
cvs rdiff -u -r1.33 -r1.34 src/sys/arch/x86/x86/tsc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/x86/tsc.c
diff -u src/sys/arch/x86/x86/tsc.c:1.33 src/sys/arch/x86/x86/tsc.c:1.34
--- src/sys/arch/x86/x86/tsc.c:1.33	Fri Nov 15 08:47:55 2013
+++ src/sys/arch/x86/x86/tsc.c	Sun Dec  8 04:07:38 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: tsc.c,v 1.33 2013/11/15 08:47:55 msaitoh Exp $	*/
+/*	$NetBSD: tsc.c,v 1.34 2013/12/08 04:07:38 msaitoh Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tsc.c,v 1.33 2013/11/15 08:47:55 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tsc.c,v 1.34 2013/12/08 04:07:38 msaitoh Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -68,14 +68,15 @@ tsc_tc_init(void)
 {
 	struct cpu_info *ci;
 	uint32_t descs[4];
-	bool safe;
+	uint32_t family;
+	bool invariant;
 
 	if (!cpu_hascounter()) {
 		return;
 	}
 
 	ci = curcpu();
-	safe = false;
+	invariant = false;
 	tsc_freq = ci->ci_data.cpu_cc_freq;
 	tsc_good = (cpu_feature[0] & CPUID_MSR) != 0 &&
 	    (rdmsr(MSR_TSC) != 0 || rdmsr(MSR_TSC) != 0);
@@ -84,28 +85,32 @@ tsc_tc_init(void)
 		/*
 		 * From Intel(tm) 64 and IA-32 Architectures Software
 		 * Developer's Manual Volume 3A: System Programming Guide,
-		 * Part 1 Order Number: 253668-026US February 2008, these
-		 * are the processors where the TSC is known safe:
+		 * Part 1, 17.13 TIME_STAMP COUNTER, these are the processors
+		 * where the TSC is known invariant:
 		 *
 		 * Pentium 4, Intel Xeon (family 0f, models 03 and higher)
 		 * Core Solo and Core Duo processors (family 06, model 0e)
 		 * Xeon 5100 series and Core 2 Duo (family 06, model 0f)
+		 * Core 2 and Xeon (family 06, model 17)
+		 * Atom (family 06, model 1c)
 		 *
 		 * We'll also assume that it's safe on the Pentium, and
 		 * that it's safe on P-II and P-III Xeons due to the
 		 * typical configuration of those systems.
+		 *
 		 */
 		switch (CPUID_TO_BASEFAMILY(ci->ci_signature)) {
 		case 0x05:
-			safe = true;
+			invariant = true;
 			break;
 		case 0x06:
-			safe = CPUID_TO_MODEL(ci->ci_signature) == 0x0e ||
+			invariant = CPUID_TO_MODEL(ci->ci_signature) == 0x0e ||
 			    CPUID_TO_MODEL(ci->ci_signature) == 0x0f ||
-			    CPUID_TO_MODEL(ci->ci_signature) == 0x0a;
+			    CPUID_TO_MODEL(ci->ci_signature) == 0x17 ||
+			    CPUID_TO_MODEL(ci->ci_signature) == 0x1c;
 			break;
 		case 0x0f:
-			safe = CPUID_TO_MODEL(ci->ci_signature) >= 0x03;
+			invariant = CPUID_TO_MODEL(ci->ci_signature) >= 0x03;
 			break;
 		}
 	} else if (cpu_vendor == CPUVENDOR_AMD) {
@@ -114,36 +119,35 @@ tsc_tc_init(void)
 		 * Nov 2, 2005 Rich Brunner, AMD Fellow
 		 * http://lkml.org/lkml/2005/11/4/173
 		 *
-		 * There are a lot of recommendations in this note.
-		 * We're only going to follow the simple, reliable
-		 * ones.
+		 * See Appendix E.4.7 CPUID Fn8000_0007_EDX Advanced Power
+		 * Management Features, AMD64 Architecture ProgrammerVolume 3:
+		 * General-Purpose and System Instructions. The check is
+		 * done below.
 		 */
-		switch (CPUID_TO_BASEFAMILY(ci->ci_signature)) {
-		case 0x06:
-		case 0x07:
-			/*
-			 * TSC is fine, apart from P-state changes.
-			 * The PowerNow code need hooks to disable
-			 * the TSC if the user modifies operating
-			 * parameters.  For now, punt.  XXX
-			 */
-			break;
-		case 0x0f:
-			/* Check for "invariant TSC", bit 8 of %edx. */
+	}
+
+	/*
+	 * The best way to check whether the TSC counter is invariant or not
+	 * is to check CPUID 80000007.
+	 */
+	family = CPUID_TO_BASEFAMILY(ci->ci_signature);
+	if (((cpu_vendor == CPUVENDOR_INTEL) || (cpu_vendor == CPUVENDOR_AMD))
+	    && ((family == 0x06) || (family == 0x0f))) {
+		x86_cpuid(0x80000000, descs);
+		if (descs[0] >= 0x80000007) {
 			x86_cpuid(0x80000007, descs);
-			safe = (descs[3] & CPUID_APM_TSC) != 0;
-			break;
+			invariant = (descs[3] & CPUID_APM_TSC) != 0;
 		}
 	}
 
-	if (!safe) {
-		aprint_debug("TSC not known safe on this CPU\n");
+	if (!invariant) {
+		aprint_debug("TSC not known invariant on this CPU\n");
 		tsc_timecounter.tc_quality = -100;
 	} else if (tsc_drift_observed > tsc_drift_max) {
 		aprint_error("ERROR: %lld cycle TSC drift observed\n",
 		    (long long)tsc_drift_observed);
 		tsc_timecounter.tc_quality = -100;
-		safe = false;
+		invariant = false;
 	}
 
 	if (tsc_freq != 0) {

Reply via email to