X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/5d5c5d0d5b79ade9a973d55186ffda2638ba2b6e..b0d623f7f2ae71ed96e60569f61f9a9a27016e80:/osfmk/i386/tsc.c diff --git a/osfmk/i386/tsc.c b/osfmk/i386/tsc.c index 2253ed910..6744a9097 100644 --- a/osfmk/i386/tsc.c +++ b/osfmk/i386/tsc.c @@ -1,31 +1,29 @@ /* - * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2005-2007 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, unlawful or unlicensed copies of an Apple operating - * system, or to circumvent, violate, or enable the circumvention or - * violation of, any terms of an Apple operating system software license - * agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and * limitations under the License. - * - * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ @@ -54,23 +52,19 @@ #include #include /* for kernel_map */ #include -#include #include -#include -#include #include -#include #include -#include -#include -#include +#include #include +#include +#include +#include #include #include #include #include #include -#include uint64_t busFCvtt2n = 0; uint64_t busFCvtn2t = 0; @@ -79,6 +73,15 @@ uint64_t tscFCvtt2n = 0; 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; + + +#define bit(n) (1ULL << (n)) +#define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) +#define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) /* Decimal powers: */ #define kilo (1000ULL) @@ -87,10 +90,11 @@ uint64_t bus2tsc = 0; #define Tera (kilo * Giga) #define Peta (kilo * Tera) +#define CPU_FAMILY_PENTIUM_M (0x6) + 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) @@ -98,14 +102,15 @@ EFI_FSB_frequency(void) uint64_t frequency = 0; DTEntry entry; void *value; - int size; + unsigned int size; if (DTLookupEntry(0, "/efi/platform", &entry) != kSuccess) { kprintf("EFI_FSB_frequency: didn't find /efi/platform\n"); return 0; } if (DTGetProperty(entry,FSB_Frequency_prop,&value,&size) != kSuccess) { - kprintf("EFI_FSB_frequency: property %s not found\n"); + kprintf("EFI_FSB_frequency: property %s not found\n", + FSB_Frequency_prop); return 0; } if (size == sizeof(uint64_t)) { @@ -129,95 +134,117 @@ EFI_FSB_frequency(void) void tsc_init(void) { - 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; + uint64_t busFCvtInt = 0; + boolean_t N_by_2_bus_ratio = FALSE; + + /* + * 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: unknown CPU model: 0x%X\n", - cpuModel); + panic("tsc_init: EFI not supported!\n"); } - } else { - panic("rtclock_init: unknown CPU family: 0x%X\n", - cpuFamily); - } - - tscFCvtt2n = busFCvtt2n / (uint64_t)tscGranularity; - tscFreq = ((1 * Giga) << 32) / tscFCvtt2n; - tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n; - - kprintf(" TSC: Frequency = %6d.%04dMHz, " - "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X, gran = %d\n", - (uint32_t)(tscFreq / Mega), - (uint32_t)(tscFreq % Mega), - (uint32_t)(tscFCvtt2n >> 32), (uint32_t)tscFCvtt2n, - (uint32_t)(tscFCvtn2t >> 32), (uint32_t)tscFCvtn2t, - tscGranularity); - - /* - * Calculate conversion from BUS to TSC - */ - bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t); + + 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); + + /* + * 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 (N_by_2_bus_ratio) + tscFCvtt2n = busFCvtt2n * 2 / (1 + 2*tscGranularity); + else + tscFCvtt2n = busFCvtt2n / tscGranularity; + + tscFreq = ((1 * Giga) << 32) / tscFCvtt2n; + 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)" : ""); + + /* + * Calculate conversion from BUS to TSC + */ + bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t); } void tsc_get_info(tscInfo_t *info) { - info->busFCvtt2n = busFCvtt2n; - info->busFCvtn2t = busFCvtn2t; - info->tscFreq = tscFreq; - info->tscFCvtt2n = tscFCvtt2n; - info->tscFCvtn2t = tscFCvtn2t; - info->tscGranularity = tscGranularity; - info->bus2tsc = bus2tsc; + info->busFCvtt2n = busFCvtt2n; + info->busFCvtn2t = busFCvtn2t; + info->tscFreq = tscFreq; + info->tscFCvtt2n = tscFCvtt2n; + info->tscFCvtn2t = tscFCvtn2t; + 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; }