]>
Commit | Line | Data |
---|---|---|
0c530ab8 | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2005-2007 Apple Inc. All rights reserved. |
0c530ab8 | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0c530ab8 | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0c530ab8 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
0c530ab8 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
0c530ab8 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
0c530ab8 A |
27 | */ |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | ||
32 | /* | |
33 | * File: i386/tsc.c | |
34 | * Purpose: Initializes the TSC and the various conversion | |
35 | * factors needed by other parts of the system. | |
36 | */ | |
37 | ||
38 | #include <platforms.h> | |
0c530ab8 A |
39 | |
40 | #include <mach/mach_types.h> | |
41 | ||
42 | #include <kern/cpu_data.h> | |
43 | #include <kern/cpu_number.h> | |
44 | #include <kern/clock.h> | |
45 | #include <kern/host_notify.h> | |
46 | #include <kern/macro_help.h> | |
47 | #include <kern/misc_protos.h> | |
48 | #include <kern/spl.h> | |
49 | #include <kern/assert.h> | |
50 | #include <mach/vm_prot.h> | |
51 | #include <vm/pmap.h> | |
52 | #include <vm/vm_kern.h> /* for kernel_map */ | |
0c530ab8 | 53 | #include <architecture/i386/pio.h> |
0c530ab8 | 54 | #include <i386/machine_cpu.h> |
2d21ac55 | 55 | #include <i386/cpuid.h> |
b0d623f7 | 56 | #include <i386/mp.h> |
0c530ab8 | 57 | #include <i386/machine_routines.h> |
b0d623f7 A |
58 | #include <i386/proc_reg.h> |
59 | #include <i386/tsc.h> | |
60 | #include <i386/misc_protos.h> | |
0c530ab8 A |
61 | #include <pexpert/pexpert.h> |
62 | #include <machine/limits.h> | |
63 | #include <machine/commpage.h> | |
64 | #include <sys/kdebug.h> | |
65 | #include <pexpert/device_tree.h> | |
0c530ab8 A |
66 | |
67 | uint64_t busFCvtt2n = 0; | |
68 | uint64_t busFCvtn2t = 0; | |
69 | uint64_t tscFreq = 0; | |
70 | uint64_t tscFCvtt2n = 0; | |
71 | uint64_t tscFCvtn2t = 0; | |
72 | uint64_t tscGranularity = 0; | |
73 | uint64_t bus2tsc = 0; | |
2d21ac55 | 74 | uint64_t busFreq = 0; |
593a1d5f A |
75 | uint32_t flex_ratio = 0; |
76 | uint32_t flex_ratio_min = 0; | |
77 | uint32_t flex_ratio_max = 0; | |
78 | ||
2d21ac55 A |
79 | |
80 | #define bit(n) (1ULL << (n)) | |
81 | #define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) | |
82 | #define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) | |
0c530ab8 A |
83 | |
84 | /* Decimal powers: */ | |
85 | #define kilo (1000ULL) | |
86 | #define Mega (kilo * kilo) | |
87 | #define Giga (kilo * Mega) | |
88 | #define Tera (kilo * Giga) | |
89 | #define Peta (kilo * Tera) | |
90 | ||
2d21ac55 A |
91 | #define CPU_FAMILY_PENTIUM_M (0x6) |
92 | ||
0c530ab8 A |
93 | static const char FSB_Frequency_prop[] = "FSBFrequency"; |
94 | /* | |
593a1d5f | 95 | * This routine extracts the bus frequency in Hz from the device tree. |
0c530ab8 A |
96 | */ |
97 | static uint64_t | |
98 | EFI_FSB_frequency(void) | |
99 | { | |
100 | uint64_t frequency = 0; | |
101 | DTEntry entry; | |
102 | void *value; | |
2d21ac55 | 103 | unsigned int size; |
0c530ab8 A |
104 | |
105 | if (DTLookupEntry(0, "/efi/platform", &entry) != kSuccess) { | |
106 | kprintf("EFI_FSB_frequency: didn't find /efi/platform\n"); | |
107 | return 0; | |
108 | } | |
109 | if (DTGetProperty(entry,FSB_Frequency_prop,&value,&size) != kSuccess) { | |
2d21ac55 A |
110 | kprintf("EFI_FSB_frequency: property %s not found\n", |
111 | FSB_Frequency_prop); | |
0c530ab8 A |
112 | return 0; |
113 | } | |
114 | if (size == sizeof(uint64_t)) { | |
115 | frequency = *(uint64_t *) value; | |
116 | kprintf("EFI_FSB_frequency: read %s value: %llu\n", | |
117 | FSB_Frequency_prop, frequency); | |
118 | if (!(90*Mega < frequency && frequency < 10*Giga)) { | |
119 | kprintf("EFI_FSB_frequency: value out of range\n"); | |
120 | frequency = 0; | |
121 | } | |
122 | } else { | |
123 | kprintf("EFI_FSB_frequency: unexpected size %d\n", size); | |
124 | } | |
125 | return frequency; | |
126 | } | |
127 | ||
128 | /* | |
129 | * Initialize the various conversion factors needed by code referencing | |
130 | * the TSC. | |
131 | */ | |
132 | void | |
133 | tsc_init(void) | |
134 | { | |
2d21ac55 A |
135 | boolean_t N_by_2_bus_ratio = FALSE; |
136 | ||
316670eb A |
137 | if (cpuid_vmm_present()) { |
138 | kprintf("VMM vendor %u TSC frequency %u KHz bus frequency %u KHz\n", | |
139 | cpuid_vmm_info()->cpuid_vmm_family, | |
140 | cpuid_vmm_info()->cpuid_vmm_tsc_frequency, | |
141 | cpuid_vmm_info()->cpuid_vmm_bus_frequency); | |
142 | ||
143 | if (cpuid_vmm_info()->cpuid_vmm_tsc_frequency && | |
144 | cpuid_vmm_info()->cpuid_vmm_bus_frequency) { | |
145 | ||
146 | busFreq = (uint64_t)cpuid_vmm_info()->cpuid_vmm_bus_frequency * kilo; | |
147 | busFCvtt2n = ((1 * Giga) << 32) / busFreq; | |
148 | busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n; | |
149 | ||
150 | tscFreq = (uint64_t)cpuid_vmm_info()->cpuid_vmm_tsc_frequency * kilo; | |
151 | tscFCvtt2n = ((1 * Giga) << 32) / tscFreq; | |
152 | tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n; | |
153 | ||
154 | tscGranularity = tscFreq / busFreq; | |
155 | ||
156 | bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t); | |
157 | ||
158 | return; | |
159 | } | |
160 | } | |
161 | ||
2d21ac55 | 162 | /* |
593a1d5f | 163 | * Get the FSB frequency and conversion factors from EFI. |
2d21ac55 A |
164 | */ |
165 | busFreq = EFI_FSB_frequency(); | |
593a1d5f | 166 | |
7e4a7d39 | 167 | switch (cpuid_cpufamily()) { |
13f56ec4 | 168 | case CPUFAMILY_INTEL_IVYBRIDGE: |
060df5ea | 169 | case CPUFAMILY_INTEL_SANDYBRIDGE: |
d1ecb069 | 170 | case CPUFAMILY_INTEL_WESTMERE: |
7e4a7d39 | 171 | case CPUFAMILY_INTEL_NEHALEM: { |
c910b4d9 A |
172 | uint64_t msr_flex_ratio; |
173 | uint64_t msr_platform_info; | |
174 | ||
175 | /* See if FLEX_RATIO is being used */ | |
176 | msr_flex_ratio = rdmsr64(MSR_FLEX_RATIO); | |
177 | msr_platform_info = rdmsr64(MSR_PLATFORM_INFO); | |
178 | flex_ratio_min = (uint32_t)bitfield(msr_platform_info, 47, 40); | |
179 | flex_ratio_max = (uint32_t)bitfield(msr_platform_info, 15, 8); | |
180 | /* No BIOS-programed flex ratio. Use hardware max as default */ | |
181 | tscGranularity = flex_ratio_max; | |
182 | if (msr_flex_ratio & bit(16)) { | |
183 | /* Flex Enabled: Use this MSR if less than max */ | |
184 | flex_ratio = (uint32_t)bitfield(msr_flex_ratio, 15, 8); | |
185 | if (flex_ratio < flex_ratio_max) | |
186 | tscGranularity = flex_ratio; | |
187 | } | |
188 | ||
189 | /* If EFI isn't configured correctly, use a constant | |
190 | * value. See 6036811. | |
191 | */ | |
192 | if (busFreq == 0) | |
b0d623f7 | 193 | busFreq = BASE_NHM_CLOCK_SOURCE; |
c910b4d9 | 194 | |
c910b4d9 A |
195 | break; |
196 | } | |
197 | default: { | |
593a1d5f A |
198 | uint64_t prfsts; |
199 | ||
200 | prfsts = rdmsr64(IA32_PERF_STS); | |
201 | tscGranularity = (uint32_t)bitfield(prfsts, 44, 40); | |
202 | N_by_2_bus_ratio = (prfsts & bit(46)) != 0; | |
c910b4d9 | 203 | } |
593a1d5f A |
204 | } |
205 | ||
2d21ac55 A |
206 | if (busFreq != 0) { |
207 | busFCvtt2n = ((1 * Giga) << 32) / busFreq; | |
208 | busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n; | |
2d21ac55 | 209 | } else { |
593a1d5f | 210 | panic("tsc_init: EFI not supported!\n"); |
2d21ac55 A |
211 | } |
212 | ||
316670eb A |
213 | kprintf(" BUS: Frequency = %6d.%06dMHz, " |
214 | "cvtt2n = %08Xx.%08Xx, cvtn2t = %08Xx.%08Xx\n", | |
593a1d5f A |
215 | (uint32_t)(busFreq / Mega), |
216 | (uint32_t)(busFreq % Mega), | |
217 | (uint32_t)(busFCvtt2n >> 32), (uint32_t)busFCvtt2n, | |
316670eb | 218 | (uint32_t)(busFCvtn2t >> 32), (uint32_t)busFCvtn2t); |
2d21ac55 A |
219 | |
220 | /* | |
221 | * Get the TSC increment. The TSC is incremented by this | |
222 | * on every bus tick. Calculate the TSC conversion factors | |
223 | * to and from nano-seconds. | |
4a3eedf9 A |
224 | * The tsc granularity is also called the "bus ratio". If the N/2 bit |
225 | * is set this indicates the bus ration is 0.5 more than this - i.e. | |
316670eb A |
226 | * that the true bus ratio is (2*tscGranularity + 1)/2. If we cannot |
227 | * determine the TSC conversion, assume it ticks at the bus frequency. | |
2d21ac55 | 228 | */ |
316670eb A |
229 | if (tscGranularity == 0) |
230 | tscGranularity = 1; | |
231 | ||
2d21ac55 | 232 | if (N_by_2_bus_ratio) |
4a3eedf9 | 233 | tscFCvtt2n = busFCvtt2n * 2 / (1 + 2*tscGranularity); |
2d21ac55 | 234 | else |
4a3eedf9 | 235 | tscFCvtt2n = busFCvtt2n / tscGranularity; |
2d21ac55 A |
236 | |
237 | tscFreq = ((1 * Giga) << 32) / tscFCvtt2n; | |
238 | tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n; | |
239 | ||
316670eb A |
240 | kprintf(" TSC: Frequency = %6d.%06dMHz, " |
241 | "cvtt2n = %08Xx.%08Xx, cvtn2t = %08Xx.%08Xx, gran = %lld%s\n", | |
593a1d5f A |
242 | (uint32_t)(tscFreq / Mega), |
243 | (uint32_t)(tscFreq % Mega), | |
244 | (uint32_t)(tscFCvtt2n >> 32), (uint32_t)tscFCvtt2n, | |
245 | (uint32_t)(tscFCvtn2t >> 32), (uint32_t)tscFCvtn2t, | |
246 | tscGranularity, N_by_2_bus_ratio ? " (N/2)" : ""); | |
2d21ac55 A |
247 | |
248 | /* | |
249 | * Calculate conversion from BUS to TSC | |
250 | */ | |
251 | bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t); | |
0c530ab8 A |
252 | } |
253 | ||
254 | void | |
255 | tsc_get_info(tscInfo_t *info) | |
256 | { | |
2d21ac55 A |
257 | info->busFCvtt2n = busFCvtt2n; |
258 | info->busFCvtn2t = busFCvtn2t; | |
259 | info->tscFreq = tscFreq; | |
260 | info->tscFCvtt2n = tscFCvtt2n; | |
261 | info->tscFCvtn2t = tscFCvtn2t; | |
262 | info->tscGranularity = tscGranularity; | |
263 | info->bus2tsc = bus2tsc; | |
264 | info->busFreq = busFreq; | |
593a1d5f A |
265 | info->flex_ratio = flex_ratio; |
266 | info->flex_ratio_min = flex_ratio_min; | |
267 | info->flex_ratio_max = flex_ratio_max; | |
0c530ab8 | 268 | } |