]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/i386/tsc.c
xnu-2422.90.20.tar.gz
[apple/xnu.git] / osfmk / i386 / tsc.c
index 724bb0f9f7332c2ed8444556f335c0f49afb2f0e..f79a8fcb25e65d46338ba0cc6b0a1ecdf47fc696 100644 (file)
@@ -36,7 +36,6 @@
  */
 
 #include <platforms.h>
-#include <mach_kdb.h>
 
 #include <mach/mach_types.h>
 
 #include <mach/vm_prot.h>
 #include <vm/pmap.h>
 #include <vm/vm_kern.h>                /* for kernel_map */
-#include <i386/ipl.h>
 #include <architecture/i386/pio.h>
-#include <i386/misc_protos.h>
-#include <i386/proc_reg.h>
 #include <i386/machine_cpu.h>
-#include <i386/mp.h>
-#include <i386/cpu_data.h>
 #include <i386/cpuid.h>
+#include <i386/mp.h>
 #include <i386/machine_routines.h>
+#include <i386/proc_reg.h>
+#include <i386/tsc.h>
+#include <i386/misc_protos.h>
 #include <pexpert/pexpert.h>
 #include <machine/limits.h>
 #include <machine/commpage.h>
 #include <sys/kdebug.h>
 #include <pexpert/device_tree.h>
-#include <i386/tsc.h>
 
 uint64_t       busFCvtt2n = 0;
 uint64_t       busFCvtn2t = 0;
@@ -75,6 +72,11 @@ uint64_t     tscFCvtn2t = 0;
 uint64_t       tscGranularity = 0;
 uint64_t       bus2tsc = 0;
 uint64_t       busFreq = 0;
+uint32_t       flex_ratio = 0;
+uint32_t       flex_ratio_min = 0;
+uint32_t       flex_ratio_max = 0;
+
+uint64_t       tsc_at_boot = 0;
 
 #define bit(n)         (1ULL << (n))
 #define bitmask(h,l)   ((bit(h)|(bit(h)-1)) & ~(bit(l)-1))
@@ -90,9 +92,10 @@ uint64_t     busFreq = 0;
 #define CPU_FAMILY_PENTIUM_M   (0x6)
 
 static const char      FSB_Frequency_prop[] = "FSBFrequency";
+static const char      TSC_at_boot_prop[]   = "InitialTSC";
 /*
- * This routine extracts the front-side bus frequency in Hz from
- * the device tree.
+ * This routine extracts the bus frequency in Hz from the device tree.
+ * Also reads any initial TSC value at boot from the device tree.
  */
 static uint64_t
 EFI_FSB_frequency(void)
@@ -122,6 +125,18 @@ EFI_FSB_frequency(void)
        } else {
                kprintf("EFI_FSB_frequency: unexpected size %d\n", size);
        }
+
+       /*
+        * While we're here, see if EFI published an initial TSC value.
+        */
+       if (DTGetProperty(entry,TSC_at_boot_prop,&value,&size) == kSuccess) {
+               if (size == sizeof(uint64_t)) {
+                       tsc_at_boot = *(uint64_t *) value;
+                       kprintf("EFI_FSB_frequency: read %s value: %llu\n",
+                               TSC_at_boot_prop, tsc_at_boot);
+               }
+       }
+
        return frequency;
 }
 
@@ -132,62 +147,119 @@ EFI_FSB_frequency(void)
 void
 tsc_init(void)
 {
-       uint64_t        busFCvtInt = 0;
        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;
+               }
+       }
+
        /*
-        * Get the FSB frequency and conversion factors.
+        * Get the FSB frequency and conversion factors from EFI.
         */
        busFreq = EFI_FSB_frequency();
+
+       switch (cpuid_cpufamily()) {
+       case CPUFAMILY_INTEL_HASWELL:
+       case CPUFAMILY_INTEL_IVYBRIDGE:
+       case CPUFAMILY_INTEL_SANDYBRIDGE:
+       case CPUFAMILY_INTEL_WESTMERE:
+       case CPUFAMILY_INTEL_NEHALEM: {
+               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;
+               }
+
+               /* If EFI isn't configured correctly, use a constant 
+                * value. See 6036811.
+                */
+               if (busFreq == 0)
+                   busFreq = BASE_NHM_CLOCK_SOURCE;
+
+               break;
+            }
+       default: {
+               uint64_t        prfsts;
+
+               prfsts = rdmsr64(IA32_PERF_STS);
+               tscGranularity = (uint32_t)bitfield(prfsts, 44, 40);
+               N_by_2_bus_ratio = (prfsts & bit(46)) != 0;
+           }
+       }
+
        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");
+               panic("tsc_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);
+       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);
 
        /*
         * Get the TSC increment.  The TSC is incremented by this
         * on every bus tick.  Calculate the TSC conversion factors
         * to and from nano-seconds.
+        * The tsc granularity is also called the "bus ratio". If the N/2 bit
+        * is set this indicates the bus ration is 0.5 more than this - i.e.
+        * that the true bus ratio is (2*tscGranularity + 1)/2. If we cannot
+        * determine the TSC conversion, assume it ticks at the bus frequency.
         */
-       if (cpuid_info()->cpuid_family == CPU_FAMILY_PENTIUM_M) {
-               uint64_t        prfsts;
-
-               prfsts = rdmsr64(IA32_PERF_STS);
-               tscGranularity = (uint32_t)bitfield(prfsts, 44, 40);
-               N_by_2_bus_ratio = prfsts & bit(46);
-
-       } else {
-               panic("rtclock_init: unknown CPU family: 0x%X\n",
-                       cpuid_info()->cpuid_family);
-       }
+       if (tscGranularity == 0)
+               tscGranularity = 1;
 
        if (N_by_2_bus_ratio)
-               tscFCvtt2n = busFCvtt2n * 2 / (uint64_t)tscGranularity;
+               tscFCvtt2n = busFCvtt2n * 2 / (1 + 2*tscGranularity);
        else
-               tscFCvtt2n = busFCvtt2n / (uint64_t)tscGranularity;
+               tscFCvtt2n = busFCvtt2n / tscGranularity;
 
        tscFreq = ((1 * Giga)  << 32) / tscFCvtt2n;
        tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n;
 
-       kprintf(" TSC: Frequency = %6d.%04dMHz, "
-                       "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X, gran = %lld\n",
-                       (uint32_t)(tscFreq / Mega),
-                       (uint32_t)(tscFreq % Mega), 
-                       (uint32_t)(tscFCvtt2n >> 32), (uint32_t)tscFCvtt2n,
-                       (uint32_t)(tscFCvtn2t >> 32), (uint32_t)tscFCvtn2t,
-                       tscGranularity);
+       kprintf(" TSC: Frequency = %6d.%06dMHz, "
+               "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X, gran = %lld%s\n",
+               (uint32_t)(tscFreq / Mega),
+               (uint32_t)(tscFreq % Mega), 
+               (uint32_t)(tscFCvtt2n >> 32), (uint32_t)tscFCvtt2n,
+               (uint32_t)(tscFCvtn2t >> 32), (uint32_t)tscFCvtn2t,
+               tscGranularity, N_by_2_bus_ratio ? " (N/2)" : "");
 
        /*
         * Calculate conversion from BUS to TSC
@@ -206,4 +278,7 @@ tsc_get_info(tscInfo_t *info)
        info->tscGranularity = tscGranularity;
        info->bus2tsc        = bus2tsc;
        info->busFreq        = busFreq;
+       info->flex_ratio     = flex_ratio;
+       info->flex_ratio_min = flex_ratio_min;
+       info->flex_ratio_max = flex_ratio_max;
 }