xref: /netbsd-src/sys/arch/x86/x86/intel_busclock.c (revision c89ae296707a1b850a02cf2732d7e1b2e61b7efc)
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