Finish moving the kernel from tsc_freq (32 bits) to tsc_frequency (64 bits).
[dragonfly.git] / sys / platform / pc32 / i386 / identcpu.c
blob4f7f4a23f55e396d50c4d95236a8465bab18cc4f
1 /*
2 * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
3 * Copyright (c) 1992 Terrence R. Lambert.
4 * Copyright (c) 1997 KATO Takenori.
5 * Copyright (c) 2001 Tamotsu Hattori.
6 * Copyright (c) 2001 Mitsuru IWASAKI.
7 * All rights reserved.
9 * This code is derived from software contributed to Berkeley by
10 * William Jolitz.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
40 * from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp
41 * $FreeBSD: src/sys/i386/i386/identcpu.c,v 1.80.2.15 2003/04/11 17:06:41 jhb Exp $
42 * $DragonFly: src/sys/platform/pc32/i386/identcpu.c,v 1.21 2008/05/10 17:24:07 dillon Exp $
45 #include "opt_cpu.h"
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/sysctl.h>
51 #include <sys/lock.h>
53 #include <machine/asmacros.h>
54 #include <machine/clock.h>
55 #include <machine/cputypes.h>
56 #include <machine/segments.h>
57 #include <machine/specialreg.h>
58 #include <machine/md_var.h>
60 #include <machine_base/isa/intr_machdep.h>
62 #define IDENTBLUE_CYRIX486 0
63 #define IDENTBLUE_IBMCPU 1
64 #define IDENTBLUE_CYRIXM2 2
66 /* XXX - should be in header file: */
67 void printcpuinfo(void);
68 void finishidentcpu(void);
69 #if defined(I586_CPU) && defined(CPU_WT_ALLOC)
70 void enable_K5_wt_alloc(void);
71 void enable_K6_wt_alloc(void);
72 void enable_K6_2_wt_alloc(void);
73 #endif
74 void panicifcpuunsupported(void);
76 static void identifycyrix(void);
77 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
78 static void print_AMD_features(void);
79 #endif
80 static void print_AMD_info(void);
81 static void print_AMD_assoc(int i);
82 static void print_transmeta_info(void);
83 static void setup_tmx86_longrun(void);
85 int cpu_class = CPUCLASS_386;
86 u_int cpu_exthigh; /* Highest arg to extended CPUID */
87 u_int cyrix_did; /* Device ID of Cyrix CPU */
88 char machine[] = MACHINE;
89 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD,
90 machine, 0, "Machine class");
92 static char cpu_model[128];
93 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD,
94 cpu_model, 0, "Machine model");
96 static char cpu_brand[48];
98 #define MAX_ADDITIONAL_INFO 16
100 static const char *additional_cpu_info_ary[MAX_ADDITIONAL_INFO];
101 static u_int additional_cpu_info_count;
103 #define MAX_BRAND_INDEX 23
106 * Brand ID's according to Intel document AP-485, number 241618-31, published
107 * September 2006, page 42.
109 static const char *cpu_brandtable[MAX_BRAND_INDEX + 1] = {
110 NULL, /* No brand */
111 "Intel Celeron",
112 "Intel Pentium III",
113 "Intel Pentium III Xeon",
114 "Intel Pentium III",
115 NULL, /* Unspecified */
116 "Mobile Intel Pentium III-M",
117 "Mobile Intel Celeron",
118 "Intel Pentium 4",
119 "Intel Pentium 4",
120 "Intel Celeron",
121 "Intel Xeon",
122 "Intel Xeon MP",
123 NULL, /* Unspecified */
124 "Mobile Intel Pentium 4-M",
125 "Mobile Intel Celeron",
126 NULL, /* Unspecified */
127 "Mobile Genuine Intel",
128 "Intel Celeron M",
129 "Mobile Intel Celeron",
130 "Intel Celeron",
131 "Mobile Genuine Intel",
132 "Intel Pentium M",
133 "Mobile Intel Celeron"
136 static struct cpu_nameclass i386_cpus[] = {
137 { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */
138 { "i386SX", CPUCLASS_386 }, /* CPU_386SX */
139 { "i386DX", CPUCLASS_386 }, /* CPU_386 */
140 { "i486SX", CPUCLASS_486 }, /* CPU_486SX */
141 { "i486DX", CPUCLASS_486 }, /* CPU_486 */
142 { "Pentium", CPUCLASS_586 }, /* CPU_586 */
143 { "Cyrix 486", CPUCLASS_486 }, /* CPU_486DLC */
144 { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */
145 { "Cyrix 5x86", CPUCLASS_486 }, /* CPU_M1SC */
146 { "Cyrix 6x86", CPUCLASS_486 }, /* CPU_M1 */
147 { "Blue Lightning", CPUCLASS_486 }, /* CPU_BLUE */
148 { "Cyrix 6x86MX", CPUCLASS_686 }, /* CPU_M2 */
149 { "NexGen 586", CPUCLASS_386 }, /* CPU_NX586 (XXX) */
150 { "Cyrix 486S/DX", CPUCLASS_486 }, /* CPU_CY486DX */
151 { "Pentium II", CPUCLASS_686 }, /* CPU_PII */
152 { "Pentium III", CPUCLASS_686 }, /* CPU_PIII */
153 { "Pentium 4", CPUCLASS_686 }, /* CPU_P4 */
156 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
157 int has_f00f_bug = 0; /* Initialized so that it can be patched. */
158 #endif
160 void
161 printcpuinfo(void)
163 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
164 u_int regs[4], i;
165 #endif
166 char *brand;
168 cpu_class = i386_cpus[cpu].cpu_class;
169 kprintf("CPU: ");
170 strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof (cpu_model));
172 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
173 /* Check for extended CPUID information and a processor name. */
174 if (cpu_high > 0 &&
175 (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
176 strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
177 strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
178 strcmp(cpu_vendor, "TransmetaCPU") == 0)) {
179 do_cpuid(0x80000000, regs);
180 if (regs[0] >= 0x80000000) {
181 cpu_exthigh = regs[0];
182 if (cpu_exthigh >= 0x80000004) {
183 brand = cpu_brand;
184 for (i = 0x80000002; i < 0x80000005; i++) {
185 do_cpuid(i, regs);
186 memcpy(brand, regs, sizeof(regs));
187 brand += sizeof(regs);
193 if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
194 if ((cpu_id & 0xf00) > 0x300) {
195 u_int brand_index;
197 cpu_model[0] = '\0';
199 switch (cpu_id & 0x3000) {
200 case 0x1000:
201 strcpy(cpu_model, "Overdrive ");
202 break;
203 case 0x2000:
204 strcpy(cpu_model, "Dual ");
205 break;
208 switch (cpu_id & 0xf00) {
209 case 0x400:
210 strcat(cpu_model, "i486 ");
211 /* Check the particular flavor of 486 */
212 switch (cpu_id & 0xf0) {
213 case 0x00:
214 case 0x10:
215 strcat(cpu_model, "DX");
216 break;
217 case 0x20:
218 strcat(cpu_model, "SX");
219 break;
220 case 0x30:
221 strcat(cpu_model, "DX2");
222 break;
223 case 0x40:
224 strcat(cpu_model, "SL");
225 break;
226 case 0x50:
227 strcat(cpu_model, "SX2");
228 break;
229 case 0x70:
230 strcat(cpu_model,
231 "DX2 Write-Back Enhanced");
232 break;
233 case 0x80:
234 strcat(cpu_model, "DX4");
235 break;
237 break;
238 case 0x500:
239 /* Check the particular flavor of 586 */
240 strcat(cpu_model, "Pentium");
241 switch (cpu_id & 0xf0) {
242 case 0x00:
243 strcat(cpu_model, " A-step");
244 break;
245 case 0x10:
246 strcat(cpu_model, "/P5");
247 break;
248 case 0x20:
249 strcat(cpu_model, "/P54C");
250 break;
251 case 0x30:
252 strcat(cpu_model, "/P54T Overdrive");
253 break;
254 case 0x40:
255 strcat(cpu_model, "/P55C");
256 break;
257 case 0x70:
258 strcat(cpu_model, "/P54C");
259 break;
260 case 0x80:
261 strcat(cpu_model, "/P55C (quarter-micron)");
262 break;
263 default:
264 /* nothing */
265 break;
267 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
269 * XXX - If/when Intel fixes the bug, this
270 * should also check the version of the
271 * CPU, not just that it's a Pentium.
273 has_f00f_bug = 1;
274 #endif
275 break;
276 case 0x600:
277 /* Check the particular flavor of 686 */
278 switch (cpu_id & 0xf0) {
279 case 0x00:
280 strcat(cpu_model, "Pentium Pro A-step");
281 break;
282 case 0x10:
283 strcat(cpu_model, "Pentium Pro");
284 break;
285 case 0x30:
286 case 0x50:
287 case 0x60:
288 strcat(cpu_model,
289 "Pentium II/Pentium II Xeon/Celeron");
290 cpu = CPU_PII;
291 break;
292 case 0x70:
293 case 0x80:
294 case 0xa0:
295 case 0xb0:
296 strcat(cpu_model,
297 "Pentium III/Pentium III Xeon/Celeron");
298 cpu = CPU_PIII;
299 break;
300 default:
301 strcat(cpu_model, "Unknown 80686");
302 break;
304 break;
305 case 0xf00:
306 strcat(cpu_model, "Pentium 4");
307 cpu = CPU_P4;
308 break;
309 default:
310 strcat(cpu_model, "unknown");
311 break;
315 * If we didn't get a brand name from the extended
316 * CPUID, try to look it up in the brand table.
318 if (cpu_high > 0 && *cpu_brand == '\0') {
319 brand_index = cpu_procinfo & CPUID_BRAND_INDEX;
320 if (brand_index <= MAX_BRAND_INDEX &&
321 cpu_brandtable[brand_index] != NULL)
322 strcpy(cpu_brand,
323 cpu_brandtable[brand_index]);
326 } else if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
328 * Values taken from AMD Processor Recognition
329 * http://www.amd.com/K6/k6docs/pdf/20734g.pdf
330 * (also describes ``Features'' encodings.
332 strcpy(cpu_model, "AMD ");
333 switch (cpu_id & 0xFF0) {
334 case 0x410:
335 strcat(cpu_model, "Standard Am486DX");
336 break;
337 case 0x430:
338 strcat(cpu_model, "Enhanced Am486DX2 Write-Through");
339 break;
340 case 0x470:
341 strcat(cpu_model, "Enhanced Am486DX2 Write-Back");
342 break;
343 case 0x480:
344 strcat(cpu_model, "Enhanced Am486DX4/Am5x86 Write-Through");
345 break;
346 case 0x490:
347 strcat(cpu_model, "Enhanced Am486DX4/Am5x86 Write-Back");
348 break;
349 case 0x4E0:
350 strcat(cpu_model, "Am5x86 Write-Through");
351 break;
352 case 0x4F0:
353 strcat(cpu_model, "Am5x86 Write-Back");
354 break;
355 case 0x500:
356 strcat(cpu_model, "K5 model 0");
357 tsc_is_broken = 1;
358 break;
359 case 0x510:
360 strcat(cpu_model, "K5 model 1");
361 break;
362 case 0x520:
363 strcat(cpu_model, "K5 PR166 (model 2)");
364 break;
365 case 0x530:
366 strcat(cpu_model, "K5 PR200 (model 3)");
367 break;
368 case 0x560:
369 strcat(cpu_model, "K6");
370 break;
371 case 0x570:
372 strcat(cpu_model, "K6 266 (model 1)");
373 break;
374 case 0x580:
375 strcat(cpu_model, "K6-2");
376 break;
377 case 0x590:
378 strcat(cpu_model, "K6-III");
379 break;
380 default:
381 strcat(cpu_model, "Unknown");
382 break;
384 #if defined(I586_CPU) && defined(CPU_WT_ALLOC)
385 if ((cpu_id & 0xf00) == 0x500) {
386 if (((cpu_id & 0x0f0) > 0)
387 && ((cpu_id & 0x0f0) < 0x60)
388 && ((cpu_id & 0x00f) > 3))
389 enable_K5_wt_alloc();
390 else if (((cpu_id & 0x0f0) > 0x80)
391 || (((cpu_id & 0x0f0) == 0x80)
392 && (cpu_id & 0x00f) > 0x07))
393 enable_K6_2_wt_alloc();
394 else if ((cpu_id & 0x0f0) > 0x50)
395 enable_K6_wt_alloc();
397 #endif
398 } else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
399 strcpy(cpu_model, "Cyrix ");
400 switch (cpu_id & 0xff0) {
401 case 0x440:
402 strcat(cpu_model, "MediaGX");
403 break;
404 case 0x520:
405 strcat(cpu_model, "6x86");
406 break;
407 case 0x540:
408 cpu_class = CPUCLASS_586;
409 strcat(cpu_model, "GXm");
410 break;
411 case 0x600:
412 strcat(cpu_model, "6x86MX");
413 break;
414 default:
416 * Even though CPU supports the cpuid
417 * instruction, it can be disabled.
418 * Therefore, this routine supports all Cyrix
419 * CPUs.
421 switch (cyrix_did & 0xf0) {
422 case 0x00:
423 switch (cyrix_did & 0x0f) {
424 case 0x00:
425 strcat(cpu_model, "486SLC");
426 break;
427 case 0x01:
428 strcat(cpu_model, "486DLC");
429 break;
430 case 0x02:
431 strcat(cpu_model, "486SLC2");
432 break;
433 case 0x03:
434 strcat(cpu_model, "486DLC2");
435 break;
436 case 0x04:
437 strcat(cpu_model, "486SRx");
438 break;
439 case 0x05:
440 strcat(cpu_model, "486DRx");
441 break;
442 case 0x06:
443 strcat(cpu_model, "486SRx2");
444 break;
445 case 0x07:
446 strcat(cpu_model, "486DRx2");
447 break;
448 case 0x08:
449 strcat(cpu_model, "486SRu");
450 break;
451 case 0x09:
452 strcat(cpu_model, "486DRu");
453 break;
454 case 0x0a:
455 strcat(cpu_model, "486SRu2");
456 break;
457 case 0x0b:
458 strcat(cpu_model, "486DRu2");
459 break;
460 default:
461 strcat(cpu_model, "Unknown");
462 break;
464 break;
465 case 0x10:
466 switch (cyrix_did & 0x0f) {
467 case 0x00:
468 strcat(cpu_model, "486S");
469 break;
470 case 0x01:
471 strcat(cpu_model, "486S2");
472 break;
473 case 0x02:
474 strcat(cpu_model, "486Se");
475 break;
476 case 0x03:
477 strcat(cpu_model, "486S2e");
478 break;
479 case 0x0a:
480 strcat(cpu_model, "486DX");
481 break;
482 case 0x0b:
483 strcat(cpu_model, "486DX2");
484 break;
485 case 0x0f:
486 strcat(cpu_model, "486DX4");
487 break;
488 default:
489 strcat(cpu_model, "Unknown");
490 break;
492 break;
493 case 0x20:
494 if ((cyrix_did & 0x0f) < 8)
495 strcat(cpu_model, "6x86"); /* Where did you get it? */
496 else
497 strcat(cpu_model, "5x86");
498 break;
499 case 0x30:
500 strcat(cpu_model, "6x86");
501 break;
502 case 0x40:
503 if ((cyrix_did & 0xf000) == 0x3000) {
504 cpu_class = CPUCLASS_586;
505 strcat(cpu_model, "GXm");
506 } else
507 strcat(cpu_model, "MediaGX");
508 break;
509 case 0x50:
510 strcat(cpu_model, "6x86MX");
511 break;
512 case 0xf0:
513 switch (cyrix_did & 0x0f) {
514 case 0x0d:
515 strcat(cpu_model, "Overdrive CPU");
516 case 0x0e:
517 strcpy(cpu_model, "Texas Instruments 486SXL");
518 break;
519 case 0x0f:
520 strcat(cpu_model, "486SLC/DLC");
521 break;
522 default:
523 strcat(cpu_model, "Unknown");
524 break;
526 break;
527 default:
528 strcat(cpu_model, "Unknown");
529 break;
531 break;
533 } else if (strcmp(cpu_vendor, "RiseRiseRise") == 0) {
534 strcpy(cpu_model, "Rise ");
535 switch (cpu_id & 0xff0) {
536 case 0x500:
537 strcat(cpu_model, "mP6");
538 break;
539 default:
540 strcat(cpu_model, "Unknown");
542 } else if (strcmp(cpu_vendor, "CentaurHauls") == 0) {
543 switch (cpu_id & 0xff0) {
544 case 0x540:
545 strcpy(cpu_model, "IDT WinChip C6");
546 tsc_is_broken = 1;
547 break;
548 case 0x580:
549 strcpy(cpu_model, "IDT WinChip 2");
550 break;
551 case 0x660:
552 strcpy(cpu_model, "VIA C3 Samuel");
553 break;
554 case 0x670:
555 if (cpu_id & 0x8)
556 strcpy(cpu_model, "VIA C3 Ezra");
557 else
558 strcpy(cpu_model, "VIA C3 Samuel 2");
559 break;
560 case 0x680:
561 strcpy(cpu_model, "VIA C3 Ezra-T");
562 break;
563 case 0x690:
564 strcpy(cpu_model, "VIA C3 Nehemiah");
565 do_cpuid(0xc0000000, regs);
566 if (regs[0] == 0xc0000001) {
567 do_cpuid(0xc0000001, regs);
568 if ((cpu_id & 0xf) >= 3)
569 if ((regs[3] & 0x0c) == 0x0c)
570 strcat(cpu_model, "+RNG");
571 if ((cpu_id & 0xf) >= 8)
572 if ((regs[3] & 0xc0) == 0xc0)
573 strcat(cpu_model, "+ACE");
575 break;
576 default:
577 strcpy(cpu_model, "VIA/IDT Unknown");
579 } else if (strcmp(cpu_vendor, "IBM") == 0) {
580 strcpy(cpu_model, "Blue Lightning CPU");
584 * Replace cpu_model with cpu_brand minus leading spaces if
585 * we have one.
587 brand = cpu_brand;
588 while (*brand == ' ')
589 ++brand;
590 if (*brand != '\0')
591 strcpy(cpu_model, brand);
593 #endif
595 kprintf("%s (", cpu_model);
596 switch(cpu_class) {
597 case CPUCLASS_286:
598 kprintf("286");
599 break;
600 case CPUCLASS_386:
601 kprintf("386");
602 break;
603 #if defined(I486_CPU)
604 case CPUCLASS_486:
605 kprintf("486");
606 /* bzero = i486_bzero; */
607 break;
608 #endif
609 #if defined(I586_CPU)
610 case CPUCLASS_586:
611 kprintf("%d.%02d-MHz ",
612 (int)((tsc_frequency + 4999) / 1000000),
613 (int)((tsc_frequency + 4999) / 10000) % 100);
614 kprintf("586");
615 break;
616 #endif
617 #if defined(I686_CPU)
618 case CPUCLASS_686:
619 kprintf("%d.%02d-MHz ",
620 ((int)(tsc_frequency + 4999) / 1000000),
621 (int)((tsc_frequency + 4999) / 10000) % 100);
622 kprintf("686");
623 break;
624 #endif
625 default:
626 kprintf("Unknown"); /* will panic below... */
628 kprintf("-class CPU)\n");
629 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
630 if(*cpu_vendor)
631 kprintf(" Origin = \"%s\"",cpu_vendor);
632 if(cpu_id)
633 kprintf(" Id = 0x%x", cpu_id);
635 if (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
636 strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
637 strcmp(cpu_vendor, "RiseRiseRise") == 0 ||
638 strcmp(cpu_vendor, "CentaurHauls") == 0 ||
639 ((strcmp(cpu_vendor, "CyrixInstead") == 0) &&
640 ((cpu_id & 0xf00) > 0x500))) {
641 kprintf(" Stepping = %u", cpu_id & 0xf);
642 if (strcmp(cpu_vendor, "CyrixInstead") == 0)
643 kprintf(" DIR=0x%04x", cyrix_did);
644 if (cpu_high > 0) {
646 * Here we should probably set up flags indicating
647 * whether or not various features are available.
648 * The interesting ones are probably VME, PSE, PAE,
649 * and PGE. The code already assumes without bothering
650 * to check that all CPUs >= Pentium have a TSC and
651 * MSRs.
653 kprintf("\n Features=0x%b", cpu_feature,
654 "\020"
655 "\001FPU" /* Integral FPU */
656 "\002VME" /* Extended VM86 mode support */
657 "\003DE" /* Debugging Extensions (CR4.DE) */
658 "\004PSE" /* 4MByte page tables */
659 "\005TSC" /* Timestamp counter */
660 "\006MSR" /* Machine specific registers */
661 "\007PAE" /* Physical address extension */
662 "\010MCE" /* Machine Check support */
663 "\011CX8" /* CMPEXCH8 instruction */
664 "\012APIC" /* SMP local APIC */
665 "\013oldMTRR" /* Previous implementation of MTRR */
666 "\014SEP" /* Fast System Call */
667 "\015MTRR" /* Memory Type Range Registers */
668 "\016PGE" /* PG_G (global bit) support */
669 "\017MCA" /* Machine Check Architecture */
670 "\020CMOV" /* CMOV instruction */
671 "\021PAT" /* Page attributes table */
672 "\022PSE36" /* 36 bit address space support */
673 "\023PN" /* Processor Serial number */
674 "\024CLFLUSH" /* Has the CLFLUSH instruction */
675 "\025<b20>"
676 "\026DTS" /* Debug Trace Store */
677 "\027ACPI" /* ACPI support */
678 "\030MMX" /* MMX instructions */
679 "\031FXSR" /* FXSAVE/FXRSTOR */
680 "\032SSE" /* Streaming SIMD Extensions */
681 "\033SSE2" /* Streaming SIMD Extensions #2 */
682 "\034SS" /* Self snoop */
683 "\035HTT" /* Hyperthreading (see EBX bit 16-23) */
684 "\036TM" /* Thermal Monitor clock slowdown */
685 "\037IA64" /* CPU can execute IA64 instructions */
686 "\040PBE" /* Pending Break Enable */
689 if (cpu_feature2 != 0) {
690 kprintf("\n Features2=0x%b", cpu_feature2,
691 "\020"
692 "\001SSE3" /* SSE3 */
693 "\002<b1>"
694 "\003RSVD2" /* "Reserved" bit 2 */
695 "\004MON" /* MONITOR/MWAIT Instructions */
696 "\005DS_CPL" /* CPL Qualified Debug Store */
697 "\006VMX" /* Virtual Machine Extensions */
698 "\007<b6>"
699 "\010EST" /* Enhanced SpeedStep */
700 "\011TM2" /* Thermal Monitor 2 */
701 "\012SSSE3" /* Supplemental SSE3 */
702 "\013CNTX-ID" /* L1 context ID available */
703 "\014<b11>"
704 "\015<b12>"
705 "\016CX16" /* CMPXCHG16B Instruction */
706 "\017XTPR" /* Send Task Priority Messages*/
707 "\020RSVD15" /* "Reserved" bit 15 */
708 "\021<b16>"
709 "\022<b17>"
710 "\023<b18>"
711 "\024<b19>"
712 "\025<b20>"
713 "\026<b21>"
714 "\027<b22>"
715 "\030<b23>"
716 "\031<b24>"
717 "\032<b25>"
718 "\033<b26>"
719 "\034<b27>"
720 "\035<b28>"
721 "\036<b29>"
722 "\037<b30>"
723 "\040<b31>"
728 * If this CPU supports hyperthreading then mention
729 * the number of logical CPU's it contains.
731 if (cpu_feature & CPUID_HTT &&
732 (cpu_procinfo & CPUID_HTT_CORES) >> 16 > 1)
733 kprintf("\n Hyperthreading: %d logical CPUs",
734 (cpu_procinfo & CPUID_HTT_CORES) >> 16);
736 if (strcmp(cpu_vendor, "AuthenticAMD") == 0 &&
737 cpu_exthigh >= 0x80000001)
738 print_AMD_features();
739 } else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
740 kprintf(" DIR=0x%04x", cyrix_did);
741 kprintf(" Stepping=%u", (cyrix_did & 0xf000) >> 12);
742 kprintf(" Revision=%u", (cyrix_did & 0x0f00) >> 8);
743 #ifndef CYRIX_CACHE_REALLY_WORKS
744 if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700)
745 kprintf("\n CPU cache: write-through mode");
746 #endif
748 /* Avoid ugly blank lines: only print newline when we have to. */
749 if (*cpu_vendor || cpu_id)
750 kprintf("\n");
752 #endif
753 if (strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
754 strcmp(cpu_vendor, "TransmetaCPU") == 0) {
755 setup_tmx86_longrun();
758 for (i = 0; i < additional_cpu_info_count; ++i) {
759 kprintf(" %s\n", additional_cpu_info_ary[i]);
762 if (!bootverbose)
763 return;
765 if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
766 print_AMD_info();
767 else if (strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
768 strcmp(cpu_vendor, "TransmetaCPU") == 0)
769 print_transmeta_info();
771 #ifdef I686_CPU
773 * XXX - Do PPro CPUID level=2 stuff here?
775 * No, but maybe in a print_Intel_info() function called from here.
777 #endif
780 void
781 panicifcpuunsupported(void)
784 #if !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU)
785 #error This kernel is not configured for one of the supported CPUs
786 #endif
788 * Now that we have told the user what they have,
789 * let them know if that machine type isn't configured.
791 switch (cpu_class) {
793 * A 286 and 386 should not make it this far, anyway.
795 case CPUCLASS_286:
796 case CPUCLASS_386:
797 #if !defined(I486_CPU)
798 case CPUCLASS_486:
799 #endif
800 #if !defined(I586_CPU)
801 case CPUCLASS_586:
802 #endif
803 #if !defined(I686_CPU)
804 case CPUCLASS_686:
805 #endif
806 panic("CPU class not configured");
807 default:
808 break;
813 static volatile u_int trap_by_rdmsr;
816 * Special exception 6 handler.
817 * The rdmsr instruction generates invalid opcodes fault on 486-class
818 * Cyrix CPU. Stacked eip register points the rdmsr instruction in the
819 * function identblue() when this handler is called. Stacked eip should
820 * be advanced.
822 inthand_t bluetrap6;
824 __asm(
825 " .text \n"
826 " .p2align 2,0x90 \n"
827 " .type " __XSTRING(CNAME(bluetrap6)) ",@function \n"
828 __XSTRING(CNAME(bluetrap6)) ": \n"
829 " ss \n"
830 " movl $0xa8c1d," __XSTRING(CNAME(trap_by_rdmsr)) " \n"
831 " addl $2, (%esp) # I know rdmsr is a 2-bytes instruction. \n"
832 " iret \n"
836 * Special exception 13 handler.
837 * Accessing non-existent MSR generates general protection fault.
839 inthand_t bluetrap13;
841 __asm(
842 " .text \n"
843 " .p2align 2,0x90 \n"
844 " .type " __XSTRING(CNAME(bluetrap13)) ",@function \n"
845 __XSTRING(CNAME(bluetrap13)) ": \n"
846 " ss \n"
847 " movl $0xa89c4," __XSTRING(CNAME(trap_by_rdmsr)) " \n"
848 " popl %eax # discard errorcode. \n"
849 " addl $2, (%esp) # I know rdmsr is a 2-bytes instruction. \n"
850 " iret \n"
854 * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not
855 * support cpuid instruction. This function should be called after
856 * loading interrupt descriptor table register.
858 * I don't like this method that handles fault, but I couldn't get
859 * information for any other methods. Does blue giant know?
861 static int
862 identblue(void)
865 trap_by_rdmsr = 0;
868 * Cyrix 486-class CPU does not support rdmsr instruction.
869 * The rdmsr instruction generates invalid opcode fault, and exception
870 * will be trapped by bluetrap6() on Cyrix 486-class CPU. The
871 * bluetrap6() set the magic number to trap_by_rdmsr.
873 setidt(6, bluetrap6, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
876 * Certain BIOS disables cpuid instruction of Cyrix 6x86MX CPU.
877 * In this case, rdmsr generates general protection fault, and
878 * exception will be trapped by bluetrap13().
880 setidt(13, bluetrap13, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
882 rdmsr(0x1002); /* Cyrix CPU generates fault. */
884 if (trap_by_rdmsr == 0xa8c1d)
885 return IDENTBLUE_CYRIX486;
886 else if (trap_by_rdmsr == 0xa89c4)
887 return IDENTBLUE_CYRIXM2;
888 return IDENTBLUE_IBMCPU;
893 * identifycyrix() set lower 16 bits of cyrix_did as follows:
895 * F E D C B A 9 8 7 6 5 4 3 2 1 0
896 * +-------+-------+---------------+
897 * | SID | RID | Device ID |
898 * | (DIR 1) | (DIR 0) |
899 * +-------+-------+---------------+
901 static void
902 identifycyrix(void)
904 int ccr2_test = 0, dir_test = 0;
905 u_char ccr2, ccr3;
907 mpintr_lock();
909 ccr2 = read_cyrix_reg(CCR2);
910 write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW);
911 read_cyrix_reg(CCR2);
912 if (read_cyrix_reg(CCR2) != ccr2)
913 ccr2_test = 1;
914 write_cyrix_reg(CCR2, ccr2);
916 ccr3 = read_cyrix_reg(CCR3);
917 write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3);
918 read_cyrix_reg(CCR3);
919 if (read_cyrix_reg(CCR3) != ccr3)
920 dir_test = 1; /* CPU supports DIRs. */
921 write_cyrix_reg(CCR3, ccr3);
923 if (dir_test) {
924 /* Device ID registers are available. */
925 cyrix_did = read_cyrix_reg(DIR1) << 8;
926 cyrix_did += read_cyrix_reg(DIR0);
927 } else if (ccr2_test)
928 cyrix_did = 0x0010; /* 486S A-step */
929 else
930 cyrix_did = 0x00ff; /* Old 486SLC/DLC and TI486SXLC/SXL */
932 mpintr_unlock();
936 * Final stage of CPU identification. -- Should I check TI?
938 void
939 finishidentcpu(void)
941 int isblue = 0;
942 u_char ccr3;
943 u_int regs[4];
945 if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
946 if (cpu == CPU_486) {
948 * These conditions are equivalent to:
949 * - CPU does not support cpuid instruction.
950 * - Cyrix/IBM CPU is detected.
952 isblue = identblue();
953 if (isblue == IDENTBLUE_IBMCPU) {
954 strcpy(cpu_vendor, "IBM");
955 cpu = CPU_BLUE;
956 return;
959 switch (cpu_id & 0xf00) {
960 case 0x600:
962 * Cyrix's datasheet does not describe DIRs.
963 * Therefor, I assume it does not have them
964 * and use the result of the cpuid instruction.
965 * XXX they seem to have it for now at least. -Peter
967 identifycyrix();
968 cpu = CPU_M2;
969 break;
970 default:
971 identifycyrix();
973 * This routine contains a trick.
974 * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now.
976 switch (cyrix_did & 0x00f0) {
977 case 0x00:
978 case 0xf0:
979 cpu = CPU_486DLC;
980 break;
981 case 0x10:
982 cpu = CPU_CY486DX;
983 break;
984 case 0x20:
985 if ((cyrix_did & 0x000f) < 8)
986 cpu = CPU_M1;
987 else
988 cpu = CPU_M1SC;
989 break;
990 case 0x30:
991 cpu = CPU_M1;
992 break;
993 case 0x40:
994 /* MediaGX CPU */
995 cpu = CPU_M1SC;
996 break;
997 default:
998 /* M2 and later CPUs are treated as M2. */
999 cpu = CPU_M2;
1002 * enable cpuid instruction.
1004 ccr3 = read_cyrix_reg(CCR3);
1005 write_cyrix_reg(CCR3, CCR3_MAPEN0);
1006 write_cyrix_reg(CCR4, read_cyrix_reg(CCR4) | CCR4_CPUID);
1007 write_cyrix_reg(CCR3, ccr3);
1009 do_cpuid(0, regs);
1010 cpu_high = regs[0]; /* eax */
1011 do_cpuid(1, regs);
1012 cpu_id = regs[0]; /* eax */
1013 cpu_feature = regs[3]; /* edx */
1014 break;
1017 } else if (cpu == CPU_486 && *cpu_vendor == '\0') {
1019 * There are BlueLightning CPUs that do not change
1020 * undefined flags by dividing 5 by 2. In this case,
1021 * the CPU identification routine in locore.s leaves
1022 * cpu_vendor null string and puts CPU_486 into the
1023 * cpu.
1025 isblue = identblue();
1026 if (isblue == IDENTBLUE_IBMCPU) {
1027 strcpy(cpu_vendor, "IBM");
1028 cpu = CPU_BLUE;
1029 return;
1034 static void
1035 print_AMD_assoc(int i)
1037 if (i == 255)
1038 kprintf(", fully associative\n");
1039 else
1040 kprintf(", %d-way associative\n", i);
1043 static void
1044 print_AMD_info(void)
1046 quad_t amd_whcr;
1048 if (cpu_exthigh >= 0x80000005) {
1049 u_int regs[4];
1051 do_cpuid(0x80000005, regs);
1052 kprintf("Data TLB: %d entries", (regs[1] >> 16) & 0xff);
1053 print_AMD_assoc(regs[1] >> 24);
1054 kprintf("Instruction TLB: %d entries", regs[1] & 0xff);
1055 print_AMD_assoc((regs[1] >> 8) & 0xff);
1056 kprintf("L1 data cache: %d kbytes", regs[2] >> 24);
1057 kprintf(", %d bytes/line", regs[2] & 0xff);
1058 kprintf(", %d lines/tag", (regs[2] >> 8) & 0xff);
1059 print_AMD_assoc((regs[2] >> 16) & 0xff);
1060 kprintf("L1 instruction cache: %d kbytes", regs[3] >> 24);
1061 kprintf(", %d bytes/line", regs[3] & 0xff);
1062 kprintf(", %d lines/tag", (regs[3] >> 8) & 0xff);
1063 print_AMD_assoc((regs[3] >> 16) & 0xff);
1064 if (cpu_exthigh >= 0x80000006) { /* K6-III, or later */
1065 do_cpuid(0x80000006, regs);
1067 * Report right L2 cache size on Duron rev. A0.
1069 if ((cpu_id & 0xFF0) == 0x630)
1070 kprintf("L2 internal cache: 64 kbytes");
1071 else
1072 kprintf("L2 internal cache: %d kbytes",
1073 regs[2] >> 16);
1075 kprintf(", %d bytes/line", regs[2] & 0xff);
1076 kprintf(", %d lines/tag", (regs[2] >> 8) & 0x0f);
1077 print_AMD_assoc((regs[2] >> 12) & 0x0f);
1080 if (((cpu_id & 0xf00) == 0x500)
1081 && (((cpu_id & 0x0f0) > 0x80)
1082 || (((cpu_id & 0x0f0) == 0x80)
1083 && (cpu_id & 0x00f) > 0x07))) {
1084 /* K6-2(new core [Stepping 8-F]), K6-III or later */
1085 amd_whcr = rdmsr(0xc0000082);
1086 if (!(amd_whcr & (0x3ff << 22))) {
1087 kprintf("Write Allocate Disable\n");
1088 } else {
1089 kprintf("Write Allocate Enable Limit: %dM bytes\n",
1090 (u_int32_t)((amd_whcr & (0x3ff << 22)) >> 22) * 4);
1091 kprintf("Write Allocate 15-16M bytes: %s\n",
1092 (amd_whcr & (1 << 16)) ? "Enable" : "Disable");
1094 } else if (((cpu_id & 0xf00) == 0x500)
1095 && ((cpu_id & 0x0f0) > 0x50)) {
1096 /* K6, K6-2(old core) */
1097 amd_whcr = rdmsr(0xc0000082);
1098 if (!(amd_whcr & (0x7f << 1))) {
1099 kprintf("Write Allocate Disable\n");
1100 } else {
1101 kprintf("Write Allocate Enable Limit: %dM bytes\n",
1102 (u_int32_t)((amd_whcr & (0x7f << 1)) >> 1) * 4);
1103 kprintf("Write Allocate 15-16M bytes: %s\n",
1104 (amd_whcr & 0x0001) ? "Enable" : "Disable");
1105 kprintf("Hardware Write Allocate Control: %s\n",
1106 (amd_whcr & 0x0100) ? "Enable" : "Disable");
1111 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1112 static void
1113 print_AMD_features(void)
1115 u_int regs[4];
1118 * Values taken from AMD Processor Recognition
1119 * http://www.amd.com/products/cpg/athlon/techdocs/pdf/20734.pdf
1121 do_cpuid(0x80000001, regs);
1122 kprintf("\n AMD Features=0x%b", regs[3] &~ cpu_feature,
1123 "\020" /* in hex */
1124 "\001FPU" /* Integral FPU */
1125 "\002VME" /* Extended VM86 mode support */
1126 "\003DE" /* Debug extensions */
1127 "\004PSE" /* 4MByte page tables */
1128 "\005TSC" /* Timestamp counter */
1129 "\006MSR" /* Machine specific registers */
1130 "\007PAE" /* Physical address extension */
1131 "\010MCE" /* Machine Check support */
1132 "\011CX8" /* CMPEXCH8 instruction */
1133 "\012APIC" /* SMP local APIC */
1134 "\013<b10>"
1135 "\014SYSCALL" /* SYSENTER/SYSEXIT instructions */
1136 "\015MTRR" /* Memory Type Range Registers */
1137 "\016PGE" /* PG_G (global bit) support */
1138 "\017MCA" /* Machine Check Architecture */
1139 "\020ICMOV" /* CMOV instruction */
1140 "\021PAT" /* Page attributes table */
1141 "\022PGE36" /* 36 bit address space support */
1142 "\023RSVD" /* Reserved, unknown */
1143 "\024MP" /* Multiprocessor Capable */
1144 "\025NX" /* No-execute page protection */
1145 "\026<b21>"
1146 "\027AMIE" /* AMD MMX Instruction Extensions */
1147 "\030MMX"
1148 "\031FXSAVE" /* FXSAVE/FXRSTOR */
1149 "\032<b25>"
1150 "\033<b26>"
1151 "\034RDTSCP" /* RDTSCP instruction */
1152 "\035<b28>"
1153 "\036LM" /* Long mode */
1154 "\037DSP" /* AMD 3DNow! Instruction Extensions */
1155 "\0403DNow!"
1158 #endif
1161 * Transmeta Crusoe LongRun Support by Tamotsu Hattori.
1164 #define MSR_TMx86_LONGRUN 0x80868010
1165 #define MSR_TMx86_LONGRUN_FLAGS 0x80868011
1167 #define LONGRUN_MODE_MASK(x) ((x) & 0x000000007f)
1168 #define LONGRUN_MODE_RESERVED(x) ((x) & 0xffffff80)
1169 #define LONGRUN_MODE_WRITE(x, y) (LONGRUN_MODE_RESERVED(x) | LONGRUN_MODE_MASK(y))
1171 #define LONGRUN_MODE_MINFREQUENCY 0x00
1172 #define LONGRUN_MODE_ECONOMY 0x01
1173 #define LONGRUN_MODE_PERFORMANCE 0x02
1174 #define LONGRUN_MODE_MAXFREQUENCY 0x03
1175 #define LONGRUN_MODE_UNKNOWN 0x04
1176 #define LONGRUN_MODE_MAX 0x04
1178 union msrinfo {
1179 u_int64_t msr;
1180 u_int32_t regs[2];
1183 u_int32_t longrun_modes[LONGRUN_MODE_MAX][3] = {
1184 /* MSR low, MSR high, flags bit0 */
1185 { 0, 0, 0}, /* LONGRUN_MODE_MINFREQUENCY */
1186 { 0, 100, 0}, /* LONGRUN_MODE_ECONOMY */
1187 { 0, 100, 1}, /* LONGRUN_MODE_PERFORMANCE */
1188 { 100, 100, 1}, /* LONGRUN_MODE_MAXFREQUENCY */
1191 static u_int
1192 tmx86_get_longrun_mode(void)
1194 union msrinfo msrinfo;
1195 u_int low, high, flags, mode;
1197 mpintr_lock();
1199 msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
1200 low = LONGRUN_MODE_MASK(msrinfo.regs[0]);
1201 high = LONGRUN_MODE_MASK(msrinfo.regs[1]);
1202 flags = rdmsr(MSR_TMx86_LONGRUN_FLAGS) & 0x01;
1204 for (mode = 0; mode < LONGRUN_MODE_MAX; mode++) {
1205 if (low == longrun_modes[mode][0] &&
1206 high == longrun_modes[mode][1] &&
1207 flags == longrun_modes[mode][2]) {
1208 goto out;
1211 mode = LONGRUN_MODE_UNKNOWN;
1212 out:
1213 mpintr_unlock();
1214 return (mode);
1217 static u_int
1218 tmx86_get_longrun_status(u_int * frequency, u_int * voltage, u_int * percentage)
1220 u_int regs[4];
1222 mpintr_lock();
1224 do_cpuid(0x80860007, regs);
1225 *frequency = regs[0];
1226 *voltage = regs[1];
1227 *percentage = regs[2];
1229 mpintr_unlock();
1230 return (1);
1233 static u_int
1234 tmx86_set_longrun_mode(u_int mode)
1236 union msrinfo msrinfo;
1238 if (mode >= LONGRUN_MODE_UNKNOWN) {
1239 return (0);
1242 mpintr_lock();
1244 /* Write LongRun mode values to Model Specific Register. */
1245 msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
1246 msrinfo.regs[0] = LONGRUN_MODE_WRITE(msrinfo.regs[0],
1247 longrun_modes[mode][0]);
1248 msrinfo.regs[1] = LONGRUN_MODE_WRITE(msrinfo.regs[1],
1249 longrun_modes[mode][1]);
1250 wrmsr(MSR_TMx86_LONGRUN, msrinfo.msr);
1252 /* Write LongRun mode flags to Model Specific Register. */
1253 msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN_FLAGS);
1254 msrinfo.regs[0] = (msrinfo.regs[0] & ~0x01) | longrun_modes[mode][2];
1255 wrmsr(MSR_TMx86_LONGRUN_FLAGS, msrinfo.msr);
1257 mpintr_unlock();
1258 return (1);
1261 static u_int crusoe_longrun;
1262 static u_int crusoe_frequency;
1263 static u_int crusoe_voltage;
1264 static u_int crusoe_percentage;
1265 static struct sysctl_ctx_list crusoe_sysctl_ctx;
1266 static struct sysctl_oid *crusoe_sysctl_tree;
1268 static int
1269 tmx86_longrun_sysctl(SYSCTL_HANDLER_ARGS)
1271 u_int mode;
1272 int error;
1274 crusoe_longrun = tmx86_get_longrun_mode();
1275 mode = crusoe_longrun;
1276 error = sysctl_handle_int(oidp, &mode, 0, req);
1277 if (error || !req->newptr) {
1278 return (error);
1280 if (mode >= LONGRUN_MODE_UNKNOWN) {
1281 error = EINVAL;
1282 return (error);
1284 if (crusoe_longrun != mode) {
1285 crusoe_longrun = mode;
1286 tmx86_set_longrun_mode(crusoe_longrun);
1289 return (error);
1292 static int
1293 tmx86_status_sysctl(SYSCTL_HANDLER_ARGS)
1295 u_int val;
1296 int error;
1298 tmx86_get_longrun_status(&crusoe_frequency,
1299 &crusoe_voltage, &crusoe_percentage);
1300 val = *(u_int *)oidp->oid_arg1;
1301 error = sysctl_handle_int(oidp, &val, 0, req);
1302 return (error);
1305 static void
1306 setup_tmx86_longrun(void)
1308 static int done = 0;
1310 if (done)
1311 return;
1312 done++;
1314 sysctl_ctx_init(&crusoe_sysctl_ctx);
1315 crusoe_sysctl_tree = SYSCTL_ADD_NODE(&crusoe_sysctl_ctx,
1316 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
1317 "crusoe", CTLFLAG_RD, 0,
1318 "Transmeta Crusoe LongRun support");
1319 SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
1320 OID_AUTO, "longrun", CTLTYPE_INT | CTLFLAG_RW,
1321 &crusoe_longrun, 0, tmx86_longrun_sysctl, "I",
1322 "LongRun mode [0-3]");
1323 SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
1324 OID_AUTO, "frequency", CTLTYPE_INT | CTLFLAG_RD,
1325 &crusoe_frequency, 0, tmx86_status_sysctl, "I",
1326 "Current frequency (MHz)");
1327 SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
1328 OID_AUTO, "voltage", CTLTYPE_INT | CTLFLAG_RD,
1329 &crusoe_voltage, 0, tmx86_status_sysctl, "I",
1330 "Current voltage (mV)");
1331 SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
1332 OID_AUTO, "percentage", CTLTYPE_INT | CTLFLAG_RD,
1333 &crusoe_percentage, 0, tmx86_status_sysctl, "I",
1334 "Processing performance (%)");
1337 static void
1338 print_transmeta_info(void)
1340 u_int regs[4], nreg = 0;
1342 do_cpuid(0x80860000, regs);
1343 nreg = regs[0];
1344 if (nreg >= 0x80860001) {
1345 do_cpuid(0x80860001, regs);
1346 kprintf(" Processor revision %u.%u.%u.%u\n",
1347 (regs[1] >> 24) & 0xff,
1348 (regs[1] >> 16) & 0xff,
1349 (regs[1] >> 8) & 0xff,
1350 regs[1] & 0xff);
1352 if (nreg >= 0x80860002) {
1353 do_cpuid(0x80860002, regs);
1354 kprintf(" Code Morphing Software revision %u.%u.%u-%u-%u\n",
1355 (regs[1] >> 24) & 0xff,
1356 (regs[1] >> 16) & 0xff,
1357 (regs[1] >> 8) & 0xff,
1358 regs[1] & 0xff,
1359 regs[2]);
1361 if (nreg >= 0x80860006) {
1362 char info[65];
1363 do_cpuid(0x80860003, (u_int*) &info[0]);
1364 do_cpuid(0x80860004, (u_int*) &info[16]);
1365 do_cpuid(0x80860005, (u_int*) &info[32]);
1366 do_cpuid(0x80860006, (u_int*) &info[48]);
1367 info[64] = 0;
1368 kprintf(" %s\n", info);
1371 crusoe_longrun = tmx86_get_longrun_mode();
1372 tmx86_get_longrun_status(&crusoe_frequency,
1373 &crusoe_voltage, &crusoe_percentage);
1374 kprintf(" LongRun mode: %d <%dMHz %dmV %d%%>\n", crusoe_longrun,
1375 crusoe_frequency, crusoe_voltage, crusoe_percentage);
1378 void
1379 additional_cpu_info(const char *line)
1381 int i;
1383 if ((i = additional_cpu_info_count) < MAX_ADDITIONAL_INFO) {
1384 additional_cpu_info_ary[i] = line;
1385 ++additional_cpu_info_count;