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>