Revert "rename amd64 architecture to x86_64"
[dragonfly.git] / sys / platform / pc64 / amd64 / est.c
1 /*      $NetBSD: est.c,v 1.25 2006/06/18 16:39:56 nonaka 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  * Copyright (c) 2004 The NetBSD Foundation, Inc.
30  * All rights reserved.
31  *
32  * Redistribution and use in source and binary forms, with or without
33  * modification, are permitted provided that the following conditions
34  * are met:
35  * 1. Redistributions of source code must retain the above copyright
36  *    notice, this list of conditions and the following disclaimer.
37  * 2. Redistributions in binary form must reproduce the above copyright
38  *    notice, this list of conditions and the following disclaimer in the
39  *    documentation and/or other materials provided with the distribution.
40  * 3. All advertising materials mentioning features or use of this software
41  *    must display the following acknowledgement:
42  *        This product includes software developed by the NetBSD
43  *        Foundation, Inc. and its contributors.
44  * 4. Neither the name of The NetBSD Foundation nor the names of its
45  *    contributors may be used to endorse or promote products derived
46  *    from this software without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
49  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
52  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58  * POSSIBILITY OF SUCH DAMAGE.
59  */
60
61 /*
62  * This is a driver for Intel's Enhanced SpeedStep Technology (EST),
63  * as implemented in Pentium M processors.
64  *
65  * Reference documentation:
66  *
67  * - IA-32 Intel Architecture Software Developer's Manual, Volume 3:
68  *   System Programming Guide.
69  *   Section 13.14, Enhanced Intel SpeedStep technology.
70  *   Table B-2, MSRs in Pentium M Processors.
71  *   http://www.intel.com/design/pentium4/manuals/253668.htm
72  *
73  * - Intel Pentium M Processor Datasheet.
74  *   Table 5, Voltage and Current Specifications.
75  *   http://www.intel.com/design/mobile/datashts/252612.htm
76  *
77  * - Intel Pentium M Processor on 90 nm Process with 2-MB L2 Cache Datasheet
78  *   Table 3-4, 3-5, 3-6, Voltage and Current Specifications.
79  *   http://www.intel.com/design/mobile/datashts/302189.htm
80  *
81  * - Linux cpufreq patches, speedstep-centrino.c.
82  *   Encoding of MSR_PERF_CTL and MSR_PERF_STATUS.
83  *   http://www.codemonkey.org.uk/projects/cpufreq/cpufreq-2.4.22-pre6-1.gz
84  *
85  *   ACPI objects: _PCT is MSR location, _PSS is freq/voltage, _PPC is caps.
86  *
87  * $NetBSD: est.c,v 1.25 2006/06/18 16:39:56 nonaka Exp $
88  * $DragonFly: src/sys/platform/pc32/i386/est.c,v 1.11 2008/06/05 18:06:32 swildner Exp $
89  */
90
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/malloc.h>
94 #include <sys/kernel.h>
95 #include <sys/module.h>
96 #include <sys/sysctl.h>
97
98 #include <machine/cpu.h>
99 #include <machine/md_var.h>
100 #include <machine/specialreg.h>
101
102
103 struct fq_info {
104         int mhz;
105         int mv;
106 };
107
108 /* Ultra Low Voltage Intel Pentium M processor 900 MHz */
109 static const struct fq_info pentium_m_900[] = {
110         {  900, 1004 },
111         {  800,  988 },
112         {  600,  844 },
113 };
114
115 /* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */
116 static const struct fq_info pentium_m_1000[] = {
117         { 1000, 1004 },
118         {  900,  988 },
119         {  800,  972 },
120         {  600,  844 },
121 };
122
123 /* Low Voltage Intel Pentium M processor 1.10 GHz */
124 static const struct fq_info pentium_m_1100[] = {
125         { 1100, 1180 },
126         { 1000, 1164 },
127         {  900, 1100 },
128         {  800, 1020 },
129         {  600,  956 },
130 };
131
132 /* Low Voltage Intel Pentium M processor 1.20 GHz */
133 static const struct fq_info pentium_m_1200[] = {
134         { 1200, 1180 },
135         { 1100, 1164 },
136         { 1000, 1100 },
137         {  900, 1020 },
138         {  800, 1004 },
139         {  600,  956 },
140 };
141
142 /* Low Voltage Intel Pentium M processor 1.30 GHz */
143 static const struct fq_info pentium_m_1300_lv[] = {
144         { 1300, 1180 },
145         { 1200, 1164 },
146         { 1100, 1100 },
147         { 1000, 1020 },
148         {  900, 1004 },
149         {  800,  988 },
150         {  600,  956 },
151 };
152
153 /* Intel Pentium M processor 1.30 GHz */
154 static const struct fq_info pentium_m_1300[] = {
155         { 1300, 1388 },
156         { 1200, 1356 },
157         { 1000, 1292 },
158         {  800, 1260 },
159         {  600,  956 },
160 };
161
162 /* Intel Pentium M processor 1.40 GHz */
163 static const struct fq_info pentium_m_1400[] = {
164         { 1400, 1484 },
165         { 1200, 1436 },
166         { 1000, 1308 },
167         {  800, 1180 },
168         {  600,  956 }
169 };
170
171 /* Intel Pentium M processor 1.50 GHz */
172 static const struct fq_info pentium_m_1500[] = {
173         { 1500, 1484 },
174         { 1400, 1452 },
175         { 1200, 1356 },
176         { 1000, 1228 },
177         {  800, 1116 },
178         {  600,  956 }
179 };
180
181 /* Intel Pentium M processor 1.60 GHz */
182 static const struct fq_info pentium_m_1600[] = {
183         { 1600, 1484 },
184         { 1400, 1420 },
185         { 1200, 1276 },
186         { 1000, 1164 },
187         {  800, 1036 },
188         {  600,  956 }
189 };
190
191 /* Intel Pentium M processor 1.70 GHz */
192 static const struct fq_info pentium_m_1700[] = {
193         { 1700, 1484 },
194         { 1400, 1308 },
195         { 1200, 1228 },
196         { 1000, 1116 },
197         {  800, 1004 },
198         {  600,  956 }
199 };
200
201 /* Intel Pentium M processor 723 Ultra Low Voltage 1.0 GHz */
202 static const struct fq_info pentium_m_n723[] = {
203         { 1000,  940 },
204         {  900,  908 },
205         {  800,  876 },
206         {  600,  812 }
207 };
208
209 /* Intel Pentium M processor 733 Ultra Low Voltage 1.1 GHz */
210 static const struct fq_info pentium_m_n733[] = {
211         { 1100,  940 },
212         { 1000,  924 },
213         {  900,  892 },
214         {  800,  876 },
215         {  600,  812 }
216 };
217
218 /* Intel Pentium M processor 753 Ultra Low Voltage 1.2 GHz */
219 static const struct fq_info pentium_m_n753[] = {
220         { 1200,  940 },
221         { 1100,  924 },
222         { 1000,  908 },
223         {  900,  876 },
224         {  800,  860 },
225         {  600,  812 }
226 };
227
228 /* Intel Pentium M processor 773 Ultra Low Voltage 1.3 GHz */
229 static const struct fq_info pentium_m_n773[] = {
230         { 1300,  940 },
231         { 1200,  924 },
232         { 1100,  908 },
233         { 1000,  892 },
234         {  900,  876 },
235         {  800,  860 },
236         {  600,  812 }
237 };
238
239 /* Intel Pentium M processor 738 Low Voltage 1.4 GHz */
240 static const struct fq_info pentium_m_n738[] = {
241         { 1400, 1116 },
242         { 1300, 1116 },
243         { 1200, 1100 },
244         { 1100, 1068 },
245         { 1000, 1052 },
246         {  900, 1036 },
247         {  800, 1020 },
248         {  600,  988 }
249 };
250
251 /* Intel Pentium M processor 758 Low Voltage 1.5 GHz */
252 static const struct fq_info pentium_m_n758[] = {
253         { 1500, 1116 },
254         { 1400, 1116 },
255         { 1300, 1100 },
256         { 1200, 1084 },
257         { 1100, 1068 },
258         { 1000, 1052 },
259         {  900, 1036 },
260         {  800, 1020 },
261         {  600,  988 }
262 };
263
264 /* Intel Pentium M processor 778 Low Voltage 1.6 GHz */
265 static const struct fq_info pentium_m_n778[] = {
266         { 1600, 1116 },
267         { 1500, 1116 },
268         { 1400, 1100 },
269         { 1300, 1184 },
270         { 1200, 1068 },
271         { 1100, 1052 },
272         { 1000, 1052 },
273         {  900, 1036 },
274         {  800, 1020 },
275         {  600,  988 }
276 };
277
278 /* Intel Pentium M processor 710 1.4 GHz */
279 static const struct fq_info pentium_m_n710[] = {
280         { 1400, 1340 },
281         { 1200, 1228 },
282         { 1000, 1148 },
283         {  800, 1068 },
284         {  600,  998 }
285 };
286
287 /* Intel Pentium M processor 715 1.5 GHz */
288 static const struct fq_info pentium_m_n715[] = {
289         { 1500, 1340 },
290         { 1200, 1228 },
291         { 1000, 1148 },
292         {  800, 1068 },
293         {  600,  988 }
294 };
295
296 /* Intel Pentium M processor 725 1.6 GHz */
297 static const struct fq_info pentium_m_n725[] = {
298         { 1600, 1340 },
299         { 1400, 1276 },
300         { 1200, 1212 },
301         { 1000, 1132 },
302         {  800, 1068 },
303         {  600,  988 }
304 };
305
306 /* Intel Pentium M processor 730 1.6 GHz */
307 static const struct fq_info pentium_m_n730[] = {
308        { 1600, 1308 },
309        { 1333, 1260 },
310        { 1200, 1212 },
311        { 1067, 1180 },
312        {  800,  988 }
313 };
314
315 /* Intel Pentium M processor 735 1.7 GHz */
316 static const struct fq_info pentium_m_n735[] = {
317         { 1700, 1340 },
318         { 1400, 1244 },
319         { 1200, 1180 },
320         { 1000, 1116 },
321         {  800, 1052 },
322         {  600,  988 }
323 };
324
325 /* Intel Pentium M processor 740 1.73 GHz */
326 static const struct fq_info pentium_m_n740[] = {
327        { 1733, 1356 },
328        { 1333, 1212 },
329        { 1067, 1100 },
330        {  800,  988 },
331 };
332
333 /* Intel Pentium M processor 740 1.73 GHz (988-1308mV version?) */
334 static const struct fq_info pentium_m_n740_2[] = {
335         { 1733, 1308 },
336         { 1333, 1148 },
337         { 1067, 1068 },
338         {  800,  988 }
339 };
340
341 /* Intel Pentium M processor 745 1.8 GHz */
342 static const struct fq_info pentium_m_n745[] = {
343         { 1800, 1340 },
344         { 1600, 1292 },
345         { 1400, 1228 },
346         { 1200, 1164 },
347         { 1000, 1116 },
348         {  800, 1052 },
349         {  600,  988 }
350 };
351
352 /* Intel Pentium M processor 750 1.86 GHz */
353 /* values extracted from \_PR\NPSS (via _PSS) SDST ACPI table */
354 static const struct fq_info pentium_m_n750[] = {
355         { 1867, 1308 },
356         { 1600, 1228 },
357         { 1333, 1148 },
358         { 1067, 1068 },
359         {  800,  988 }
360 };
361
362 static const struct fq_info pentium_m_n750_2[] = {
363         { 1867, 1356 },
364         { 1600, 1228 },
365         { 1333, 1148 },
366         { 1067, 1068 },
367         {  800,  988 }
368 };
369
370 /* Intel Pentium M processor 755 2.0 GHz */
371 static const struct fq_info pentium_m_n755[] = {
372         { 2000, 1340 },
373         { 1800, 1292 },
374         { 1600, 1244 },
375         { 1400, 1196 },
376         { 1200, 1148 },
377         { 1000, 1100 },
378         {  800, 1052 },
379         {  600,  988 }
380 };
381
382 /* Intel Pentium M processor 760 2.0 GHz */
383 static const struct fq_info pentium_m_n760[] = {
384         { 2000, 1356 },
385         { 1600, 1244 },
386         { 1333, 1164 },
387         { 1067, 1084 },
388         {  800,  988 }
389 };
390
391 /* Intel Pentium M processor 760 2.0 GHz */
392 static const struct fq_info pentium_m_n760_2[] = {
393         { 2000, 1308 },
394         { 1600, 1244 },
395         { 1333, 1164 },
396         { 1067, 1084 },
397         {  800,  988 }
398 };
399
400 /* Intel Pentium M processor 765 2.1 GHz */
401 static const struct fq_info pentium_m_n765[] = {
402         { 2100, 1340 },
403         { 1800, 1276 },
404         { 1600, 1228 },
405         { 1400, 1180 },
406         { 1200, 1132 },
407         { 1000, 1084 },
408         {  800, 1036 },
409         {  600,  988 }
410 };
411
412 /* Intel Pentium M processor 770 2.13 GHz */
413 static const struct fq_info pentium_m_n770[] = {
414         { 2133, 1551 },
415         { 1800, 1429 },
416         { 1600, 1356 },
417         { 1400, 1180 },
418         { 1200, 1132 },
419         { 1000, 1084 },
420         {  800, 1036 },
421         {  600,  988 }
422 };
423
424 /* Intel Pentium M processor 770 2.13 GHz */
425 static const struct fq_info pentium_m_n770_2[] = {
426         { 2133, 1356 },
427         { 1867, 1292 },
428         { 1600, 1212 },
429         { 1333, 1148 },
430         { 1067, 1068 },
431         {  800,  988 }
432 };
433
434 /* Intel Pentium Core Duo T2300 */
435 static const struct fq_info pentium_core_duo_t2300[] = {
436         { 1666, 1404 },
437         { 1500, 1404 },
438         { 1333, 1404 },
439         { 1167, 1404 },
440         { 1000, 1004 },
441         {  667, 1004 },
442         {  333, 1004 },
443         {  167, 1004 },
444 };
445
446 static const struct fq_info pentium_core2_duo_t7500[] = {
447         { 2200, 1420 },
448         { 1600, 1212 },
449         { 1200, 1068 },
450         {  800,  988 },
451 };
452
453 struct fqlist {
454         const char *brand_tag;
455         const u_int cpu_id;
456         size_t tablec;
457         const struct fq_info *table;
458         const int fsbmult; /* in multiples of 133 MHz */
459 };
460
461 #define ENTRY(s, i, v, f)       { s, i, sizeof(v) / sizeof((v)[0]), v, f }
462 static const struct fqlist pentium_m[] = { /* Banias */
463         ENTRY(" 900", 0x0695, pentium_m_900,  3),
464         ENTRY("1000", 0x0695, pentium_m_1000, 3),
465         ENTRY("1100", 0x0695, pentium_m_1100, 3),
466         ENTRY("1200", 0x0695, pentium_m_1200, 3),
467         ENTRY("1300", 0x0695, pentium_m_1300, 3),
468         ENTRY("1300", 0x0695, pentium_m_1300_lv, 3),
469         ENTRY("1400", 0x0695, pentium_m_1400, 3),
470         ENTRY("1500", 0x0695, pentium_m_1500, 3),
471         ENTRY("1600", 0x0695, pentium_m_1600, 3),
472         ENTRY("1700", 0x0695, pentium_m_1700, 3),
473 };
474
475 static const struct fqlist pentium_m_dothan[] = {
476
477         /* low voltage CPUs */
478         ENTRY("1.00", 0x06d8, pentium_m_n723, 3),
479         ENTRY("1.10", 0x06d6, pentium_m_n733, 3),
480         ENTRY("1.20", 0x06d8, pentium_m_n753, 3),
481         ENTRY("1.30", 0, pentium_m_n773, 3), /* does this exist? */
482
483         /* ultra low voltage CPUs */
484         ENTRY("1.40", 0x06d6, pentium_m_n738, 3),
485         ENTRY("1.50", 0x06d8, pentium_m_n758, 3),
486         ENTRY("1.60", 0x06d8, pentium_m_n778, 3),
487
488         /* 'regular' 400 MHz FSB CPUs */
489         ENTRY("1.40", 0x06d6, pentium_m_n710, 3),
490         ENTRY("1.50", 0x06d6, pentium_m_n715, 3),
491         ENTRY("1.50", 0x06d8, pentium_m_n715, 3),
492         ENTRY("1.60", 0x06d6, pentium_m_n725, 3),
493         ENTRY("1.70", 0x06d6, pentium_m_n735, 3),
494         ENTRY("1.80", 0x06d6, pentium_m_n745, 3),
495         ENTRY("2.00", 0x06d6, pentium_m_n755, 3),
496         ENTRY("2.10", 0x06d6, pentium_m_n765, 3),
497
498         /* 533 MHz FSB CPUs */
499         ENTRY("1.60", 0x06d8, pentium_m_n730, 4),
500         ENTRY("1.73", 0x06d8, pentium_m_n740, 4),
501         ENTRY("1.73", 0x06d8, pentium_m_n740_2, 4),
502         ENTRY("1.86", 0x06d8, pentium_m_n750, 4),
503         ENTRY("1.86", 0x06d8, pentium_m_n750_2, 4),
504         ENTRY("2.00", 0x06d8, pentium_m_n760, 4),
505         ENTRY("2.00", 0x06d8, pentium_m_n760_2, 4),
506         ENTRY("2.13", 0x06d8, pentium_m_n770, 4),
507         ENTRY("2.13", 0x06d8, pentium_m_n770_2, 4),
508
509
510 };
511
512 static const struct fqlist pentium_yonah[] = {
513
514         /* 666 MHz FSB CPUs */
515         ENTRY("1.66", 0x06e8, pentium_core_duo_t2300, 5 ),
516 };
517
518 static const struct fqlist pentium_merom[] = {
519
520         /* 800 MHz FSB CPUs */
521         ENTRY("2.20", 0x06fa, pentium_core2_duo_t7500, 6 ),
522 };
523
524 #undef ENTRY
525
526 struct est_cpu {
527         const char *brand_prefix;
528         const char *brand_suffix;
529         size_t listc;
530         const struct fqlist *list;
531 };
532
533 static const struct est_cpu est_cpus[] = {
534         {
535                 "Intel(R) Pentium(R) M processor ", "MHz",
536                 (sizeof(pentium_m) / sizeof(pentium_m[0])),
537                 pentium_m
538         },
539         {
540                 "Intel(R) Pentium(R) M processor ", "GHz",
541                 (sizeof(pentium_m_dothan) / sizeof(pentium_m_dothan[0])),
542                 pentium_m_dothan
543         },
544         {
545                 "Genuine Intel(R) CPU           T2300  @ ", "GHz",
546                 (sizeof(pentium_yonah) / sizeof(pentium_yonah[0])),
547                 pentium_yonah
548         },
549         {
550                 "Intel(R) Core(TM)2 Duo CPU     T7500  @ ", "GHz",
551                 (sizeof(pentium_merom) / sizeof(pentium_merom[0])),
552                 pentium_merom
553         },
554 };
555
556 #define NESTCPUS  (sizeof(est_cpus) / sizeof(est_cpus[0]))
557
558 #define MSR2MV(msr)     (((int) (msr) & 0xff) * 16 + 700)
559 #define MSR2MHZ(msr)    (((((int) (msr) >> 8) & 0xff) * 100 * fsbmult + 1)/ 3)
560 #define MV2MSR(mv)      ((((int) (mv) - 700) >> 4) & 0xff)
561 #define MHZ2MSR(mhz)    (((3 * (mhz + 30) / (100 * fsbmult)) & 0xff) << 8)
562 /* XXX 30 is slop to deal with the 33.333 MHz roundoff values */
563
564 /*
565  * Names and numbers from IA-32 System Programming Guide
566  * (not found in <machine/specialregs.h>
567  */
568 #define MSR_PERF_STATUS         0x198
569 #define MSR_PERF_CTL            0x199
570
571 static const struct fqlist *est_fqlist; /* not NULL if functional */
572 static int      fsbmult;
573
574 static const char est_desc[] = "Enhanced SpeedStep";
575
576 static char freqs_available[80];
577
578 static int
579 est_sysctl_helper(SYSCTL_HANDLER_ARGS)
580 {
581         uint64_t msr;
582         int      fq, oldfq, err = 0;
583         int      i;
584
585         if (est_fqlist == NULL)
586                 return (EOPNOTSUPP);
587
588         oldfq = MSR2MHZ(rdmsr(MSR_PERF_CTL));
589
590         if (req->newptr != NULL) {
591                 err = SYSCTL_IN(req, &fq, sizeof(fq));
592                 if (err)
593                         return err;
594
595                 if (fq != oldfq) {
596                         for (i = est_fqlist->tablec - 1; i > 0; i--) {
597                                 if (est_fqlist->table[i].mhz >= fq)
598                                         break;
599                         }
600                         fq = est_fqlist->table[i].mhz;
601                         msr = (rdmsr(MSR_PERF_CTL) & ~0xffffULL) |
602                             MV2MSR(est_fqlist->table[i].mv) |
603                             MHZ2MSR(est_fqlist->table[i].mhz);
604                         wrmsr(MSR_PERF_CTL, msr);
605                 }
606         } else {
607                 err = SYSCTL_OUT(req, &oldfq, sizeof(oldfq));
608         }
609
610         return err;
611 }
612
613 /*
614  * Look for a CPU matching hw.model
615  */
616 static const struct fqlist *
617 findcpu(const char *hwmodel, int mv)
618 {
619         const struct est_cpu    *ccpu;
620         const struct fqlist     *fql;
621         const char              *tag;
622         size_t                  len;
623         size_t                  i;
624         int k;
625
626         for (ccpu = est_cpus; ccpu < est_cpus + NESTCPUS; ++ccpu) {
627                 len = strlen(ccpu->brand_prefix);
628                 if (strncmp(ccpu->brand_prefix, hwmodel, len) != 0)
629                         continue;
630                 tag = hwmodel + len;
631                 for (i = 0; i < ccpu->listc; i++) {
632                         fql = &ccpu->list[i];
633                         len = strlen(fql->brand_tag);
634                         if (strncmp(fql->brand_tag, tag, len) != 0 ||
635                             strcmp(ccpu->brand_suffix, tag + len))
636                                 continue;
637
638                         if (fql->cpu_id == 0 || fql->cpu_id == cpu_id) {
639                                 /* verify operating point is in table, because
640                                    CPUID + brand_tag still isn't unique. */
641                                 for (k = fql->tablec - 1; k >= 0; k--) {
642                                         if (fql->table[k].mv == mv)
643                                                 return fql;
644                                 }
645                         }
646                 }
647         }
648         return(NULL);
649 }
650
651
652 static struct sysctl_ctx_list   machdep_est_ctx;
653
654 static int
655 est_init(void)
656 {
657         char                    hwmodel[128];
658         int                     mib[] = { CTL_HW, HW_MODEL };
659         size_t                  modellen = sizeof(hwmodel);
660         struct sysctl_oid       *oid, *leaf;
661         uint64_t                msr;
662         int                     mv;
663         size_t                  len, freq_len;
664         int                     err;
665         size_t                  i;
666
667         if ((cpu_feature2 & CPUID2_EST) == 0) {
668                 kprintf("Enhanced SpeedStep unsupported on this hardware.\n");
669                 return(EOPNOTSUPP);
670         }
671
672         modellen = sizeof(hwmodel);
673         err = kernel_sysctl(mib, 2, hwmodel, &modellen, NULL, 0, NULL);
674         if (err) {
675                 kprintf("kernel_sysctl hw.model failed\n");
676                 return(err);
677         }
678
679         msr = rdmsr(MSR_PERF_STATUS);
680         mv = MSR2MV(msr);
681         kprintf("%s (%d mV) ", est_desc, mv);
682
683         est_fqlist = findcpu(hwmodel, mv);
684         if (est_fqlist == NULL) {
685                 kprintf(" - unknown CPU or operating point"
686                        "(cpu_id:%#x, msr:%#jx).\n", cpu_id, (intmax_t)msr);
687                 return(EOPNOTSUPP);
688         }
689
690         /*
691          * OK, tell the user the available frequencies.
692          */
693         fsbmult = est_fqlist->fsbmult;
694         kprintf("%d MHz\n", MSR2MHZ(msr));
695
696         freq_len = est_fqlist->tablec * (sizeof("9999 ")-1) + 1;
697         if (freq_len >= sizeof(freqs_available)) {
698                 kprintf("increase the size of freqs_available[]\n");
699                 return(ENOMEM);
700         }
701         freqs_available[0] = '\0';
702         len = 0;
703         for (i = 0; i < est_fqlist->tablec; i++) {
704                 len += ksnprintf(freqs_available + len, freq_len - len, "%d%s",
705                     est_fqlist->table[i].mhz,
706                     i < est_fqlist->tablec - 1 ? " " : "");
707         }
708         kprintf("%s frequencies available (MHz): %s\n", est_desc,
709                freqs_available);
710
711         /*
712          * Setup the sysctl sub-tree machdep.est.*
713          */
714         oid = SYSCTL_ADD_NODE(&machdep_est_ctx,
715             SYSCTL_STATIC_CHILDREN(_machdep), OID_AUTO, "est",
716             CTLFLAG_RD, NULL, "");
717         if (oid == NULL)
718                 return(EOPNOTSUPP);
719         oid = SYSCTL_ADD_NODE(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
720             OID_AUTO, "frequency", CTLFLAG_RD, NULL, "");
721         if (oid == NULL)
722                 return(EOPNOTSUPP);
723         leaf = SYSCTL_ADD_PROC(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
724             OID_AUTO, "target", CTLTYPE_INT | CTLFLAG_RW, NULL, 0,
725             est_sysctl_helper, "I",
726             "Target CPU frequency for Enhanced SpeedStep");
727         if (leaf == NULL)
728                 return(EOPNOTSUPP);
729         leaf = SYSCTL_ADD_PROC(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
730             OID_AUTO, "current", CTLTYPE_INT | CTLFLAG_RD, NULL, 0,
731             est_sysctl_helper, "I",
732             "Current CPU frequency for Enhanced SpeedStep");
733         if (leaf == NULL)
734                 return(EOPNOTSUPP);
735         leaf = SYSCTL_ADD_STRING(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
736             OID_AUTO, "available", CTLFLAG_RD, freqs_available,
737             sizeof(freqs_available),
738             "CPU frequencies supported by Enhanced SpeedStep");
739         if (leaf == NULL)
740                 return(EOPNOTSUPP);
741
742         return(0);
743 }
744
745 static int
746 est_modevh(struct module *m __unused, int what, void *arg __unused)
747 {
748         int error;
749
750         switch (what) {
751         case MOD_LOAD:
752                 error = sysctl_ctx_init(&machdep_est_ctx);
753                 if (error != 0)
754                         break;
755                 error = est_init();
756                 break;
757         case MOD_UNLOAD:
758                 error = sysctl_ctx_free(&machdep_est_ctx);
759                 break;
760         default:
761                 error = EINVAL;
762                 break;
763         }
764         return(error);
765 }
766
767 static moduledata_t est_mod = {
768         "est",
769         est_modevh,
770         NULL,
771 };
772
773 DECLARE_MODULE(est, est_mod, SI_BOOT2_KLD, SI_ORDER_ANY);