xref: /netbsd-src/sys/arch/x86/x86/intel_busclock.c (revision c89ae296707a1b850a02cf2732d7e1b2e61b7efc)
1 /*	$NetBSD: intel_busclock.c,v 1.26 2023/01/20 01:35:03 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.26 2023/01/20 01:35:03 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
via_get_bus_clock(struct cpu_info * ci)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
viac7_get_bus_clock(struct cpu_info * ci)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
p3_get_bus_clock(struct cpu_info * ci)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 attempting 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
p4_get_bus_clock(struct cpu_info * ci)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