scoutos / prex-0.9.0 / bsp / drv / dev / cpufreq / est.c @ 03e9c04a
History | View | Annotate | Download (13.2 KB)
1 | 03e9c04a | Brad Neuman | /* $OpenBSD: est.c,v 1.11 2005/03/07 06:59:14 mbalmer Exp $ */
|
---|---|---|---|
2 | /*
|
||
3 | * Copyright (c) 2003 Michael Eriksson.
|
||
4 | * All rights reserved.
|
||
5 | *
|
||
6 | * Redistribution and use in source and binary forms, with or without
|
||
7 | * modification, are permitted provided that the following conditions
|
||
8 | * are met:
|
||
9 | * 1. Redistributions of source code must retain the above copyright
|
||
10 | * notice, this list of conditions and the following disclaimer.
|
||
11 | * 2. Redistributions in binary form must reproduce the above copyright
|
||
12 | * notice, this list of conditions and the following disclaimer in the
|
||
13 | * documentation and/or other materials provided with the distribution.
|
||
14 | * 3. The name of the author may not be used to endorse or promote products
|
||
15 | * derived from this software without specific prior written permission.
|
||
16 | *
|
||
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
27 | */
|
||
28 | /*
|
||
29 | * This is a driver for Intel's Enhanced SpeedStep, as implemented in
|
||
30 | * Pentium M processors.
|
||
31 | *
|
||
32 | * Reference documentation:
|
||
33 | *
|
||
34 | * - IA-32 Intel Architecture Software Developer's Manual, Volume 3:
|
||
35 | * System Programming Guide.
|
||
36 | * Section 13.14, Enhanced Intel SpeedStep technology.
|
||
37 | * Table B-2, MSRs in Pentium M Processors.
|
||
38 | * http://www.intel.com/design/pentium4/manuals/245472.htm
|
||
39 | *
|
||
40 | * - Intel Pentium M Processor Datasheet.
|
||
41 | * Table 5, Voltage and Current Specifications.
|
||
42 | * http://www.intel.com/design/mobile/datashts/252612.htm
|
||
43 | *
|
||
44 | * - Intel Pentium M Processor on 90 nm Process with 2-MB L2 Cache Datasheet
|
||
45 | * Table 3-4, Voltage and Current Specifications.
|
||
46 | * http://www.intel.com/design/mobile/datashts/302189.htm
|
||
47 | *
|
||
48 | * - Linux cpufreq patches, speedstep-centrino.c.
|
||
49 | * Encoding of MSR_PERF_CTL and MSR_PERF_STATUS.
|
||
50 | * http://www.codemonkey.org.uk/projects/cpufreq/cpufreq-2.4.22-pre6-1.gz
|
||
51 | */
|
||
52 | |||
53 | /*
|
||
54 | * est.c - Intel enhanced speedstep driver from OpenBSD.
|
||
55 | */
|
||
56 | |||
57 | #include <driver.h> |
||
58 | #include <cpufreq.h> |
||
59 | #include <cpufunc.h> |
||
60 | #include <sys/ioctl.h> |
||
61 | |||
62 | /* #define DEBUG_EST 1 */
|
||
63 | |||
64 | #ifdef DEBUG_EST
|
||
65 | #define DPRINTF(a) printf a
|
||
66 | #else
|
||
67 | #define DPRINTF(a)
|
||
68 | #endif
|
||
69 | |||
70 | /* Status/control registers (from the IA-32 System Programming Guide). */
|
||
71 | #define MSR_PERF_STATUS 0x198 |
||
72 | #define MSR_PERF_CTL 0x199 |
||
73 | |||
74 | /* Register and bit for enabling SpeedStep. */
|
||
75 | #define MSR_MISC_ENABLE 0x1a0 |
||
76 | #define MSR_SS_ENABLE (1<<16) |
||
77 | |||
78 | static int est_probe(struct driver *); |
||
79 | static int est_init(struct driver *); |
||
80 | static int est_setperf(int); |
||
81 | static int est_getperf(void); |
||
82 | static void est_getinfo(struct cpufreqinfo *); |
||
83 | static int est_identify(char *); |
||
84 | |||
85 | static struct cpufreq_ops est_ops = { |
||
86 | /* setperf */ est_setperf,
|
||
87 | /* getpref */ est_getperf,
|
||
88 | /* getinfo */ est_getinfo,
|
||
89 | }; |
||
90 | |||
91 | struct driver est_driver = {
|
||
92 | /* name */ "est", |
||
93 | /* devops */ NULL, |
||
94 | /* flags */ 0, |
||
95 | /* flags */ 0, |
||
96 | /* probe */ est_probe,
|
||
97 | /* init */ est_init,
|
||
98 | /* shutdown */ NULL, |
||
99 | }; |
||
100 | |||
101 | /*
|
||
102 | * Frequency tables
|
||
103 | */
|
||
104 | struct fq_info {
|
||
105 | int mhz;
|
||
106 | int mv;
|
||
107 | }; |
||
108 | |||
109 | /* Ultra Low Voltage Intel Pentium M processor 900 MHz */
|
||
110 | static const struct fq_info pentium_m_900[] = { |
||
111 | { 900, 1004 }, |
||
112 | { 800, 988 }, |
||
113 | { 600, 844 }, |
||
114 | }; |
||
115 | |||
116 | /* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */
|
||
117 | static const struct fq_info pentium_m_1000[] = { |
||
118 | { 1000, 1004 }, |
||
119 | { 900, 988 }, |
||
120 | { 800, 972 }, |
||
121 | { 600, 844 }, |
||
122 | }; |
||
123 | |||
124 | /* Low Voltage Intel Pentium M processor 1.10 GHz */
|
||
125 | static const struct fq_info pentium_m_1100[] = { |
||
126 | { 1100, 1180 }, |
||
127 | { 1000, 1164 }, |
||
128 | { 900, 1100 }, |
||
129 | { 800, 1020 }, |
||
130 | { 600, 956 }, |
||
131 | }; |
||
132 | |||
133 | /* Low Voltage Intel Pentium M processor 1.20 GHz */
|
||
134 | static const struct fq_info pentium_m_1200[] = { |
||
135 | { 1200, 1180 }, |
||
136 | { 1100, 1164 }, |
||
137 | { 1000, 1100 }, |
||
138 | { 900, 1020 }, |
||
139 | { 800, 1004 }, |
||
140 | { 600, 956 }, |
||
141 | }; |
||
142 | |||
143 | /* Intel Pentium M processor 1.30 GHz */
|
||
144 | static const struct fq_info pentium_m_1300[] = { |
||
145 | { 1300, 1388 }, |
||
146 | { 1200, 1356 }, |
||
147 | { 1000, 1292 }, |
||
148 | { 800, 1260 }, |
||
149 | { 600, 956 }, |
||
150 | }; |
||
151 | |||
152 | /* Intel Pentium M processor 1.40 GHz */
|
||
153 | static const struct fq_info pentium_m_1400[] = { |
||
154 | { 1400, 1484 }, |
||
155 | { 1200, 1436 }, |
||
156 | { 1000, 1308 }, |
||
157 | { 800, 1180 }, |
||
158 | { 600, 956 } |
||
159 | }; |
||
160 | |||
161 | /* Intel Pentium M processor 1.50 GHz */
|
||
162 | static const struct fq_info pentium_m_1500[] = { |
||
163 | { 1500, 1484 }, |
||
164 | { 1400, 1452 }, |
||
165 | { 1200, 1356 }, |
||
166 | { 1000, 1228 }, |
||
167 | { 800, 1116 }, |
||
168 | { 600, 956 } |
||
169 | }; |
||
170 | |||
171 | /* Intel Pentium M processor 1.60 GHz */
|
||
172 | static const struct fq_info pentium_m_1600[] = { |
||
173 | { 1600, 1484 }, |
||
174 | { 1400, 1420 }, |
||
175 | { 1200, 1276 }, |
||
176 | { 1000, 1164 }, |
||
177 | { 800, 1036 }, |
||
178 | { 600, 956 } |
||
179 | }; |
||
180 | |||
181 | /* Intel Pentium M processor 1.70 GHz */
|
||
182 | static const struct fq_info pentium_m_1700[] = { |
||
183 | { 1700, 1484 }, |
||
184 | { 1400, 1308 }, |
||
185 | { 1200, 1228 }, |
||
186 | { 1000, 1116 }, |
||
187 | { 800, 1004 }, |
||
188 | { 600, 956 } |
||
189 | }; |
||
190 | |||
191 | |||
192 | /* Intel Pentium M processor 723 1.0 GHz */
|
||
193 | static const struct fq_info pentium_m_n723[] = { |
||
194 | { 1000, 940 }, |
||
195 | { 900, 908 }, |
||
196 | { 800, 876 }, |
||
197 | { 600, 812 } |
||
198 | }; |
||
199 | |||
200 | /* Intel Pentium M processor 733 1.1 GHz */
|
||
201 | static const struct fq_info pentium_m_n733[] = { |
||
202 | { 1100, 940 }, |
||
203 | { 1000, 924 }, |
||
204 | { 900, 892 }, |
||
205 | { 800, 876 }, |
||
206 | { 600, 812 } |
||
207 | }; |
||
208 | |||
209 | /* Intel Pentium M processor 753 1.2 GHz */
|
||
210 | static const struct fq_info pentium_m_n753[] = { |
||
211 | { 1200, 940 }, |
||
212 | { 1100, 924 }, |
||
213 | { 1000, 908 }, |
||
214 | { 900, 876 }, |
||
215 | { 800, 860 }, |
||
216 | { 600, 812 } |
||
217 | }; |
||
218 | |||
219 | /* Intel Pentium M processor 738 1.4 GHz */
|
||
220 | static const struct fq_info pentium_m_n738[] = { |
||
221 | { 1400, 1116 }, |
||
222 | { 1300, 1116 }, |
||
223 | { 1200, 1100 }, |
||
224 | { 1100, 1068 }, |
||
225 | { 1000, 1052 }, |
||
226 | { 900, 1036 }, |
||
227 | { 800, 1020 }, |
||
228 | { 600, 988 } |
||
229 | }; |
||
230 | |||
231 | #if 0
|
||
232 | /* Intel Pentium M processor 758 1.5 GHz */
|
||
233 | static const struct fq_info pentium_m_n758[] = {
|
||
234 | { 1500, 1116 },
|
||
235 | { 1400, 1116 },
|
||
236 | { 1300, 1100 },
|
||
237 | { 1200, 1084 },
|
||
238 | { 1100, 1068 },
|
||
239 | { 1000, 1052 },
|
||
240 | { 900, 1036 },
|
||
241 | { 800, 1020 },
|
||
242 | { 600, 988 }
|
||
243 | };
|
||
244 | #endif
|
||
245 | |||
246 | /* Intel Pentium M processor 715 1.5 GHz */
|
||
247 | static const struct fq_info pentium_m_n715[] = { |
||
248 | { 1500, 1340 }, |
||
249 | { 1200, 1228 }, |
||
250 | { 1000, 1148 }, |
||
251 | { 800, 1068 }, |
||
252 | { 600, 988 } |
||
253 | }; |
||
254 | |||
255 | /* Intel Pentium M processor 725 1.6 GHz */
|
||
256 | static const struct fq_info pentium_m_n725[] = { |
||
257 | { 1600, 1340 }, |
||
258 | { 1400, 1276 }, |
||
259 | { 1200, 1212 }, |
||
260 | { 1000, 1132 }, |
||
261 | { 800, 1068 }, |
||
262 | { 600, 988 } |
||
263 | }; |
||
264 | |||
265 | /* Intel Pentium M processor 735 1.7 GHz */
|
||
266 | static const struct fq_info pentium_m_n735[] = { |
||
267 | { 1700, 1340 }, |
||
268 | { 1400, 1244 }, |
||
269 | { 1200, 1180 }, |
||
270 | { 1000, 1116 }, |
||
271 | { 800, 1052 }, |
||
272 | { 600, 988 } |
||
273 | }; |
||
274 | |||
275 | /* Intel Pentium M processor 745 1.8 GHz */
|
||
276 | static const struct fq_info pentium_m_n745[] = { |
||
277 | { 1800, 1340 }, |
||
278 | { 1600, 1292 }, |
||
279 | { 1400, 1228 }, |
||
280 | { 1200, 1164 }, |
||
281 | { 1000, 1116 }, |
||
282 | { 800, 1052 }, |
||
283 | { 600, 988 } |
||
284 | }; |
||
285 | |||
286 | /* Intel Pentium M processor 755 2.0 GHz */
|
||
287 | static const struct fq_info pentium_m_n755[] = { |
||
288 | { 2000, 1340 }, |
||
289 | { 1800, 1292 }, |
||
290 | { 1600, 1244 }, |
||
291 | { 1400, 1196 }, |
||
292 | { 1200, 1148 }, |
||
293 | { 1000, 1100 }, |
||
294 | { 800, 1052 }, |
||
295 | { 600, 988 } |
||
296 | }; |
||
297 | |||
298 | /* Intel Pentium M processor 765 2.1 GHz */
|
||
299 | static const struct fq_info pentium_m_n765[] = { |
||
300 | { 2100, 1340 }, |
||
301 | { 1800, 1276 }, |
||
302 | { 1600, 1228 }, |
||
303 | { 1400, 1180 }, |
||
304 | { 1200, 1132 }, |
||
305 | { 1000, 1084 }, |
||
306 | { 800, 1036 }, |
||
307 | { 600, 988 } |
||
308 | }; |
||
309 | |||
310 | struct fqlist {
|
||
311 | const char *brand_tag; |
||
312 | const struct fq_info *table; |
||
313 | int n;
|
||
314 | }; |
||
315 | |||
316 | static const struct fqlist pentium_m[] = { |
||
317 | #define ENTRY(s, v) { s, v, (int)(sizeof(v) / sizeof((v)[0])) } |
||
318 | ENTRY(" 900", pentium_m_900),
|
||
319 | ENTRY("1000", pentium_m_1000),
|
||
320 | ENTRY("1100", pentium_m_1100),
|
||
321 | ENTRY("1200", pentium_m_1200),
|
||
322 | ENTRY("1300", pentium_m_1300),
|
||
323 | ENTRY("1400", pentium_m_1400),
|
||
324 | ENTRY("1500", pentium_m_1500),
|
||
325 | ENTRY("1600", pentium_m_1600),
|
||
326 | ENTRY("1700", pentium_m_1700),
|
||
327 | #undef ENTRY
|
||
328 | }; |
||
329 | |||
330 | static const struct fqlist pentium_m_dothan[] = { |
||
331 | #define ENTRY(s, v) { s, v, (int)(sizeof(v) / sizeof((v)[0])) } |
||
332 | ENTRY("1.00", pentium_m_n723),
|
||
333 | ENTRY("1.10", pentium_m_n733),
|
||
334 | ENTRY("1.20", pentium_m_n753),
|
||
335 | ENTRY("1.40", pentium_m_n738),
|
||
336 | #if 0
|
||
337 | ENTRY("1.50", pentium_m_n758),
|
||
338 | #endif
|
||
339 | ENTRY("1.50", pentium_m_n715),
|
||
340 | ENTRY("1.60", pentium_m_n725),
|
||
341 | ENTRY("1.70", pentium_m_n735),
|
||
342 | ENTRY("1.80", pentium_m_n745),
|
||
343 | ENTRY("2.00", pentium_m_n755),
|
||
344 | ENTRY("2.10", pentium_m_n765),
|
||
345 | #undef ENTRY
|
||
346 | }; |
||
347 | |||
348 | struct est_cpu {
|
||
349 | const char *brand_prefix; |
||
350 | const char *brand_suffix; |
||
351 | const struct fqlist *list; |
||
352 | int n;
|
||
353 | }; |
||
354 | |||
355 | static const struct est_cpu est_cpus[] = { |
||
356 | { |
||
357 | "Intel(R) Pentium(R) M processor ", "MHz", |
||
358 | pentium_m, |
||
359 | (int)(sizeof(pentium_m) / sizeof(pentium_m[0])) |
||
360 | }, |
||
361 | { |
||
362 | "Intel(R) Pentium(R) M processor ", "GHz", |
||
363 | pentium_m_dothan, |
||
364 | (int)(sizeof(pentium_m_dothan) / sizeof(pentium_m_dothan[0])) |
||
365 | }, |
||
366 | }; |
||
367 | |||
368 | #define NESTCPUS (int)(sizeof(est_cpus) / sizeof(est_cpus[0])) |
||
369 | |||
370 | |||
371 | #define MSRVALUE(mhz, mv) ((((mhz) / 100) << 8) | (((mv) - 700) / 16)) |
||
372 | #define MSR2MHZ(msr) (int)((((u_int) (msr) >> 8) & 0xff) * 100) |
||
373 | #define MSR2MV(msr) (((int) (msr) & 0xff) * 16 + 700) |
||
374 | |||
375 | static const struct fqlist *est_fqlist; |
||
376 | |||
377 | static int maxfreq; /* max speed in Mhz */ |
||
378 | static int maxvolts; /* max voltage in mV */ |
||
379 | static int curfreq; /* current speed in Mhz */ |
||
380 | static int curvolts; /* current voltage in mV */ |
||
381 | #ifdef CONFIG_DVS_EMULATION
|
||
382 | static int bochs; /* true if bochs is active */ |
||
383 | #endif
|
||
384 | |||
385 | /*
|
||
386 | * Set CPU performance
|
||
387 | *
|
||
388 | * @level: percent of cpu speed
|
||
389 | */
|
||
390 | static int |
||
391 | est_setperf(int level)
|
||
392 | { |
||
393 | int i;
|
||
394 | int fq, max_mhz;
|
||
395 | u_int msr_lo, msr_hi; |
||
396 | |||
397 | max_mhz = est_fqlist->table[0].mhz;
|
||
398 | fq = max_mhz * level / 100;
|
||
399 | |||
400 | for (i = est_fqlist->n - 1; i > 0; i--) |
||
401 | if (est_fqlist->table[i].mhz >= fq)
|
||
402 | break;
|
||
403 | |||
404 | if (est_fqlist->table[i].mhz == curfreq)
|
||
405 | return 0; |
||
406 | |||
407 | curfreq = est_fqlist->table[i].mhz; |
||
408 | curvolts = est_fqlist->table[i].mv; |
||
409 | #ifdef DEBUG_EST
|
||
410 | DPRINTF(("setperf: %dMHz %dmV\n", curfreq, curvolts));
|
||
411 | #endif
|
||
412 | #ifdef CONFIG_DVS_EMULATION
|
||
413 | if (bochs)
|
||
414 | return 0; |
||
415 | #endif
|
||
416 | rdmsr(MSR_PERF_CTL, &msr_lo, &msr_hi); |
||
417 | msr_lo = (msr_lo & ~0xffff) |
|
||
418 | MSRVALUE(est_fqlist->table[i].mhz, est_fqlist->table[i].mv); |
||
419 | wrmsr(MSR_PERF_CTL, msr_lo, msr_hi); |
||
420 | return 0; |
||
421 | } |
||
422 | |||
423 | /*
|
||
424 | * Get CPU performance
|
||
425 | */
|
||
426 | static int |
||
427 | est_getperf(void)
|
||
428 | { |
||
429 | int max_mhz;
|
||
430 | int level;
|
||
431 | |||
432 | max_mhz = est_fqlist->table[0].mhz;
|
||
433 | ASSERT(max_mhz); |
||
434 | level = curfreq * 100 / max_mhz;
|
||
435 | return level;
|
||
436 | } |
||
437 | |||
438 | static void |
||
439 | est_getinfo(struct cpufreqinfo *info)
|
||
440 | { |
||
441 | |||
442 | info->maxfreq = maxfreq; |
||
443 | info->maxvolts = maxvolts; |
||
444 | info->freq = curfreq; |
||
445 | info->volts = curvolts; |
||
446 | } |
||
447 | |||
448 | static int |
||
449 | est_identify(char *brand_str)
|
||
450 | { |
||
451 | int i, j, mhz, mv;
|
||
452 | size_t len; |
||
453 | const struct est_cpu *cpu; |
||
454 | u_int msr_lo, msr_hi; |
||
455 | char *tag;
|
||
456 | const struct fqlist *fql; |
||
457 | |||
458 | DPRINTF(("CPU brand: %s\n", brand_str));
|
||
459 | |||
460 | #ifdef CONFIG_DVS_EMULATION
|
||
461 | if (bochs) {
|
||
462 | msr_lo = 0x1031;
|
||
463 | cpu = &est_cpus[0];
|
||
464 | est_fqlist = &cpu->list[7];
|
||
465 | } else
|
||
466 | rdmsr(MSR_PERF_STATUS, &msr_lo, &msr_hi); |
||
467 | #else
|
||
468 | rdmsr(MSR_PERF_STATUS, &msr_lo, &msr_hi); |
||
469 | #endif
|
||
470 | mhz = MSR2MHZ(msr_lo); |
||
471 | mv = MSR2MV(msr_lo); |
||
472 | |||
473 | #ifdef CONFIG_DVS_EMULATION
|
||
474 | if (!bochs) {
|
||
475 | #endif
|
||
476 | /*
|
||
477 | * Look for a CPU matching brand_str.
|
||
478 | */
|
||
479 | for (i = 0; est_fqlist == NULL && i < NESTCPUS; i++) { |
||
480 | cpu = &est_cpus[i]; |
||
481 | len = strnlen(cpu->brand_prefix, 48);
|
||
482 | if (strncmp(cpu->brand_prefix, brand_str, len) != 0) |
||
483 | continue;
|
||
484 | tag = brand_str + len; |
||
485 | for (j = 0; j < cpu->n; j++) { |
||
486 | fql = &cpu->list[j]; |
||
487 | len = strnlen(fql->brand_tag, 48);
|
||
488 | if (!strncmp(fql->brand_tag, tag, len) &&
|
||
489 | !strncmp(cpu->brand_suffix, tag + len, 48)) {
|
||
490 | est_fqlist = fql; |
||
491 | break;
|
||
492 | } |
||
493 | } |
||
494 | } |
||
495 | if (est_fqlist == NULL) { |
||
496 | DPRINTF(("Unknown EST cpu, no changes possible\n"));
|
||
497 | return ENXIO;
|
||
498 | } |
||
499 | |||
500 | /*
|
||
501 | * Check that the current operating point is in our list.
|
||
502 | */
|
||
503 | for (i = est_fqlist->n - 1; i >= 0; i--) |
||
504 | if (est_fqlist->table[i].mhz == mhz)
|
||
505 | break;
|
||
506 | if (i < 0) { |
||
507 | DPRINTF((" (not in table)\n"));
|
||
508 | return ENXIO;
|
||
509 | } |
||
510 | #ifdef CONFIG_DVS_EMULATION
|
||
511 | } |
||
512 | #endif
|
||
513 | /*
|
||
514 | * Store current state
|
||
515 | */
|
||
516 | maxfreq = est_fqlist->table[0].mhz;
|
||
517 | maxvolts = est_fqlist->table[0].mv;
|
||
518 | curfreq = mhz; |
||
519 | curvolts = mv; |
||
520 | return 0; |
||
521 | } |
||
522 | |||
523 | static int |
||
524 | est_probe(struct driver *self)
|
||
525 | { |
||
526 | u_int regs[4];
|
||
527 | char brand_str[49]; |
||
528 | char *p, *q;
|
||
529 | u_int cpu_id; |
||
530 | |||
531 | #ifdef CONFIG_DVS_EMULATION
|
||
532 | bochs = 0;
|
||
533 | if (bus_read_8(0xe9) == 0xe9) { |
||
534 | /*
|
||
535 | * Detect Bochs. Fake the cpuid value.
|
||
536 | */
|
||
537 | bochs = 1;
|
||
538 | cpu_id = 0x6d6;
|
||
539 | strlcpy(brand_str, |
||
540 | "Intel(R) Pentium(R) M processor 1600MHz",
|
||
541 | sizeof(brand_str));
|
||
542 | DPRINTF(("CPU ID: %08x\n", cpu_id));
|
||
543 | return est_identify(brand_str);
|
||
544 | } |
||
545 | #endif
|
||
546 | /*
|
||
547 | * Check enhanced speed step capability
|
||
548 | */
|
||
549 | cpuid(1, regs);
|
||
550 | cpu_id = regs[0];
|
||
551 | DPRINTF(("CPU ID: %08x\n", cpu_id));
|
||
552 | if ((regs[2] & 0x80) == 0) { |
||
553 | DPRINTF(("cpu: clock control not supported\n"));
|
||
554 | return ENXIO;
|
||
555 | } |
||
556 | |||
557 | /*
|
||
558 | * Get CPU brand string
|
||
559 | */
|
||
560 | cpuid(0x80000002, regs);
|
||
561 | memcpy(brand_str, regs, sizeof(regs));
|
||
562 | cpuid(0x80000003, regs);
|
||
563 | memcpy(brand_str + 16, regs, sizeof(regs)); |
||
564 | cpuid(0x80000004, regs);
|
||
565 | memcpy(brand_str + 32, regs, sizeof(regs)); |
||
566 | |||
567 | /* Store string with lef-align */
|
||
568 | p = q = brand_str; |
||
569 | while (*p == ' ') |
||
570 | p++; |
||
571 | while (*p)
|
||
572 | *q++ = *p++; |
||
573 | *q = '\0';
|
||
574 | |||
575 | return est_identify(brand_str);
|
||
576 | } |
||
577 | |||
578 | static int |
||
579 | est_init(struct driver *self)
|
||
580 | { |
||
581 | #ifdef DEBUG
|
||
582 | int i;
|
||
583 | #endif
|
||
584 | |||
585 | cpufreq_attach(&est_ops); |
||
586 | |||
587 | #ifdef DEBUG
|
||
588 | printf("Enhanced SpeedStep %d MHz (%d mV)\n", curfreq, curvolts);
|
||
589 | printf("Speeds: ");
|
||
590 | for (i = 0; i < est_fqlist->n; i++) |
||
591 | printf("%d%s", est_fqlist->table[i].mhz,
|
||
592 | i < est_fqlist->n - 1 ? ", " : " MHz\n"); |
||
593 | #endif
|
||
594 | return 0; |
||
595 | } |