Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Apr 2011 21:08:35 +0000 (UTC)
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r220577 - head/sys/x86/x86
Message-ID:  <201104122108.p3CL8ZaP035670@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jkim
Date: Tue Apr 12 21:08:34 2011
New Revision: 220577
URL: http://svn.freebsd.org/changeset/base/220577

Log:
  Add a new tunable 'machdep.disable_tsc_calibration' to allow skipping TSC
  frequency calibration.  For Intel processors, if brand string from CPUID
  contains its nominal frequency, this frequency is used instead.

Modified:
  head/sys/x86/x86/tsc.c

Modified: head/sys/x86/x86/tsc.c
==============================================================================
--- head/sys/x86/x86/tsc.c	Tue Apr 12 20:50:57 2011	(r220576)
+++ head/sys/x86/x86/tsc.c	Tue Apr 12 21:08:34 2011	(r220577)
@@ -67,6 +67,11 @@ SYSCTL_INT(_machdep, OID_AUTO, disable_t
     "Disable x86 Time Stamp Counter");
 TUNABLE_INT("machdep.disable_tsc", &tsc_disabled);
 
+static int	tsc_skip_calibration;
+SYSCTL_INT(_machdep, OID_AUTO, disable_tsc_calibration, CTLFLAG_RDTUN,
+    &tsc_skip_calibration, 0, "Disable TSC frequency calibration");
+TUNABLE_INT("machdep.disable_tsc_calibration", &tsc_skip_calibration);
+
 static void tsc_freq_changed(void *arg, const struct cf_level *level,
     int status);
 static void tsc_freq_changing(void *arg, const struct cf_level *level,
@@ -83,24 +88,70 @@ static struct timecounter tsc_timecounte
 	800,			/* quality (adjusted in code) */
 };
 
-void
-init_TSC(void)
+static void
+tsc_freq_intel(void)
 {
-	u_int64_t tscval[2];
-
-	if ((cpu_feature & CPUID_TSC) == 0 || tsc_disabled)
-		return;
-
-	if (bootverbose)
-	        printf("Calibrating TSC clock ... ");
+	char brand[48];
+	u_int regs[4];
+	uint64_t freq;
+	char *p;
+	u_int i;
 
-	tscval[0] = rdtsc();
-	DELAY(1000000);
-	tscval[1] = rdtsc();
+	/*
+	 * Intel Processor Identification and the CPUID Instruction
+	 * Application Note 485.
+	 *
+	 * http://www.intel.com/assets/pdf/appnote/241618.pdf
+	 */
+	if (cpu_exthigh >= 0x80000004) {
+		p = brand;
+		for (i = 0x80000002; i < 0x80000005; i++) {
+			do_cpuid(i, regs);
+			memcpy(p, regs, sizeof(regs));
+			p += sizeof(regs);
+		}
+		p = NULL;
+		for (i = 0; i < sizeof(brand) - 1; i++)
+			if (brand[i] == 'H' && brand[i + 1] == 'z')
+				p = brand + i;
+		if (p != NULL) {
+			p -= 5;
+			switch (p[4]) {
+			case 'M':
+				i = 1;
+				break;
+			case 'G':
+				i = 1000;
+				break;
+			case 'T':
+				i = 1000000;
+				break;
+			default:
+				return;
+			}
+#define	C2D(c)	((c) - '0')
+			if (p[1] == '.') {
+				freq = C2D(p[0]) * 1000;
+				freq += C2D(p[2]) * 100;
+				freq += C2D(p[3]) * 10;
+				freq *= i * 1000;
+			} else {
+				freq = C2D(p[0]) * 1000;
+				freq += C2D(p[1]) * 100;
+				freq += C2D(p[2]) * 10;
+				freq += C2D(p[3]);
+				freq *= i * 1000000;
+			}
+#undef C2D
+			tsc_freq = freq;
+		}
+	}
+}
 
-	tsc_freq = tscval[1] - tscval[0];
-	if (bootverbose)
-		printf("TSC clock: %ju Hz\n", (intmax_t)tsc_freq);
+static void
+probe_tsc_freq(void)
+{
+	uint64_t tsc1, tsc2;
 
 	switch (cpu_vendor_id) {
 	case CPU_VENDOR_AMD:
@@ -127,12 +178,38 @@ init_TSC(void)
 		break;
 	}
 
+	if (tsc_skip_calibration) {
+		if (cpu_vendor_id == CPU_VENDOR_INTEL)
+			tsc_freq_intel();
+		return;
+	}
+
+	if (bootverbose)
+	        printf("Calibrating TSC clock ... ");
+	tsc1 = rdtsc();
+	DELAY(1000000);
+	tsc2 = rdtsc();
+	tsc_freq = tsc2 - tsc1;
+	if (bootverbose)
+		printf("TSC clock: %ju Hz\n", (intmax_t)tsc_freq);
+}
+
+void
+init_TSC(void)
+{
+
+	if ((cpu_feature & CPUID_TSC) == 0 || tsc_disabled)
+		return;
+
+	probe_tsc_freq();
+
 	/*
 	 * Inform CPU accounting about our boot-time clock rate.  This will
 	 * be updated if someone loads a cpufreq driver after boot that
 	 * discovers a new max frequency.
 	 */
-	set_cputicker(rdtsc, tsc_freq, 1);
+	if (tsc_freq != 0)
+		set_cputicker(rdtsc, tsc_freq, 1);
 
 	if (tsc_is_invariant)
 		return;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201104122108.p3CL8ZaP035670>