1*c89ae296Smsaitoh /* $NetBSD: intel_busclock.c,v 1.26 2023/01/20 01:35:03 msaitoh Exp $ */
2699c85afSxtraeme
3699c85afSxtraeme /*-
4699c85afSxtraeme * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
5699c85afSxtraeme * All rights reserved.
6699c85afSxtraeme *
7699c85afSxtraeme * This code is derived from software contributed to The NetBSD Foundation
8699c85afSxtraeme * by Frank van der Linden, and by Jason R. Thorpe.
9699c85afSxtraeme *
10699c85afSxtraeme * Redistribution and use in source and binary forms, with or without
11699c85afSxtraeme * modification, are permitted provided that the following conditions
12699c85afSxtraeme * are met:
13699c85afSxtraeme * 1. Redistributions of source code must retain the above copyright
14699c85afSxtraeme * notice, this list of conditions and the following disclaimer.
15699c85afSxtraeme * 2. Redistributions in binary form must reproduce the above copyright
16699c85afSxtraeme * notice, this list of conditions and the following disclaimer in the
17699c85afSxtraeme * documentation and/or other materials provided with the distribution.
18699c85afSxtraeme *
19699c85afSxtraeme * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20699c85afSxtraeme * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21699c85afSxtraeme * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22699c85afSxtraeme * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23699c85afSxtraeme * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24699c85afSxtraeme * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25699c85afSxtraeme * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26699c85afSxtraeme * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27699c85afSxtraeme * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28699c85afSxtraeme * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29699c85afSxtraeme * POSSIBILITY OF SUCH DAMAGE.
30699c85afSxtraeme */
31699c85afSxtraeme
32699c85afSxtraeme #include <sys/cdefs.h>
33*c89ae296Smsaitoh __KERNEL_RCSID(0, "$NetBSD: intel_busclock.c,v 1.26 2023/01/20 01:35:03 msaitoh Exp $");
34699c85afSxtraeme
35699c85afSxtraeme #include <sys/param.h>
36699c85afSxtraeme #include <sys/systm.h>
37f81f6237Sdyoung #include <sys/device.h>
380664a045Sad #include <sys/cpu.h>
39699c85afSxtraeme
40699c85afSxtraeme #include <machine/specialreg.h>
41699c85afSxtraeme #include <machine/pio.h>
42699c85afSxtraeme
43699c85afSxtraeme #include <x86/cpuvar.h>
445fa6e7c2Schristos #include <x86/cpufunc.h>
45acdf2636Sjruoho #include <x86/est.h>
46699c85afSxtraeme
47699c85afSxtraeme int
via_get_bus_clock(struct cpu_info * ci)4841fe337fSxtraeme via_get_bus_clock(struct cpu_info *ci)
4941fe337fSxtraeme {
5041fe337fSxtraeme uint64_t msr;
5141fe337fSxtraeme int bus, bus_clock = 0;
5241fe337fSxtraeme
5341fe337fSxtraeme msr = rdmsr(MSR_EBL_CR_POWERON);
5441fe337fSxtraeme bus = (msr >> 18) & 0x3;
5541fe337fSxtraeme switch (bus) {
5641fe337fSxtraeme case 0:
5741fe337fSxtraeme bus_clock = 10000;
5841fe337fSxtraeme break;
5941fe337fSxtraeme case 1:
6041fe337fSxtraeme bus_clock = 13333;
6141fe337fSxtraeme break;
6241fe337fSxtraeme case 2:
6341fe337fSxtraeme bus_clock = 20000;
6441fe337fSxtraeme break;
6541fe337fSxtraeme case 3:
6641fe337fSxtraeme bus_clock = 16667;
6741fe337fSxtraeme break;
6841fe337fSxtraeme default:
6941fe337fSxtraeme break;
7041fe337fSxtraeme }
7141fe337fSxtraeme
7241fe337fSxtraeme return bus_clock;
7341fe337fSxtraeme }
7441fe337fSxtraeme
7541fe337fSxtraeme int
viac7_get_bus_clock(struct cpu_info * ci)76f986f968Sjmcneill viac7_get_bus_clock(struct cpu_info *ci)
77f986f968Sjmcneill {
78f986f968Sjmcneill uint64_t msr;
79f986f968Sjmcneill int mult;
80f986f968Sjmcneill
81f986f968Sjmcneill msr = rdmsr(MSR_PERF_STATUS);
82f986f968Sjmcneill mult = (msr >> 8) & 0xff;
83f986f968Sjmcneill if (mult == 0)
84f986f968Sjmcneill return 0;
85f986f968Sjmcneill
86f986f968Sjmcneill return ((ci->ci_data.cpu_cc_freq + 10000000) / 10000000 * 10000000) /
87f986f968Sjmcneill mult / 10000;
88f986f968Sjmcneill }
89f986f968Sjmcneill
90f986f968Sjmcneill int
p3_get_bus_clock(struct cpu_info * ci)91699c85afSxtraeme p3_get_bus_clock(struct cpu_info *ci)
92699c85afSxtraeme {
93699c85afSxtraeme uint64_t msr;
94699c85afSxtraeme int bus, bus_clock = 0;
95d0d1f964Smartin uint32_t model;
96699c85afSxtraeme
97b1a32cacSmsaitoh model = CPUID_TO_MODEL(ci->ci_signature);
986431e0a7Smsaitoh
996431e0a7Smsaitoh switch (model) {
100699c85afSxtraeme case 0x9: /* Pentium M (130 nm, Banias) */
101699c85afSxtraeme bus_clock = 10000;
102699c85afSxtraeme break;
1031c41482eSjym case 0xc: /* Core i7, Atom, model 1 */
1041c41482eSjym /*
105*c89ae296Smsaitoh * Newer CPUs will GP when attempting to access MSR_FSB_FREQ.
1061c41482eSjym * In the long-term, use ACPI instead of all this.
1071c41482eSjym */
1085e90fb23Sjym if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
1095e90fb23Sjym aprint_debug_dev(ci->ci_dev,
1105e90fb23Sjym "unable to determine bus speed");
1111c41482eSjym goto print_msr;
1121c41482eSjym }
113e50d6685Sjmcneill bus = (msr >> 0) & 0x7;
114e50d6685Sjmcneill switch (bus) {
115e50d6685Sjmcneill case 1:
116e50d6685Sjmcneill bus_clock = 13333;
117e50d6685Sjmcneill break;
118e50d6685Sjmcneill default:
119e50d6685Sjmcneill aprint_debug("%s: unknown Atom FSB_FREQ "
120e50d6685Sjmcneill "value %d", device_xname(ci->ci_dev), bus);
121e50d6685Sjmcneill goto print_msr;
122e50d6685Sjmcneill }
123e50d6685Sjmcneill break;
124699c85afSxtraeme case 0xd: /* Pentium M (90 nm, Dothan) */
1255e90fb23Sjym if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
1265e90fb23Sjym aprint_debug_dev(ci->ci_dev,
1275e90fb23Sjym "unable to determine bus speed");
1285e90fb23Sjym goto print_msr;
1295e90fb23Sjym }
130699c85afSxtraeme bus = (msr >> 0) & 0x7;
131699c85afSxtraeme switch (bus) {
132699c85afSxtraeme case 0:
133699c85afSxtraeme bus_clock = 10000;
134699c85afSxtraeme break;
135699c85afSxtraeme case 1:
136699c85afSxtraeme bus_clock = 13333;
137699c85afSxtraeme break;
138699c85afSxtraeme default:
139699c85afSxtraeme aprint_debug("%s: unknown Pentium M FSB_FREQ "
140699c85afSxtraeme "value %d", device_xname(ci->ci_dev), bus);
141699c85afSxtraeme goto print_msr;
142699c85afSxtraeme }
143699c85afSxtraeme break;
144699c85afSxtraeme case 0xe: /* Core Duo/Solo */
145699c85afSxtraeme case 0xf: /* Core Xeon */
146fc14d85dSmsaitoh case 0x17: /* Xeon [35]000, Core 2 Quad [89]00 */
1475e90fb23Sjym if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
1485e90fb23Sjym aprint_debug_dev(ci->ci_dev,
1495e90fb23Sjym "unable to determine bus speed");
1505e90fb23Sjym goto print_msr;
1515e90fb23Sjym }
152699c85afSxtraeme bus = (msr >> 0) & 0x7;
153699c85afSxtraeme switch (bus) {
154699c85afSxtraeme case 5:
155699c85afSxtraeme bus_clock = 10000;
156699c85afSxtraeme break;
157699c85afSxtraeme case 1:
158699c85afSxtraeme bus_clock = 13333;
159699c85afSxtraeme break;
160699c85afSxtraeme case 3:
161699c85afSxtraeme bus_clock = 16667;
162699c85afSxtraeme break;
163699c85afSxtraeme case 2:
164699c85afSxtraeme bus_clock = 20000;
165699c85afSxtraeme break;
166699c85afSxtraeme case 0:
167699c85afSxtraeme bus_clock = 26667;
168699c85afSxtraeme break;
169699c85afSxtraeme case 4:
170699c85afSxtraeme bus_clock = 33333;
171699c85afSxtraeme break;
172fc14d85dSmsaitoh case 6:
173fc14d85dSmsaitoh bus_clock = 40000;
174fc14d85dSmsaitoh break;
175699c85afSxtraeme default:
176699c85afSxtraeme aprint_debug("%s: unknown Core FSB_FREQ value %d",
177699c85afSxtraeme device_xname(ci->ci_dev), bus);
178699c85afSxtraeme goto print_msr;
179699c85afSxtraeme }
180699c85afSxtraeme break;
181699c85afSxtraeme case 0x1: /* Pentium Pro, model 1 */
182699c85afSxtraeme case 0x3: /* Pentium II, model 3 */
183699c85afSxtraeme case 0x5: /* Pentium II, II Xeon, Celeron, model 5 */
184699c85afSxtraeme case 0x6: /* Celeron, model 6 */
185699c85afSxtraeme case 0x7: /* Pentium III, III Xeon, model 7 */
186699c85afSxtraeme case 0x8: /* Pentium III, III Xeon, Celeron, model 8 */
187699c85afSxtraeme case 0xa: /* Pentium III Xeon, model A */
188699c85afSxtraeme case 0xb: /* Pentium III, model B */
189699c85afSxtraeme msr = rdmsr(MSR_EBL_CR_POWERON);
190699c85afSxtraeme bus = (msr >> 18) & 0x3;
191699c85afSxtraeme switch (bus) {
192699c85afSxtraeme case 0:
193699c85afSxtraeme bus_clock = 6666;
194699c85afSxtraeme break;
195699c85afSxtraeme case 1:
196699c85afSxtraeme bus_clock = 13333;
197699c85afSxtraeme break;
198699c85afSxtraeme case 2:
199699c85afSxtraeme bus_clock = 10000;
200699c85afSxtraeme break;
201a39b0c6eSchristos case 3:
202a39b0c6eSchristos bus_clock = 10666;
203a39b0c6eSchristos break;
204699c85afSxtraeme default:
205699c85afSxtraeme aprint_debug("%s: unknown i686 EBL_CR_POWERON "
206699c85afSxtraeme "value %d ", device_xname(ci->ci_dev), bus);
207699c85afSxtraeme goto print_msr;
208699c85afSxtraeme }
209699c85afSxtraeme break;
210caea426aSmsaitoh case 0x1c: /* Atom */
211caea426aSmsaitoh case 0x26:
212caea426aSmsaitoh case 0x27:
213caea426aSmsaitoh case 0x35:
214caea426aSmsaitoh case 0x36:
215caea426aSmsaitoh if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
216caea426aSmsaitoh aprint_debug_dev(ci->ci_dev,
217caea426aSmsaitoh "unable to determine bus speed");
218caea426aSmsaitoh goto print_msr;
219caea426aSmsaitoh }
220caea426aSmsaitoh bus = (msr >> 0) & 0x7;
221caea426aSmsaitoh switch (bus) {
222caea426aSmsaitoh case 7:
223caea426aSmsaitoh bus_clock = 8333;
224caea426aSmsaitoh break;
225caea426aSmsaitoh case 5:
226caea426aSmsaitoh bus_clock = 10000;
227caea426aSmsaitoh break;
228caea426aSmsaitoh case 1:
229caea426aSmsaitoh bus_clock = 13333;
230caea426aSmsaitoh break;
231caea426aSmsaitoh case 3:
232caea426aSmsaitoh bus_clock = 16667;
233caea426aSmsaitoh break;
234caea426aSmsaitoh default:
235caea426aSmsaitoh aprint_debug("%s: unknown Atom FSB_FREQ value %d",
236caea426aSmsaitoh device_xname(ci->ci_dev), bus);
237caea426aSmsaitoh goto print_msr;
238caea426aSmsaitoh }
239caea426aSmsaitoh break;
240caea426aSmsaitoh case 0x37: /* Silvermont */
241fc14d85dSmsaitoh case 0x4a:
242caea426aSmsaitoh case 0x4d:
243fc14d85dSmsaitoh case 0x5a:
244fc14d85dSmsaitoh case 0x5d:
245caea426aSmsaitoh if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
246caea426aSmsaitoh aprint_debug_dev(ci->ci_dev,
247caea426aSmsaitoh "unable to determine bus speed");
248caea426aSmsaitoh goto print_msr;
249caea426aSmsaitoh }
250caea426aSmsaitoh bus = (msr >> 0) & 0x7;
251caea426aSmsaitoh switch (bus) {
252caea426aSmsaitoh case 4:
253caea426aSmsaitoh bus_clock = 8000;
254caea426aSmsaitoh break;
255caea426aSmsaitoh case 0:
256caea426aSmsaitoh bus_clock = 8333;
257caea426aSmsaitoh break;
258caea426aSmsaitoh case 1:
259caea426aSmsaitoh bus_clock = 10000;
260caea426aSmsaitoh break;
261caea426aSmsaitoh case 2:
262caea426aSmsaitoh bus_clock = 13333;
263caea426aSmsaitoh break;
264caea426aSmsaitoh case 3:
265fc14d85dSmsaitoh bus_clock = 11667;
266caea426aSmsaitoh break;
267caea426aSmsaitoh default:
268caea426aSmsaitoh aprint_debug("%s: unknown Silvermont FSB_FREQ value %d",
269caea426aSmsaitoh device_xname(ci->ci_dev), bus);
270caea426aSmsaitoh goto print_msr;
271caea426aSmsaitoh }
272caea426aSmsaitoh break;
273e1434c25Smsaitoh case 0x4c: /* Airmont */
274e1434c25Smsaitoh if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
275e1434c25Smsaitoh aprint_debug_dev(ci->ci_dev,
276e1434c25Smsaitoh "unable to determine bus speed");
277e1434c25Smsaitoh goto print_msr;
278e1434c25Smsaitoh }
2795045f81cSmsaitoh bus = (msr >> 0) & 0x0f;
280e1434c25Smsaitoh switch (bus) {
281e1434c25Smsaitoh case 0:
282e1434c25Smsaitoh bus_clock = 8333;
283e1434c25Smsaitoh break;
284e1434c25Smsaitoh case 1:
285e1434c25Smsaitoh bus_clock = 10000;
286e1434c25Smsaitoh break;
287e1434c25Smsaitoh case 2:
288e1434c25Smsaitoh bus_clock = 13333;
289e1434c25Smsaitoh break;
290e1434c25Smsaitoh case 3:
291e1434c25Smsaitoh bus_clock = 11666;
292e1434c25Smsaitoh break;
2935045f81cSmsaitoh case 4:
294e1434c25Smsaitoh bus_clock = 8000;
295e1434c25Smsaitoh break;
2965045f81cSmsaitoh case 5:
297e1434c25Smsaitoh bus_clock = 9333;
298e1434c25Smsaitoh break;
2995045f81cSmsaitoh case 6:
300e1434c25Smsaitoh bus_clock = 9000;
301e1434c25Smsaitoh break;
3025045f81cSmsaitoh case 7:
303e1434c25Smsaitoh bus_clock = 8888;
304e1434c25Smsaitoh break;
3055045f81cSmsaitoh case 8:
306c92fa102Smsaitoh bus_clock = 8750;
307c92fa102Smsaitoh break;
308e1434c25Smsaitoh default:
309e1434c25Smsaitoh aprint_debug("%s: unknown Airmont FSB_FREQ value %d",
310e1434c25Smsaitoh device_xname(ci->ci_dev), bus);
311e1434c25Smsaitoh goto print_msr;
312e1434c25Smsaitoh }
313e1434c25Smsaitoh break;
314699c85afSxtraeme default:
315fc14d85dSmsaitoh aprint_debug("%s: unknown i686 model %02x, can't get bus clock",
316699c85afSxtraeme device_xname(ci->ci_dev),
317b1a32cacSmsaitoh CPUID_TO_MODEL(ci->ci_signature));
318699c85afSxtraeme print_msr:
319699c85afSxtraeme /*
320699c85afSxtraeme * Show the EBL_CR_POWERON MSR, so we'll at least have
321699c85afSxtraeme * some extra information, such as clock ratio, etc.
322699c85afSxtraeme */
323699c85afSxtraeme aprint_debug(" (0x%" PRIu64 ")\n", rdmsr(MSR_EBL_CR_POWERON));
324699c85afSxtraeme break;
325699c85afSxtraeme }
326699c85afSxtraeme
327699c85afSxtraeme return bus_clock;
328699c85afSxtraeme }
329699c85afSxtraeme
330699c85afSxtraeme int
p4_get_bus_clock(struct cpu_info * ci)331699c85afSxtraeme p4_get_bus_clock(struct cpu_info *ci)
332699c85afSxtraeme {
333699c85afSxtraeme uint64_t msr;
334699c85afSxtraeme int bus, bus_clock = 0;
335699c85afSxtraeme
336699c85afSxtraeme msr = rdmsr(MSR_EBC_FREQUENCY_ID);
337b1a32cacSmsaitoh if (CPUID_TO_MODEL(ci->ci_signature) < 2) {
338699c85afSxtraeme bus = (msr >> 21) & 0x7;
339699c85afSxtraeme switch (bus) {
340699c85afSxtraeme case 0:
341699c85afSxtraeme bus_clock = 10000;
342699c85afSxtraeme break;
343699c85afSxtraeme case 1:
344699c85afSxtraeme bus_clock = 13333;
345699c85afSxtraeme break;
346699c85afSxtraeme default:
347699c85afSxtraeme aprint_debug("%s: unknown Pentium 4 (model %d) "
348699c85afSxtraeme "EBC_FREQUENCY_ID value %d\n",
349699c85afSxtraeme device_xname(ci->ci_dev),
350b1a32cacSmsaitoh CPUID_TO_MODEL(ci->ci_signature), bus);
351699c85afSxtraeme break;
352699c85afSxtraeme }
353699c85afSxtraeme } else {
354699c85afSxtraeme bus = (msr >> 16) & 0x7;
355699c85afSxtraeme switch (bus) {
356699c85afSxtraeme case 0:
357b1a32cacSmsaitoh bus_clock = (CPUID_TO_MODEL(ci->ci_signature) == 2) ?
35895c5c320Smsaitoh 10000 : 26667;
359699c85afSxtraeme break;
360699c85afSxtraeme case 1:
361699c85afSxtraeme bus_clock = 13333;
362699c85afSxtraeme break;
363699c85afSxtraeme case 2:
364699c85afSxtraeme bus_clock = 20000;
365699c85afSxtraeme break;
366699c85afSxtraeme case 3:
36795c5c320Smsaitoh bus_clock = 16667;
36895c5c320Smsaitoh break;
36995c5c320Smsaitoh case 4:
37095c5c320Smsaitoh bus_clock = 33333;
371699c85afSxtraeme break;
372699c85afSxtraeme default:
373699c85afSxtraeme aprint_debug("%s: unknown Pentium 4 (model %d) "
374699c85afSxtraeme "EBC_FREQUENCY_ID value %d\n",
375699c85afSxtraeme device_xname(ci->ci_dev),
376b1a32cacSmsaitoh CPUID_TO_MODEL(ci->ci_signature), bus);
377699c85afSxtraeme break;
378699c85afSxtraeme }
379699c85afSxtraeme }
380699c85afSxtraeme
381699c85afSxtraeme return bus_clock;
382699c85afSxtraeme }
383