- uint64_t busFreq;
- uint64_t busFCvtInt;
- uint32_t cpuModel;
- uint32_t cpuFamily;
- uint32_t xcpuid[4];
-
- /*
- * Get the FSB frequency and conversion factors.
- */
- busFreq = EFI_FSB_frequency();
- if (busFreq != 0) {
- busFCvtt2n = ((1 * Giga) << 32) / busFreq;
- busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n;
- busFCvtInt = tmrCvt(1 * Peta, 0xFFFFFFFFFFFFFFFFULL / busFreq);
- } else {
- panic("rtclock_init: EFI not supported!\n");
- }
-
- kprintf(" BUS: Frequency = %6d.%04dMHz, "
- "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X, "
- "cvtInt = %08X.%08X\n",
- (uint32_t)(busFreq / Mega),
- (uint32_t)(busFreq % Mega),
- (uint32_t)(busFCvtt2n >> 32), (uint32_t)busFCvtt2n,
- (uint32_t)(busFCvtn2t >> 32), (uint32_t)busFCvtn2t,
- (uint32_t)(busFCvtInt >> 32), (uint32_t)busFCvtInt);
-
- do_cpuid(1, xcpuid);
- cpuFamily = ( xcpuid[eax] >> 8 ) & 0xf;
- /*
- * Get the extended family if necessary.
- */
- if (cpuFamily == 0x0f)
- cpuFamily += (xcpuid[eax] >> 20) & 0x00ff;
-
- cpuModel = ( xcpuid[eax] >> 4 ) & 0xf;
- /*
- * Get the extended model if necessary.
- */
- if (cpuFamily == CPUID_FAMILY_686
- || cpuFamily == CPUID_FAMILY_EXTENDED)
- cpuModel += ((xcpuid[eax] >> 16) & 0xf) << 4;
-
- /*
- * Get the TSC increment. The TSC is incremented by this
- * on every bus tick. Calculate the TSC conversion factors
- * to and from nano-seconds.
- */
- if (cpuFamily == CPUID_FAMILY_686) {
- if (cpuModel == CPUID_MODEL_CORE || cpuModel == CPUID_MODEL_CORE2) {
- uint64_t prfsts;
-
- prfsts = rdmsr64(IA32_PERF_STS);
- tscGranularity = (uint32_t)(prfsts >> BusRatioShift) & BusRatioMask;
+ boolean_t N_by_2_bus_ratio = FALSE;
+
+ if (cpuid_vmm_present()) {
+ kprintf("VMM vendor %u TSC frequency %u KHz bus frequency %u KHz\n",
+ cpuid_vmm_info()->cpuid_vmm_family,
+ cpuid_vmm_info()->cpuid_vmm_tsc_frequency,
+ cpuid_vmm_info()->cpuid_vmm_bus_frequency);
+
+ if (cpuid_vmm_info()->cpuid_vmm_tsc_frequency &&
+ cpuid_vmm_info()->cpuid_vmm_bus_frequency) {
+
+ busFreq = (uint64_t)cpuid_vmm_info()->cpuid_vmm_bus_frequency * kilo;
+ busFCvtt2n = ((1 * Giga) << 32) / busFreq;
+ busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n;
+
+ tscFreq = (uint64_t)cpuid_vmm_info()->cpuid_vmm_tsc_frequency * kilo;
+ tscFCvtt2n = ((1 * Giga) << 32) / tscFreq;
+ tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n;
+
+ tscGranularity = tscFreq / busFreq;
+
+ bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t);
+
+ return;
+ }
+ }
+
+ switch (cpuid_cpufamily()) {
+ case CPUFAMILY_INTEL_KABYLAKE:
+ case CPUFAMILY_INTEL_SKYLAKE: {
+ /*
+ * SkyLake and later has an Always Running Timer (ART) providing
+ * the reference frequency. CPUID leaf 0x15 determines the
+ * rationship between this and the TSC frequency expressed as
+ * - multiplier (numerator, N), and
+ * - divisor (denominator, M).
+ * So that TSC = ART * N / M.
+ */
+ cpuid_tsc_leaf_t *tsc_leafp = &cpuid_info()->cpuid_tsc_leaf;
+ uint64_t N = (uint64_t) tsc_leafp->numerator;
+ uint64_t M = (uint64_t) tsc_leafp->denominator;
+ uint64_t refFreq;
+
+ refFreq = EFI_get_frequency("ARTFrequency");
+ if (refFreq == 0)
+ refFreq = BASE_ART_CLOCK_SOURCE;
+
+ assert(N != 0);
+ assert(M != 1);
+ tscFreq = refFreq * N / M;
+ busFreq = tscFreq; /* bus is APIC frequency */
+
+ kprintf(" ART: Frequency = %6d.%06dMHz, N/M = %lld/%llu\n",
+ (uint32_t)(refFreq / Mega),
+ (uint32_t)(refFreq % Mega),
+ N, M);
+
+ break;
+ }
+ default: {
+ uint64_t msr_flex_ratio;
+ uint64_t msr_platform_info;
+
+ /* See if FLEX_RATIO is being used */
+ msr_flex_ratio = rdmsr64(MSR_FLEX_RATIO);
+ msr_platform_info = rdmsr64(MSR_PLATFORM_INFO);
+ flex_ratio_min = (uint32_t)bitfield(msr_platform_info, 47, 40);
+ flex_ratio_max = (uint32_t)bitfield(msr_platform_info, 15, 8);
+ /* No BIOS-programed flex ratio. Use hardware max as default */
+ tscGranularity = flex_ratio_max;
+ if (msr_flex_ratio & bit(16)) {
+ /* Flex Enabled: Use this MSR if less than max */
+ flex_ratio = (uint32_t)bitfield(msr_flex_ratio, 15, 8);
+ if (flex_ratio < flex_ratio_max)
+ tscGranularity = flex_ratio;
+ }
+
+ busFreq = EFI_get_frequency("FSBFrequency");
+ /* If EFI isn't configured correctly, use a constant
+ * value. See 6036811.
+ */
+ if (busFreq == 0)
+ busFreq = BASE_NHM_CLOCK_SOURCE;
+
+ break;
+ }
+ case CPUFAMILY_INTEL_PENRYN: {
+ uint64_t prfsts;
+
+ prfsts = rdmsr64(IA32_PERF_STS);
+ tscGranularity = (uint32_t)bitfield(prfsts, 44, 40);
+ N_by_2_bus_ratio = (prfsts & bit(46)) != 0;
+
+ busFreq = EFI_get_frequency("FSBFrequency");
+ }
+ }
+
+ if (busFreq != 0) {
+ busFCvtt2n = ((1 * Giga) << 32) / busFreq;
+ busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n;
+ } else {
+ panic("tsc_init: EFI not supported!\n");
+ }
+
+ kprintf(" BUS: Frequency = %6d.%06dMHz, "
+ "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X\n",
+ (uint32_t)(busFreq / Mega),
+ (uint32_t)(busFreq % Mega),
+ (uint32_t)(busFCvtt2n >> 32), (uint32_t)busFCvtt2n,
+ (uint32_t)(busFCvtn2t >> 32), (uint32_t)busFCvtn2t);
+
+ if (tscFreq == busFreq) {
+ bus2tsc = 1;
+ tscGranularity = 1;
+ tscFCvtn2t = busFCvtn2t;
+ tscFCvtt2n = busFCvtt2n;