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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to