]>
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> | |
39 | #include <mach_kdb.h> | |
40 | ||
41 | #include <mach/mach_types.h> | |
42 | ||
43 | #include <kern/cpu_data.h> | |
44 | #include <kern/cpu_number.h> | |
45 | #include <kern/clock.h> | |
46 | #include <kern/host_notify.h> | |
47 | #include <kern/macro_help.h> | |
48 | #include <kern/misc_protos.h> | |
49 | #include <kern/spl.h> | |
50 | #include <kern/assert.h> | |
51 | #include <mach/vm_prot.h> | |
52 | #include <vm/pmap.h> | |
53 | #include <vm/vm_kern.h> /* for kernel_map */ | |
0c530ab8 | 54 | #include <architecture/i386/pio.h> |
0c530ab8 | 55 | #include <i386/machine_cpu.h> |
2d21ac55 | 56 | #include <i386/cpuid.h> |
b0d623f7 | 57 | #include <i386/mp.h> |
0c530ab8 | 58 | #include <i386/machine_routines.h> |
b0d623f7 A |
59 | #include <i386/proc_reg.h> |
60 | #include <i386/tsc.h> | |
61 | #include <i386/misc_protos.h> | |
0c530ab8 A |
62 | #include <pexpert/pexpert.h> |
63 | #include <machine/limits.h> | |
64 | #include <machine/commpage.h> | |
65 | #include <sys/kdebug.h> | |
66 | #include <pexpert/device_tree.h> | |
0c530ab8 A |
67 | |
68 | uint64_t busFCvtt2n = 0; | |
69 | uint64_t busFCvtn2t = 0; | |
70 | uint64_t tscFreq = 0; | |
71 | uint64_t tscFCvtt2n = 0; | |
72 | uint64_t tscFCvtn2t = 0; | |
73 | uint64_t tscGranularity = 0; | |
74 | uint64_t bus2tsc = 0; | |
2d21ac55 | 75 | uint64_t busFreq = 0; |
593a1d5f A |
76 | uint32_t flex_ratio = 0; |
77 | uint32_t flex_ratio_min = 0; | |
78 | uint32_t flex_ratio_max = 0; | |
79 | ||
2d21ac55 A |
80 | |
81 | #define bit(n) (1ULL << (n)) | |
82 | #define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) | |
83 | #define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) | |
0c530ab8 A |
84 | |
85 | /* Decimal powers: */ | |
86 | #define kilo (1000ULL) | |
87 | #define Mega (kilo * kilo) | |
88 | #define Giga (kilo * Mega) | |
89 | #define Tera (kilo * Giga) | |
90 | #define Peta (kilo * Tera) | |
91 | ||
2d21ac55 A |
92 | #define CPU_FAMILY_PENTIUM_M (0x6) |
93 | ||
0c530ab8 A |
94 | static const char FSB_Frequency_prop[] = "FSBFrequency"; |
95 | /* | |
593a1d5f | 96 | * This routine extracts the bus frequency in Hz from the device tree. |
0c530ab8 A |
97 | */ |
98 | static uint64_t | |
99 | EFI_FSB_frequency(void) | |
100 | { | |
101 | uint64_t frequency = 0; | |
102 | DTEntry entry; | |
103 | void *value; | |
2d21ac55 | 104 | unsigned int size; |
0c530ab8 A |
105 | |
106 | if (DTLookupEntry(0, "/efi/platform", &entry) != kSuccess) { | |
107 | kprintf("EFI_FSB_frequency: didn't find /efi/platform\n"); | |
108 | return 0; | |
109 | } | |
110 | if (DTGetProperty(entry,FSB_Frequency_prop,&value,&size) != kSuccess) { | |
2d21ac55 A |
111 | kprintf("EFI_FSB_frequency: property %s not found\n", |
112 | FSB_Frequency_prop); | |
0c530ab8 A |
113 | return 0; |
114 | } | |
115 | if (size == sizeof(uint64_t)) { | |
116 | frequency = *(uint64_t *) value; | |
117 | kprintf("EFI_FSB_frequency: read %s value: %llu\n", | |
118 | FSB_Frequency_prop, frequency); | |
119 | if (!(90*Mega < frequency && frequency < 10*Giga)) { | |
120 | kprintf("EFI_FSB_frequency: value out of range\n"); | |
121 | frequency = 0; | |
122 | } | |
123 | } else { | |
124 | kprintf("EFI_FSB_frequency: unexpected size %d\n", size); | |
125 | } | |
126 | return frequency; | |
127 | } | |
128 | ||
129 | /* | |
130 | * Initialize the various conversion factors needed by code referencing | |
131 | * the TSC. | |
132 | */ | |
133 | void | |
134 | tsc_init(void) | |
135 | { | |
2d21ac55 A |
136 | uint64_t busFCvtInt = 0; |
137 | boolean_t N_by_2_bus_ratio = FALSE; | |
138 | ||
139 | /* | |
593a1d5f | 140 | * Get the FSB frequency and conversion factors from EFI. |
2d21ac55 A |
141 | */ |
142 | busFreq = EFI_FSB_frequency(); | |
593a1d5f | 143 | |
7e4a7d39 | 144 | switch (cpuid_cpufamily()) { |
060df5ea | 145 | case CPUFAMILY_INTEL_SANDYBRIDGE: |
d1ecb069 | 146 | case CPUFAMILY_INTEL_WESTMERE: |
7e4a7d39 | 147 | case CPUFAMILY_INTEL_NEHALEM: { |
c910b4d9 A |
148 | uint64_t cpu_mhz; |
149 | uint64_t msr_flex_ratio; | |
150 | uint64_t msr_platform_info; | |
151 | ||
152 | /* See if FLEX_RATIO is being used */ | |
153 | msr_flex_ratio = rdmsr64(MSR_FLEX_RATIO); | |
154 | msr_platform_info = rdmsr64(MSR_PLATFORM_INFO); | |
155 | flex_ratio_min = (uint32_t)bitfield(msr_platform_info, 47, 40); | |
156 | flex_ratio_max = (uint32_t)bitfield(msr_platform_info, 15, 8); | |
157 | /* No BIOS-programed flex ratio. Use hardware max as default */ | |
158 | tscGranularity = flex_ratio_max; | |
159 | if (msr_flex_ratio & bit(16)) { | |
160 | /* Flex Enabled: Use this MSR if less than max */ | |
161 | flex_ratio = (uint32_t)bitfield(msr_flex_ratio, 15, 8); | |
162 | if (flex_ratio < flex_ratio_max) | |
163 | tscGranularity = flex_ratio; | |
164 | } | |
165 | ||
166 | /* If EFI isn't configured correctly, use a constant | |
167 | * value. See 6036811. | |
168 | */ | |
169 | if (busFreq == 0) | |
b0d623f7 | 170 | busFreq = BASE_NHM_CLOCK_SOURCE; |
c910b4d9 A |
171 | |
172 | cpu_mhz = tscGranularity * BASE_NHM_CLOCK_SOURCE; | |
173 | ||
c910b4d9 A |
174 | break; |
175 | } | |
176 | default: { | |
593a1d5f A |
177 | uint64_t prfsts; |
178 | ||
179 | prfsts = rdmsr64(IA32_PERF_STS); | |
180 | tscGranularity = (uint32_t)bitfield(prfsts, 44, 40); | |
181 | N_by_2_bus_ratio = (prfsts & bit(46)) != 0; | |
c910b4d9 | 182 | } |
593a1d5f A |
183 | } |
184 | ||
2d21ac55 A |
185 | if (busFreq != 0) { |
186 | busFCvtt2n = ((1 * Giga) << 32) / busFreq; | |
187 | busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n; | |
188 | busFCvtInt = tmrCvt(1 * Peta, 0xFFFFFFFFFFFFFFFFULL / busFreq); | |
189 | } else { | |
593a1d5f | 190 | panic("tsc_init: EFI not supported!\n"); |
2d21ac55 A |
191 | } |
192 | ||
193 | kprintf(" BUS: Frequency = %6d.%04dMHz, " | |
593a1d5f A |
194 | "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X, " |
195 | "cvtInt = %08X.%08X\n", | |
196 | (uint32_t)(busFreq / Mega), | |
197 | (uint32_t)(busFreq % Mega), | |
198 | (uint32_t)(busFCvtt2n >> 32), (uint32_t)busFCvtt2n, | |
199 | (uint32_t)(busFCvtn2t >> 32), (uint32_t)busFCvtn2t, | |
200 | (uint32_t)(busFCvtInt >> 32), (uint32_t)busFCvtInt); | |
2d21ac55 A |
201 | |
202 | /* | |
203 | * Get the TSC increment. The TSC is incremented by this | |
204 | * on every bus tick. Calculate the TSC conversion factors | |
205 | * to and from nano-seconds. | |
4a3eedf9 A |
206 | * The tsc granularity is also called the "bus ratio". If the N/2 bit |
207 | * is set this indicates the bus ration is 0.5 more than this - i.e. | |
208 | * that the true bus ratio is (2*tscGranularity + 1)/2. | |
2d21ac55 | 209 | */ |
2d21ac55 | 210 | if (N_by_2_bus_ratio) |
4a3eedf9 | 211 | tscFCvtt2n = busFCvtt2n * 2 / (1 + 2*tscGranularity); |
2d21ac55 | 212 | else |
4a3eedf9 | 213 | tscFCvtt2n = busFCvtt2n / tscGranularity; |
2d21ac55 A |
214 | |
215 | tscFreq = ((1 * Giga) << 32) / tscFCvtt2n; | |
216 | tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n; | |
217 | ||
218 | kprintf(" TSC: Frequency = %6d.%04dMHz, " | |
593a1d5f A |
219 | "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X, gran = %lld%s\n", |
220 | (uint32_t)(tscFreq / Mega), | |
221 | (uint32_t)(tscFreq % Mega), | |
222 | (uint32_t)(tscFCvtt2n >> 32), (uint32_t)tscFCvtt2n, | |
223 | (uint32_t)(tscFCvtn2t >> 32), (uint32_t)tscFCvtn2t, | |
224 | tscGranularity, N_by_2_bus_ratio ? " (N/2)" : ""); | |
2d21ac55 A |
225 | |
226 | /* | |
227 | * Calculate conversion from BUS to TSC | |
228 | */ | |
229 | bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t); | |
0c530ab8 A |
230 | } |
231 | ||
232 | void | |
233 | tsc_get_info(tscInfo_t *info) | |
234 | { | |
2d21ac55 A |
235 | info->busFCvtt2n = busFCvtt2n; |
236 | info->busFCvtn2t = busFCvtn2t; | |
237 | info->tscFreq = tscFreq; | |
238 | info->tscFCvtt2n = tscFCvtt2n; | |
239 | info->tscFCvtn2t = tscFCvtn2t; | |
240 | info->tscGranularity = tscGranularity; | |
241 | info->bus2tsc = bus2tsc; | |
242 | info->busFreq = busFreq; | |
593a1d5f A |
243 | info->flex_ratio = flex_ratio; |
244 | info->flex_ratio_min = flex_ratio_min; | |
245 | info->flex_ratio_max = flex_ratio_max; | |
0c530ab8 | 246 | } |