1 | /* $NetBSD: intel_busclock.c,v 1.24 2015/07/02 05:11:50 msaitoh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Frank van der Linden, and by Jason R. Thorpe. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: intel_busclock.c,v 1.24 2015/07/02 05:11:50 msaitoh Exp $" ); |
34 | |
35 | #include <sys/param.h> |
36 | #include <sys/systm.h> |
37 | #include <sys/device.h> |
38 | #include <sys/cpu.h> |
39 | |
40 | #include <machine/specialreg.h> |
41 | #include <machine/pio.h> |
42 | |
43 | #include <x86/cpuvar.h> |
44 | #include <x86/cpufunc.h> |
45 | #include <x86/est.h> |
46 | |
47 | int |
48 | via_get_bus_clock(struct cpu_info *ci) |
49 | { |
50 | uint64_t msr; |
51 | int bus, bus_clock = 0; |
52 | |
53 | msr = rdmsr(MSR_EBL_CR_POWERON); |
54 | bus = (msr >> 18) & 0x3; |
55 | switch (bus) { |
56 | case 0: |
57 | bus_clock = 10000; |
58 | break; |
59 | case 1: |
60 | bus_clock = 13333; |
61 | break; |
62 | case 2: |
63 | bus_clock = 20000; |
64 | break; |
65 | case 3: |
66 | bus_clock = 16667; |
67 | break; |
68 | default: |
69 | break; |
70 | } |
71 | |
72 | return bus_clock; |
73 | } |
74 | |
75 | int |
76 | viac7_get_bus_clock(struct cpu_info *ci) |
77 | { |
78 | uint64_t msr; |
79 | int mult; |
80 | |
81 | msr = rdmsr(MSR_PERF_STATUS); |
82 | mult = (msr >> 8) & 0xff; |
83 | if (mult == 0) |
84 | return 0; |
85 | |
86 | return ((ci->ci_data.cpu_cc_freq + 10000000) / 10000000 * 10000000) / |
87 | mult / 10000; |
88 | } |
89 | |
90 | int |
91 | p3_get_bus_clock(struct cpu_info *ci) |
92 | { |
93 | uint64_t msr; |
94 | int bus, bus_clock = 0; |
95 | uint32_t model; |
96 | |
97 | model = CPUID_TO_MODEL(ci->ci_signature); |
98 | |
99 | switch (model) { |
100 | case 0x9: /* Pentium M (130 nm, Banias) */ |
101 | bus_clock = 10000; |
102 | break; |
103 | case 0xc: /* Core i7, Atom, model 1 */ |
104 | /* |
105 | * Newer CPUs will GP when attemping to access MSR_FSB_FREQ. |
106 | * In the long-term, use ACPI instead of all this. |
107 | */ |
108 | if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) { |
109 | aprint_debug_dev(ci->ci_dev, |
110 | "unable to determine bus speed" ); |
111 | goto print_msr; |
112 | } |
113 | bus = (msr >> 0) & 0x7; |
114 | switch (bus) { |
115 | case 1: |
116 | bus_clock = 13333; |
117 | break; |
118 | default: |
119 | aprint_debug("%s: unknown Atom FSB_FREQ " |
120 | "value %d" , device_xname(ci->ci_dev), bus); |
121 | goto print_msr; |
122 | } |
123 | break; |
124 | case 0xd: /* Pentium M (90 nm, Dothan) */ |
125 | if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) { |
126 | aprint_debug_dev(ci->ci_dev, |
127 | "unable to determine bus speed" ); |
128 | goto print_msr; |
129 | } |
130 | bus = (msr >> 0) & 0x7; |
131 | switch (bus) { |
132 | case 0: |
133 | bus_clock = 10000; |
134 | break; |
135 | case 1: |
136 | bus_clock = 13333; |
137 | break; |
138 | default: |
139 | aprint_debug("%s: unknown Pentium M FSB_FREQ " |
140 | "value %d" , device_xname(ci->ci_dev), bus); |
141 | goto print_msr; |
142 | } |
143 | break; |
144 | case 0xe: /* Core Duo/Solo */ |
145 | case 0xf: /* Core Xeon */ |
146 | case 0x17: /* Xeon [35]000, Core 2 Quad [89]00 */ |
147 | if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) { |
148 | aprint_debug_dev(ci->ci_dev, |
149 | "unable to determine bus speed" ); |
150 | goto print_msr; |
151 | } |
152 | bus = (msr >> 0) & 0x7; |
153 | switch (bus) { |
154 | case 5: |
155 | bus_clock = 10000; |
156 | break; |
157 | case 1: |
158 | bus_clock = 13333; |
159 | break; |
160 | case 3: |
161 | bus_clock = 16667; |
162 | break; |
163 | case 2: |
164 | bus_clock = 20000; |
165 | break; |
166 | case 0: |
167 | bus_clock = 26667; |
168 | break; |
169 | case 4: |
170 | bus_clock = 33333; |
171 | break; |
172 | case 6: |
173 | bus_clock = 40000; |
174 | break; |
175 | default: |
176 | aprint_debug("%s: unknown Core FSB_FREQ value %d" , |
177 | device_xname(ci->ci_dev), bus); |
178 | goto print_msr; |
179 | } |
180 | break; |
181 | case 0x1: /* Pentium Pro, model 1 */ |
182 | case 0x3: /* Pentium II, model 3 */ |
183 | case 0x5: /* Pentium II, II Xeon, Celeron, model 5 */ |
184 | case 0x6: /* Celeron, model 6 */ |
185 | case 0x7: /* Pentium III, III Xeon, model 7 */ |
186 | case 0x8: /* Pentium III, III Xeon, Celeron, model 8 */ |
187 | case 0xa: /* Pentium III Xeon, model A */ |
188 | case 0xb: /* Pentium III, model B */ |
189 | msr = rdmsr(MSR_EBL_CR_POWERON); |
190 | bus = (msr >> 18) & 0x3; |
191 | switch (bus) { |
192 | case 0: |
193 | bus_clock = 6666; |
194 | break; |
195 | case 1: |
196 | bus_clock = 13333; |
197 | break; |
198 | case 2: |
199 | bus_clock = 10000; |
200 | break; |
201 | case 3: |
202 | bus_clock = 10666; |
203 | break; |
204 | default: |
205 | aprint_debug("%s: unknown i686 EBL_CR_POWERON " |
206 | "value %d " , device_xname(ci->ci_dev), bus); |
207 | goto print_msr; |
208 | } |
209 | break; |
210 | case 0x1c: /* Atom */ |
211 | case 0x26: |
212 | case 0x27: |
213 | case 0x35: |
214 | case 0x36: |
215 | if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) { |
216 | aprint_debug_dev(ci->ci_dev, |
217 | "unable to determine bus speed" ); |
218 | goto print_msr; |
219 | } |
220 | bus = (msr >> 0) & 0x7; |
221 | switch (bus) { |
222 | case 7: |
223 | bus_clock = 8333; |
224 | break; |
225 | case 5: |
226 | bus_clock = 10000; |
227 | break; |
228 | case 1: |
229 | bus_clock = 13333; |
230 | break; |
231 | case 3: |
232 | bus_clock = 16667; |
233 | break; |
234 | default: |
235 | aprint_debug("%s: unknown Atom FSB_FREQ value %d" , |
236 | device_xname(ci->ci_dev), bus); |
237 | goto print_msr; |
238 | } |
239 | break; |
240 | case 0x37: /* Silvermont */ |
241 | case 0x4a: |
242 | case 0x4d: |
243 | case 0x5a: |
244 | case 0x5d: |
245 | if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) { |
246 | aprint_debug_dev(ci->ci_dev, |
247 | "unable to determine bus speed" ); |
248 | goto print_msr; |
249 | } |
250 | bus = (msr >> 0) & 0x7; |
251 | switch (bus) { |
252 | case 4: |
253 | bus_clock = 8000; |
254 | break; |
255 | case 0: |
256 | bus_clock = 8333; |
257 | break; |
258 | case 1: |
259 | bus_clock = 10000; |
260 | break; |
261 | case 2: |
262 | bus_clock = 13333; |
263 | break; |
264 | case 3: |
265 | bus_clock = 11667; |
266 | break; |
267 | default: |
268 | aprint_debug("%s: unknown Silvermont FSB_FREQ value %d" , |
269 | device_xname(ci->ci_dev), bus); |
270 | goto print_msr; |
271 | } |
272 | break; |
273 | case 0x4c: /* Airmont */ |
274 | if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) { |
275 | aprint_debug_dev(ci->ci_dev, |
276 | "unable to determine bus speed" ); |
277 | goto print_msr; |
278 | } |
279 | bus = (msr >> 0) & 0x0f; |
280 | switch (bus) { |
281 | case 0: |
282 | bus_clock = 8333; |
283 | break; |
284 | case 1: |
285 | bus_clock = 10000; |
286 | break; |
287 | case 2: |
288 | bus_clock = 13333; |
289 | break; |
290 | case 3: |
291 | bus_clock = 11666; |
292 | break; |
293 | case 4: |
294 | bus_clock = 8000; |
295 | break; |
296 | case 5: |
297 | bus_clock = 9333; |
298 | break; |
299 | case 6: |
300 | bus_clock = 9000; |
301 | break; |
302 | case 7: |
303 | bus_clock = 8888; |
304 | break; |
305 | case 8: |
306 | bus_clock = 8750; |
307 | break; |
308 | default: |
309 | aprint_debug("%s: unknown Airmont FSB_FREQ value %d" , |
310 | device_xname(ci->ci_dev), bus); |
311 | goto print_msr; |
312 | } |
313 | break; |
314 | default: |
315 | aprint_debug("%s: unknown i686 model %02x, can't get bus clock" , |
316 | device_xname(ci->ci_dev), |
317 | CPUID_TO_MODEL(ci->ci_signature)); |
318 | print_msr: |
319 | /* |
320 | * Show the EBL_CR_POWERON MSR, so we'll at least have |
321 | * some extra information, such as clock ratio, etc. |
322 | */ |
323 | aprint_debug(" (0x%" PRIu64 ")\n" , rdmsr(MSR_EBL_CR_POWERON)); |
324 | break; |
325 | } |
326 | |
327 | return bus_clock; |
328 | } |
329 | |
330 | int |
331 | p4_get_bus_clock(struct cpu_info *ci) |
332 | { |
333 | uint64_t msr; |
334 | int bus, bus_clock = 0; |
335 | |
336 | msr = rdmsr(MSR_EBC_FREQUENCY_ID); |
337 | if (CPUID_TO_MODEL(ci->ci_signature) < 2) { |
338 | bus = (msr >> 21) & 0x7; |
339 | switch (bus) { |
340 | case 0: |
341 | bus_clock = 10000; |
342 | break; |
343 | case 1: |
344 | bus_clock = 13333; |
345 | break; |
346 | default: |
347 | aprint_debug("%s: unknown Pentium 4 (model %d) " |
348 | "EBC_FREQUENCY_ID value %d\n" , |
349 | device_xname(ci->ci_dev), |
350 | CPUID_TO_MODEL(ci->ci_signature), bus); |
351 | break; |
352 | } |
353 | } else { |
354 | bus = (msr >> 16) & 0x7; |
355 | switch (bus) { |
356 | case 0: |
357 | bus_clock = (CPUID_TO_MODEL(ci->ci_signature) == 2) ? |
358 | 10000 : 26667; |
359 | break; |
360 | case 1: |
361 | bus_clock = 13333; |
362 | break; |
363 | case 2: |
364 | bus_clock = 20000; |
365 | break; |
366 | case 3: |
367 | bus_clock = 16667; |
368 | break; |
369 | case 4: |
370 | bus_clock = 33333; |
371 | break; |
372 | default: |
373 | aprint_debug("%s: unknown Pentium 4 (model %d) " |
374 | "EBC_FREQUENCY_ID value %d\n" , |
375 | device_xname(ci->ci_dev), |
376 | CPUID_TO_MODEL(ci->ci_signature), bus); |
377 | break; |
378 | } |
379 | } |
380 | |
381 | return bus_clock; |
382 | } |
383 | |