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
47int
48via_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
75int
76viac7_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
90int
91p3_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));
318print_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
330int
331p4_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