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
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 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));
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