summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorjkim <jkim@FreeBSD.org>2011-04-12 23:04:01 +0000
committerjkim <jkim@FreeBSD.org>2011-04-12 23:04:01 +0000
commit218c7113eda7be885de958c079152f70afe24ad9 (patch)
tree32c006d3850d3958b17e9567cbf9d124b9917034 /sys/i386
parentc14cd58282c1241f10c3b38c4ca228eff76f0249 (diff)
downloadFreeBSD-src-218c7113eda7be885de958c079152f70afe24ad9.zip
FreeBSD-src-218c7113eda7be885de958c079152f70afe24ad9.tar.gz
Reinstate cpu_est_clockrate() support for P-state invariant TSC if APERF and
MPERF MSRs are available. It was disabled in r216443. Remove the earlier hack to subtract 0.5% from the calibrated frequency as DELAY(9) is little bit more reliable now.
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/machdep.c49
1 files changed, 24 insertions, 25 deletions
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 5869c21..50ca5fd 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -1136,25 +1136,22 @@ cpu_flush_dcache(void *ptr, size_t len)
int
cpu_est_clockrate(int cpu_id, uint64_t *rate)
{
+ uint64_t tsc1, tsc2;
+ uint64_t acnt, mcnt;
register_t reg;
- uint64_t freq, tsc1, tsc2;
if (pcpu_find(cpu_id) == NULL || rate == NULL)
return (EINVAL);
if ((cpu_feature & CPUID_TSC) == 0)
return (EOPNOTSUPP);
- freq = atomic_load_acq_64(&tsc_freq);
- /* If TSC is P-state invariant, DELAY(9) based logic fails. */
- if (tsc_is_invariant && freq != 0)
+ /*
+ * If TSC is P-state invariant and APERF/MPERF MSRs do not exist,
+ * DELAY(9) based logic fails.
+ */
+ if (tsc_is_invariant && !tsc_perf_stat)
return (EOPNOTSUPP);
- /* If we're booting, trust the rate calibrated moments ago. */
- if (cold && freq != 0) {
- *rate = freq;
- return (0);
- }
-
#ifdef SMP
if (smp_cpus > 1) {
/* Schedule ourselves on the indicated cpu. */
@@ -1166,10 +1163,23 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate)
/* Calibrate by measuring a short delay. */
reg = intr_disable();
- tsc1 = rdtsc();
- DELAY(1000);
- tsc2 = rdtsc();
- intr_restore(reg);
+ if (tsc_is_invariant) {
+ wrmsr(MSR_MPERF, 0);
+ wrmsr(MSR_APERF, 0);
+ tsc1 = rdtsc();
+ DELAY(1000);
+ mcnt = rdmsr(MSR_MPERF);
+ acnt = rdmsr(MSR_APERF);
+ tsc2 = rdtsc();
+ intr_restore(reg);
+ *rate = (tsc2 - tsc1) / 1000 * acnt / mcnt * 1000000;
+ } else {
+ tsc1 = rdtsc();
+ DELAY(1000);
+ tsc2 = rdtsc();
+ intr_restore(reg);
+ *rate = (tsc2 - tsc1) * 1000;
+ }
#ifdef SMP
if (smp_cpus > 1) {
@@ -1179,17 +1189,6 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate)
}
#endif
- tsc2 -= tsc1;
- if (freq != 0) {
- *rate = tsc2 * 1000;
- return (0);
- }
-
- /*
- * Subtract 0.5% of the total. Empirical testing has shown that
- * overhead in DELAY() works out to approximately this value.
- */
- *rate = tsc2 * 1000 - tsc2 * 5;
return (0);
}
OpenPOWER on IntegriCloud