xref: /netbsd-src/sys/arch/x86/x86/intel_busclock.c (revision f82d7874c259b2a6cc59b714f844919f32bf7b51)
1 /*	$NetBSD: intel_busclock.c,v 1.5 2008/04/28 20:23:40 martin 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.5 2008/04/28 20:23:40 martin Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/cpu.h>
38 
39 #include <machine/specialreg.h>
40 #include <machine/pio.h>
41 #include <machine/cpufunc.h>
42 
43 #include <x86/cpuvar.h>
44 #include <x86/cpufunc.h>
45 
46 int
47 via_get_bus_clock(struct cpu_info *ci)
48 {
49 	uint64_t msr;
50 	int bus, bus_clock = 0;
51 
52 	msr = rdmsr(MSR_EBL_CR_POWERON);
53 	bus = (msr >> 18) & 0x3;
54 	switch (bus) {
55 	case 0:
56 		bus_clock = 10000;
57 		break;
58 	case 1:
59 		bus_clock = 13333;
60 		break;
61 	case 2:
62 		bus_clock = 20000;
63 		break;
64 	case 3:
65 		bus_clock = 16667;
66 		break;
67 	default:
68 		break;
69 	}
70 
71 	return bus_clock;
72 }
73 
74 int
75 p3_get_bus_clock(struct cpu_info *ci)
76 {
77 	uint64_t msr;
78 	int bus, bus_clock = 0;
79 
80 	switch (CPUID2MODEL(ci->ci_signature)) {
81 	case 0x9: /* Pentium M (130 nm, Banias) */
82 		bus_clock = 10000;
83 		break;
84 	case 0xd: /* Pentium M (90 nm, Dothan) */
85 		msr = rdmsr(MSR_FSB_FREQ);
86 		bus = (msr >> 0) & 0x7;
87 		switch (bus) {
88 		case 0:
89 			bus_clock = 10000;
90 			break;
91 		case 1:
92 			bus_clock = 13333;
93 			break;
94 		default:
95 			aprint_debug("%s: unknown Pentium M FSB_FREQ "
96 			    "value %d", device_xname(ci->ci_dev), bus);
97 			goto print_msr;
98 		}
99 		break;
100 	case 0xe: /* Core Duo/Solo */
101 	case 0xf: /* Core Xeon */
102 		msr = rdmsr(MSR_FSB_FREQ);
103 		bus = (msr >> 0) & 0x7;
104 		switch (bus) {
105 		case 5:
106 			bus_clock = 10000;
107 			break;
108 		case 1:
109 			bus_clock = 13333;
110 			break;
111 		case 3:
112 			bus_clock = 16667;
113 			break;
114 		case 2:
115 			bus_clock = 20000;
116 			break;
117 		case 0:
118 			bus_clock = 26667;
119 			break;
120 		case 4:
121 			bus_clock = 33333;
122 			break;
123 		default:
124 			aprint_debug("%s: unknown Core FSB_FREQ value %d",
125 			    device_xname(ci->ci_dev), bus);
126 			goto print_msr;
127 		}
128 		break;
129 	case 0x1: /* Pentium Pro, model 1 */
130 	case 0x3: /* Pentium II, model 3 */
131 	case 0x5: /* Pentium II, II Xeon, Celeron, model 5 */
132 	case 0x6: /* Celeron, model 6 */
133 	case 0x7: /* Pentium III, III Xeon, model 7 */
134 	case 0x8: /* Pentium III, III Xeon, Celeron, model 8 */
135 	case 0xa: /* Pentium III Xeon, model A */
136 	case 0xb: /* Pentium III, model B */
137 		msr = rdmsr(MSR_EBL_CR_POWERON);
138 		bus = (msr >> 18) & 0x3;
139 		switch (bus) {
140 		case 0:
141 			bus_clock = 6666;
142 			break;
143 		case 1:
144 			bus_clock = 13333;
145 			break;
146 		case 2:
147 			bus_clock = 10000;
148 			break;
149 		default:
150 			aprint_debug("%s: unknown i686 EBL_CR_POWERON "
151 			    "value %d ", device_xname(ci->ci_dev), bus);
152 			goto print_msr;
153 		}
154 		break;
155 	default:
156 		aprint_debug("%s: unknown i686 model %d, can't get bus clock",
157 		    device_xname(ci->ci_dev),
158 		    CPUID2MODEL(ci->ci_signature));
159 print_msr:
160 		/*
161 		 * Show the EBL_CR_POWERON MSR, so we'll at least have
162 		 * some extra information, such as clock ratio, etc.
163 		 */
164 		aprint_debug(" (0x%" PRIu64 ")\n", rdmsr(MSR_EBL_CR_POWERON));
165 		break;
166 	}
167 
168 	return bus_clock;
169 }
170 
171 int
172 p4_get_bus_clock(struct cpu_info *ci)
173 {
174 	uint64_t msr;
175 	int bus, bus_clock = 0;
176 
177 	msr = rdmsr(MSR_EBC_FREQUENCY_ID);
178 	if (CPUID2MODEL(ci->ci_signature) < 2) {
179 		bus = (msr >> 21) & 0x7;
180 		switch (bus) {
181 		case 0:
182 			bus_clock = 10000;
183 			break;
184 		case 1:
185 			bus_clock = 13333;
186 			break;
187 		default:
188 			aprint_debug("%s: unknown Pentium 4 (model %d) "
189 			    "EBC_FREQUENCY_ID value %d\n",
190 			    device_xname(ci->ci_dev),
191 			    CPUID2MODEL(ci->ci_signature), bus);
192 			break;
193 		}
194 	} else {
195 		bus = (msr >> 16) & 0x7;
196 		switch (bus) {
197 		case 0:
198 			bus_clock = (CPUID2MODEL(ci->ci_signature) == 2) ?
199 			    10000 : 26666;
200 			break;
201 		case 1:
202 			bus_clock = 13333;
203 			break;
204 		case 2:
205 			bus_clock = 20000;
206 			break;
207 		case 3:
208 			bus_clock = 16666;
209 			break;
210 		default:
211 			aprint_debug("%s: unknown Pentium 4 (model %d) "
212 			    "EBC_FREQUENCY_ID value %d\n",
213 			    device_xname(ci->ci_dev),
214 			    CPUID2MODEL(ci->ci_signature), bus);
215 			break;
216 		}
217 	}
218 
219 	return bus_clock;
220 }
221