#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;
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;
+
#define bit(n) (1ULL << (n))
#define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1))
static const char FSB_Frequency_prop[] = "FSBFrequency";
/*
- * 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.
*/
static uint64_t
EFI_FSB_frequency(void)
boolean_t N_by_2_bus_ratio = FALSE;
/*
- * Get the FSB frequency and conversion factors.
+ * Get the FSB frequency and conversion factors from EFI.
*/
busFreq = EFI_FSB_frequency();
+
+ if (cpuid_info()->cpuid_family != CPU_FAMILY_PENTIUM_M) {
+ panic("tsc_init: unknown CPU family: 0x%X\n",
+ cpuid_info()->cpuid_family);
+ }
+
+ switch (cpuid_info()->cpuid_model) {
+ case CPUID_MODEL_NEHALEM: {
+ uint64_t cpu_mhz;
+ 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;
+
+ cpu_mhz = tscGranularity * 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);
+ "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);
/*
* Get the TSC increment. The TSC is incremented by this
* 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 (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)) != 0;
-
- } else {
- panic("rtclock_init: unknown CPU family: 0x%X\n",
- cpuid_info()->cpuid_family);
- }
-
if (N_by_2_bus_ratio)
tscFCvtt2n = busFCvtt2n * 2 / (1 + 2*tscGranularity);
else
tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n;
kprintf(" TSC: Frequency = %6d.%04dMHz, "
- "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)" : "");
+ "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
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;
}