1/*	$NetBSD: i386.c,v 1.27.2.3 2012/04/06 17:46:41 riz Exp $	*/
2
3/*-
4 * Copyright (c) 1999, 2000, 2001, 2006, 2007, 2008 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/*-
33 * Copyright (c)2008 YAMAMOTO Takashi,
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58#include <sys/cdefs.h>
59#ifndef lint
60__RCSID("$NetBSD: i386.c,v 1.27.2.3 2012/04/06 17:46:41 riz Exp $");
61#endif /* not lint */
62
63#include <sys/types.h>
64#include <sys/param.h>
65#include <sys/bitops.h>
66#include <sys/sysctl.h>
67
68#include <string.h>
69#include <stdio.h>
70#include <stdlib.h>
71#include <err.h>
72#include <assert.h>
73#include <math.h>
74#include <util.h>
75
76#include <machine/specialreg.h>
77#include <machine/cpu.h>
78
79#include <x86/cpuvar.h>
80#include <x86/cputypes.h>
81#include <x86/cacheinfo.h>
82
83#include "../cpuctl.h"
84
85/* Size of buffer for printing humanized numbers */
86#define HUMAN_BUFSIZE sizeof("999KB")
87
88#define       x86_cpuid(a,b)  x86_cpuid2((a),0,(b))
89
90void	x86_cpuid2(uint32_t, uint32_t, uint32_t *);
91void	x86_identify(void);
92
93struct cpu_info {
94	const char	*ci_dev;
95	int32_t		ci_cpuid_level;
96	uint32_t	ci_signature;	 /* X86 cpuid type */
97	uint32_t	ci_feat_val[5];	 /* X86 CPUID feature bits
98					  *	[0] basic features %edx
99					  *	[1] basic features %ecx
100					  *	[2] extended features %edx
101					  *	[3] extended features %ecx
102					  *	[4] VIA padlock features
103					  */
104	uint32_t	ci_cpu_class;	 /* CPU class */
105	uint32_t	ci_brand_id;	 /* Intel brand id */
106	uint32_t	ci_vendor[4];	 /* vendor string */
107	uint32_t	ci_cpu_serial[3]; /* PIII serial number */
108	uint64_t	ci_tsc_freq;	 /* cpu cycles/second */
109	uint8_t		ci_packageid;
110	uint8_t		ci_coreid;
111	uint8_t		ci_smtid;
112	uint32_t	ci_initapicid;
113	struct x86_cache_info ci_cinfo[CAI_COUNT];
114	void		(*ci_info)(struct cpu_info *);
115};
116
117struct cpu_nocpuid_nameclass {
118	int cpu_vendor;
119	const char *cpu_vendorname;
120	const char *cpu_name;
121	int cpu_class;
122	void (*cpu_setup)(struct cpu_info *);
123	void (*cpu_cacheinfo)(struct cpu_info *);
124	void (*cpu_info)(struct cpu_info *);
125};
126
127struct cpu_extend_nameclass {
128	int ext_model;
129	const char *cpu_models[CPU_MAXMODEL+1];
130};
131
132struct cpu_cpuid_nameclass {
133	const char *cpu_id;
134	int cpu_vendor;
135	const char *cpu_vendorname;
136	struct cpu_cpuid_family {
137		int cpu_class;
138		const char *cpu_models[CPU_MAXMODEL+2];
139		void (*cpu_setup)(struct cpu_info *);
140		void (*cpu_probe)(struct cpu_info *);
141		void (*cpu_info)(struct cpu_info *);
142		struct cpu_extend_nameclass *cpu_extended_names;
143	} cpu_family[CPU_MAXFAMILY - CPU_MINFAMILY + 1];
144};
145
146static const struct x86_cache_info intel_cpuid_cache_info[] = INTEL_CACHE_INFO;
147
148/*
149 * Map Brand ID from cpuid instruction to brand name.
150 * Source: Intel Processor Identification and the CPUID Instruction, AP-485
151 */
152static const char * const i386_intel_brand[] = {
153	"",		    /* Unsupported */
154	"Celeron",	    /* Intel (R) Celeron (TM) processor */
155	"Pentium III",      /* Intel (R) Pentium (R) III processor */
156	"Pentium III Xeon", /* Intel (R) Pentium (R) III Xeon (TM) processor */
157	"Pentium III",      /* Intel (R) Pentium (R) III processor */
158	"",		    /* Reserved */
159	"Mobile Pentium III", /* Mobile Intel (R) Pentium (R) III processor-M */
160	"Mobile Celeron",   /* Mobile Intel (R) Celeron (R) processor */
161	"Pentium 4",	    /* Intel (R) Pentium (R) 4 processor */
162	"Pentium 4",	    /* Intel (R) Pentium (R) 4 processor */
163	"Celeron",	    /* Intel (R) Celeron (TM) processor */
164	"Xeon",		    /* Intel (R) Xeon (TM) processor */
165	"Xeon MP",	    /* Intel (R) Xeon (TM) processor MP */
166	"",		    /* Reserved */
167	"Mobile Pentium 4", /* Mobile Intel (R) Pentium (R) 4 processor-M */
168	"Mobile Celeron",   /* Mobile Intel (R) Celeron (R) processor */
169};
170
171/*
172 * AMD processors don't have Brand IDs, so we need these names for probe.
173 */
174static const char * const amd_brand[] = {
175	"",
176	"Duron",	/* AMD Duron(tm) */
177	"MP",		/* AMD Athlon(tm) MP */
178	"XP",		/* AMD Athlon(tm) XP */
179	"4"		/* AMD Athlon(tm) 4 */
180};
181
182static int cpu_vendor;
183static char cpu_brand_string[49];
184static char amd_brand_name[48];
185static int use_pae, largepagesize;
186
187static void via_cpu_probe(struct cpu_info *);
188static void amd_family6_probe(struct cpu_info *);
189static void intel_family_new_probe(struct cpu_info *);
190static const char *intel_family6_name(struct cpu_info *);
191static const char *amd_amd64_name(struct cpu_info *);
192static void amd_family5_setup(struct cpu_info *);
193static void transmeta_cpu_info(struct cpu_info *);
194static const char *print_cache_config(struct cpu_info *, int, const char *,
195    const char *);
196static const char *print_tlb_config(struct cpu_info *, int, const char *,
197    const char *);
198static void 	amd_cpu_cacheinfo(struct cpu_info *);
199static void	via_cpu_cacheinfo(struct cpu_info *);
200static void	x86_print_cacheinfo(struct cpu_info *);
201static const struct x86_cache_info *cache_info_lookup(
202    const struct x86_cache_info *, uint8_t);
203static void cyrix6x86_cpu_setup(struct cpu_info *);
204static void winchip_cpu_setup(struct cpu_info *);
205static void amd_family5_setup(struct cpu_info *);
206static void powernow_probe(struct cpu_info *);
207
208/*
209 * Info for CTL_HW
210 */
211static char	cpu_model[120];
212
213/*
214 * Note: these are just the ones that may not have a cpuid instruction.
215 * We deal with the rest in a different way.
216 */
217const struct cpu_nocpuid_nameclass i386_nocpuid_cpus[] = {
218	{ CPUVENDOR_INTEL, "Intel", "386SX",	CPUCLASS_386,
219	  NULL, NULL, NULL },			/* CPU_386SX */
220	{ CPUVENDOR_INTEL, "Intel", "386DX",	CPUCLASS_386,
221	  NULL, NULL, NULL },			/* CPU_386   */
222	{ CPUVENDOR_INTEL, "Intel", "486SX",	CPUCLASS_486,
223	  NULL, NULL, NULL },			/* CPU_486SX */
224	{ CPUVENDOR_INTEL, "Intel", "486DX",	CPUCLASS_486,
225	  NULL, NULL, NULL },			/* CPU_486   */
226	{ CPUVENDOR_CYRIX, "Cyrix", "486DLC",	CPUCLASS_486,
227	  NULL, NULL, NULL },			/* CPU_486DLC */
228	{ CPUVENDOR_CYRIX, "Cyrix", "6x86",	CPUCLASS_486,
229	  NULL, NULL, NULL },		/* CPU_6x86 */
230	{ CPUVENDOR_NEXGEN,"NexGen","586",      CPUCLASS_386,
231	  NULL, NULL, NULL },			/* CPU_NX586 */
232};
233
234const char *classnames[] = {
235	"386",
236	"486",
237	"586",
238	"686"
239};
240
241const char *modifiers[] = {
242	"",
243	"OverDrive",
244	"Dual",
245	""
246};
247
248struct cpu_extend_nameclass intel_family6_ext_models[] = {
249	{ /* Extended models 1x */
250	  0x01, { NULL,			NULL,
251		  NULL,			NULL,
252		  NULL,			"EP80579 Integrated Processor",
253		  "Celeron (45nm)",	"Core 2 Extreme",
254		  NULL,			NULL,
255		  "Core i7 (Nehalem)",	NULL,
256		  "Atom",		"XeonMP (Nehalem)",
257		   NULL,		NULL} },
258	{ /* End of list */
259	  0x00, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
260		  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
261};
262
263const struct cpu_cpuid_nameclass i386_cpuid_cpus[] = {
264	{
265		"GenuineIntel",
266		CPUVENDOR_INTEL,
267		"Intel",
268		/* Family 4 */
269		{ {
270			CPUCLASS_486,
271			{
272				"486DX", "486DX", "486SX", "486DX2", "486SL",
273				"486SX2", 0, "486DX2 W/B Enhanced",
274				"486DX4", 0, 0, 0, 0, 0, 0, 0,
275				"486"		/* Default */
276			},
277			NULL,
278			NULL,
279			NULL,
280			NULL,
281		},
282		/* Family 5 */
283		{
284			CPUCLASS_586,
285			{
286				"Pentium (P5 A-step)", "Pentium (P5)",
287				"Pentium (P54C)", "Pentium (P24T)",
288				"Pentium/MMX", "Pentium", 0,
289				"Pentium (P54C)", "Pentium/MMX (Tillamook)",
290				0, 0, 0, 0, 0, 0, 0,
291				"Pentium"	/* Default */
292			},
293			NULL,
294			NULL,
295			NULL,
296			NULL,
297		},
298		/* Family 6 */
299		{
300			CPUCLASS_686,
301			{
302				"Pentium Pro (A-step)", "Pentium Pro", 0,
303				"Pentium II (Klamath)", "Pentium Pro",
304				"Pentium II/Celeron (Deschutes)",
305				"Celeron (Mendocino)",
306				"Pentium III (Katmai)",
307				"Pentium III (Coppermine)",
308				"Pentium M (Banias)",
309				"Pentium III Xeon (Cascades)",
310				"Pentium III (Tualatin)", 0,
311				"Pentium M (Dothan)",
312				"Pentium M (Yonah)",
313				"Core 2",
314				"Pentium Pro, II or III"	/* Default */
315			},
316			NULL,
317			intel_family_new_probe,
318			NULL,
319			&intel_family6_ext_models[0],
320		},
321		/* Family > 6 */
322		{
323			CPUCLASS_686,
324			{
325				0, 0, 0, 0, 0, 0, 0, 0,
326				0, 0, 0, 0, 0, 0, 0, 0,
327				"Pentium 4"	/* Default */
328			},
329			NULL,
330			intel_family_new_probe,
331			NULL,
332			NULL,
333		} }
334	},
335	{
336		"AuthenticAMD",
337		CPUVENDOR_AMD,
338		"AMD",
339		/* Family 4 */
340		{ {
341			CPUCLASS_486,
342			{
343				0, 0, 0, "Am486DX2 W/T",
344				0, 0, 0, "Am486DX2 W/B",
345				"Am486DX4 W/T or Am5x86 W/T 150",
346				"Am486DX4 W/B or Am5x86 W/B 150", 0, 0,
347				0, 0, "Am5x86 W/T 133/160",
348				"Am5x86 W/B 133/160",
349				"Am486 or Am5x86"	/* Default */
350			},
351			NULL,
352			NULL,
353			NULL,
354			NULL,
355		},
356		/* Family 5 */
357		{
358			CPUCLASS_586,
359			{
360				"K5", "K5", "K5", "K5", 0, 0, "K6",
361				"K6", "K6-2", "K6-III", "Geode LX", 0, 0,
362				"K6-2+/III+", 0, 0,
363				"K5 or K6"		/* Default */
364			},
365			amd_family5_setup,
366			NULL,
367			amd_cpu_cacheinfo,
368			NULL,
369		},
370		/* Family 6 */
371		{
372			CPUCLASS_686,
373			{
374				0, "Athlon Model 1", "Athlon Model 2",
375				"Duron", "Athlon Model 4 (Thunderbird)",
376				0, "Athlon", "Duron", "Athlon", 0,
377				"Athlon", 0, 0, 0, 0, 0,
378				"K7 (Athlon)"	/* Default */
379			},
380			NULL,
381			amd_family6_probe,
382			amd_cpu_cacheinfo,
383			NULL,
384		},
385		/* Family > 6 */
386		{
387			CPUCLASS_686,
388			{
389				0, 0, 0, 0, 0, 0, 0, 0,
390				0, 0, 0, 0, 0, 0, 0, 0,
391				"Unknown K8 (Athlon)"	/* Default */
392			},
393			NULL,
394			amd_family6_probe,
395			amd_cpu_cacheinfo,
396			NULL,
397		} }
398	},
399	{
400		"CyrixInstead",
401		CPUVENDOR_CYRIX,
402		"Cyrix",
403		/* Family 4 */
404		{ {
405			CPUCLASS_486,
406			{
407				0, 0, 0,
408				"MediaGX",
409				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
410				"486"		/* Default */
411			},
412			cyrix6x86_cpu_setup, /* XXX ?? */
413			NULL,
414			NULL,
415			NULL,
416		},
417		/* Family 5 */
418		{
419			CPUCLASS_586,
420			{
421				0, 0, "6x86", 0,
422				"MMX-enhanced MediaGX (GXm)", /* or Geode? */
423				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
424				"6x86"		/* Default */
425			},
426			cyrix6x86_cpu_setup,
427			NULL,
428			NULL,
429			NULL,
430		},
431		/* Family 6 */
432		{
433			CPUCLASS_686,
434			{
435				"6x86MX", 0, 0, 0, 0, 0, 0, 0,
436				0, 0, 0, 0, 0, 0, 0, 0,
437				"6x86MX"		/* Default */
438			},
439			cyrix6x86_cpu_setup,
440			NULL,
441			NULL,
442			NULL,
443		},
444		/* Family > 6 */
445		{
446			CPUCLASS_686,
447			{
448				0, 0, 0, 0, 0, 0, 0, 0,
449				0, 0, 0, 0, 0, 0, 0, 0,
450				"Unknown 6x86MX"		/* Default */
451			},
452			NULL,
453			NULL,
454			NULL,
455			NULL,
456		} }
457	},
458	{	/* MediaGX is now owned by National Semiconductor */
459		"Geode by NSC",
460		CPUVENDOR_CYRIX, /* XXX */
461		"National Semiconductor",
462		/* Family 4, NSC never had any of these */
463		{ {
464			CPUCLASS_486,
465			{
466				0, 0, 0, 0, 0, 0, 0, 0,
467				0, 0, 0, 0, 0, 0, 0, 0,
468				"486 compatible"	/* Default */
469			},
470			NULL,
471			NULL,
472			NULL,
473			NULL,
474		},
475		/* Family 5: Geode family, formerly MediaGX */
476		{
477			CPUCLASS_586,
478			{
479				0, 0, 0, 0,
480				"Geode GX1",
481				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
482				"Geode"		/* Default */
483			},
484			cyrix6x86_cpu_setup,
485			NULL,
486			amd_cpu_cacheinfo,
487			NULL,
488		},
489		/* Family 6, not yet available from NSC */
490		{
491			CPUCLASS_686,
492			{
493				0, 0, 0, 0, 0, 0, 0, 0,
494				0, 0, 0, 0, 0, 0, 0, 0,
495				"Pentium Pro compatible" /* Default */
496			},
497			NULL,
498			NULL,
499			NULL,
500			NULL,
501		},
502		/* Family > 6, not yet available from NSC */
503		{
504			CPUCLASS_686,
505			{
506				0, 0, 0, 0, 0, 0, 0, 0,
507				0, 0, 0, 0, 0, 0, 0, 0,
508				"Pentium Pro compatible"	/* Default */
509			},
510			NULL,
511			NULL,
512			NULL,
513			NULL,
514		} }
515	},
516	{
517		"CentaurHauls",
518		CPUVENDOR_IDT,
519		"IDT",
520		/* Family 4, IDT never had any of these */
521		{ {
522			CPUCLASS_486,
523			{
524				0, 0, 0, 0, 0, 0, 0, 0,
525				0, 0, 0, 0, 0, 0, 0, 0,
526				"486 compatible"	/* Default */
527			},
528			NULL,
529			NULL,
530			NULL,
531			NULL,
532		},
533		/* Family 5 */
534		{
535			CPUCLASS_586,
536			{
537				0, 0, 0, 0, "WinChip C6", 0, 0, 0,
538				"WinChip 2", "WinChip 3", 0, 0, 0, 0, 0, 0,
539				"WinChip"		/* Default */
540			},
541			winchip_cpu_setup,
542			NULL,
543			NULL,
544			NULL,
545		},
546		/* Family 6, VIA acquired IDT Centaur design subsidiary */
547		{
548			CPUCLASS_686,
549			{
550				0, 0, 0, 0, 0, 0, "C3 Samuel",
551				"C3 Samuel 2/Ezra", "C3 Ezra-T",
552				"C3 Nehemiah", "C7 Esther", 0, 0, "C7 Esther",
553				0, "VIA Nano",
554				"Unknown VIA/IDT"	/* Default */
555			},
556			NULL,
557			via_cpu_probe,
558			via_cpu_cacheinfo,
559			NULL,
560		},
561		/* Family > 6, not yet available from VIA */
562		{
563			CPUCLASS_686,
564			{
565				0, 0, 0, 0, 0, 0, 0, 0,
566				0, 0, 0, 0, 0, 0, 0, 0,
567				"Pentium Pro compatible"	/* Default */
568			},
569			NULL,
570			NULL,
571			NULL,
572			NULL,
573		} }
574	},
575	{
576		"GenuineTMx86",
577		CPUVENDOR_TRANSMETA,
578		"Transmeta",
579		/* Family 4, Transmeta never had any of these */
580		{ {
581			CPUCLASS_486,
582			{
583				0, 0, 0, 0, 0, 0, 0, 0,
584				0, 0, 0, 0, 0, 0, 0, 0,
585				"486 compatible"	/* Default */
586			},
587			NULL,
588			NULL,
589			NULL,
590			NULL,
591		},
592		/* Family 5 */
593		{
594			CPUCLASS_586,
595			{
596				0, 0, 0, 0, 0, 0, 0, 0,
597				0, 0, 0, 0, 0, 0, 0, 0,
598				"Crusoe"		/* Default */
599			},
600			NULL,
601			NULL,
602			transmeta_cpu_info,
603			NULL,
604		},
605		/* Family 6, not yet available from Transmeta */
606		{
607			CPUCLASS_686,
608			{
609				0, 0, 0, 0, 0, 0, 0, 0,
610				0, 0, 0, 0, 0, 0, 0, 0,
611				"Pentium Pro compatible"	/* Default */
612			},
613			NULL,
614			NULL,
615			NULL,
616			NULL,
617		},
618		/* Family > 6, not yet available from Transmeta */
619		{
620			CPUCLASS_686,
621			{
622				0, 0, 0, 0, 0, 0, 0, 0,
623				0, 0, 0, 0, 0, 0, 0, 0,
624				"Pentium Pro compatible"	/* Default */
625			},
626			NULL,
627			NULL,
628			NULL,
629			NULL,
630		} }
631	}
632};
633
634/*
635 * disable the TSC such that we don't use the TSC in microtime(9)
636 * because some CPUs got the implementation wrong.
637 */
638static void
639disable_tsc(struct cpu_info *ci)
640{
641	if (ci->ci_feat_val[0] & CPUID_TSC) {
642		ci->ci_feat_val[0] &= ~CPUID_TSC;
643		aprint_error("WARNING: broken TSC disabled\n");
644	}
645}
646
647static void
648cyrix6x86_cpu_setup(struct cpu_info *ci)
649{
650
651	/*
652	 * Do not disable the TSC on the Geode GX, it's reported to
653	 * work fine.
654	 */
655	if (ci->ci_signature != 0x552)
656		disable_tsc(ci);
657}
658
659void
660winchip_cpu_setup(struct cpu_info *ci)
661{
662	switch (CPUID2MODEL(ci->ci_signature)) { /* model */
663	case 4:	/* WinChip C6 */
664		disable_tsc(ci);
665	}
666}
667
668
669static void
670identifycpu_cpuids(struct cpu_info *ci)
671{
672	const char *cpuname = ci->ci_dev;
673	u_int lp_max = 1;	/* logical processors per package */
674	u_int smt_max;		/* smt per core */
675	u_int core_max = 1;	/* core per package */
676	u_int smt_bits, core_bits;
677	uint32_t descs[4];
678
679	aprint_verbose("%s: Initial APIC ID %u\n", cpuname, ci->ci_initapicid);
680	ci->ci_packageid = ci->ci_initapicid;
681	ci->ci_coreid = 0;
682	ci->ci_smtid = 0;
683	if (cpu_vendor != CPUVENDOR_INTEL) {
684		return;
685	}
686
687	/*
688	 * 253668.pdf 7.10.2
689	 */
690
691	if ((ci->ci_feat_val[0] & CPUID_HTT) != 0) {
692		x86_cpuid(1, descs);
693		lp_max = (descs[1] >> 16) & 0xff;
694	}
695	x86_cpuid(0, descs);
696	if (descs[0] >= 4) {
697		x86_cpuid2(4, 0, descs);
698		core_max = (descs[0] >> 26) + 1;
699	}
700	assert(lp_max >= core_max);
701	smt_max = lp_max / core_max;
702	smt_bits = ilog2(smt_max - 1) + 1;
703	core_bits = ilog2(core_max - 1) + 1;
704	if (smt_bits + core_bits) {
705		ci->ci_packageid = ci->ci_initapicid >> (smt_bits + core_bits);
706	}
707	aprint_verbose("%s: Cluster/Package ID %u\n", cpuname,
708	    ci->ci_packageid);
709	if (core_bits) {
710		u_int core_mask = __BITS(smt_bits, smt_bits + core_bits - 1);
711
712		ci->ci_coreid =
713		    __SHIFTOUT(ci->ci_initapicid, core_mask);
714		aprint_verbose("%s: Core ID %u\n", cpuname, ci->ci_coreid);
715	}
716	if (smt_bits) {
717		u_int smt_mask = __BITS((int)0, (int)(smt_bits - 1));
718
719		ci->ci_smtid = __SHIFTOUT(ci->ci_initapicid, smt_mask);
720		aprint_verbose("%s: SMT ID %u\n", cpuname, ci->ci_smtid);
721	}
722}
723
724static void
725via_cpu_probe(struct cpu_info *ci)
726{
727	u_int model = CPUID2MODEL(ci->ci_signature);
728	u_int stepping = CPUID2STEPPING(ci->ci_signature);
729	u_int descs[4];
730	u_int lfunc;
731
732	/*
733	 * Determine the largest extended function value.
734	 */
735	x86_cpuid(0x80000000, descs);
736	lfunc = descs[0];
737
738	/*
739	 * Determine the extended feature flags.
740	 */
741	if (lfunc >= 0x80000001) {
742		x86_cpuid(0x80000001, descs);
743		ci->ci_feat_val[2] |= descs[3];
744	}
745
746	if (model < 0x9 || (model == 0x9 && stepping < 3))
747		return;
748
749	/* Nehemiah or Esther */
750	x86_cpuid(0xc0000000, descs);
751	lfunc = descs[0];
752	if (lfunc < 0xc0000001)	/* no ACE, no RNG */
753		return;
754
755	x86_cpuid(0xc0000001, descs);
756	lfunc = descs[3];
757	ci->ci_feat_val[4] = lfunc;
758}
759
760static const char *
761intel_family6_name(struct cpu_info *ci)
762{
763	int model = CPUID2MODEL(ci->ci_signature);
764	const char *ret = NULL;
765	u_int l2cache = ci->ci_cinfo[CAI_L2CACHE].cai_totalsize;
766
767	if (model == 5) {
768		switch (l2cache) {
769		case 0:
770		case 128 * 1024:
771			ret = "Celeron (Covington)";
772			break;
773		case 256 * 1024:
774			ret = "Mobile Pentium II (Dixon)";
775			break;
776		case 512 * 1024:
777			ret = "Pentium II";
778			break;
779		case 1 * 1024 * 1024:
780		case 2 * 1024 * 1024:
781			ret = "Pentium II Xeon";
782			break;
783		}
784	} else if (model == 6) {
785		switch (l2cache) {
786		case 256 * 1024:
787		case 512 * 1024:
788			ret = "Mobile Pentium II";
789			break;
790		}
791	} else if (model == 7) {
792		switch (l2cache) {
793		case 512 * 1024:
794			ret = "Pentium III";
795			break;
796		case 1 * 1024 * 1024:
797		case 2 * 1024 * 1024:
798			ret = "Pentium III Xeon";
799			break;
800		}
801	} else if (model >= 8) {
802		if (ci->ci_brand_id && ci->ci_brand_id < 0x10) {
803			switch (ci->ci_brand_id) {
804			case 0x3:
805				if (ci->ci_signature == 0x6B1)
806					ret = "Celeron";
807				break;
808			case 0x8:
809				if (ci->ci_signature >= 0xF13)
810					ret = "genuine processor";
811				break;
812			case 0xB:
813				if (ci->ci_signature >= 0xF13)
814					ret = "Xeon MP";
815				break;
816			case 0xE:
817				if (ci->ci_signature < 0xF13)
818					ret = "Xeon";
819				break;
820			}
821			if (ret == NULL)
822				ret = i386_intel_brand[ci->ci_brand_id];
823		}
824	}
825
826	return ret;
827}
828
829/*
830 * Identify AMD64 CPU names from cpuid.
831 *
832 * Based on:
833 * "Revision Guide for AMD Athlon 64 and AMD Opteron Processors"
834 * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25759.pdf
835 * "Revision Guide for AMD NPT Family 0Fh Processors"
836 * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/33610.pdf
837 * and other miscellaneous reports.
838 */
839static const char *
840amd_amd64_name(struct cpu_info *ci)
841{
842	int extfamily, extmodel, model;
843	const char *ret = NULL;
844
845	model = CPUID2MODEL(ci->ci_signature);
846	extfamily = CPUID2EXTFAMILY(ci->ci_signature);
847	extmodel  = CPUID2EXTMODEL(ci->ci_signature);
848
849	switch (extfamily) {
850	case 0x00:
851		switch (model) {
852		case 0x1:
853			switch (extmodel) {
854			case 0x2:	/* rev JH-E1/E6 */
855			case 0x4:	/* rev JH-F2 */
856				ret = "Dual-Core Opteron";
857				break;
858			}
859			break;
860		case 0x3:
861			switch (extmodel) {
862			case 0x2:	/* rev JH-E6 (Toledo) */
863				ret = "Dual-Core Opteron or Athlon 64 X2";
864				break;
865			case 0x4:	/* rev JH-F2 (Windsor) */
866				ret = "Athlon 64 FX or Athlon 64 X2";
867				break;
868			}
869			break;
870		case 0x4:
871			switch (extmodel) {
872			case 0x0:	/* rev SH-B0/C0/CG (ClawHammer) */
873			case 0x1:	/* rev SH-D0 */
874				ret = "Athlon 64";
875				break;
876			case 0x2:	/* rev SH-E5 (Lancaster?) */
877				ret = "Mobile Athlon 64 or Turion 64";
878				break;
879			}
880			break;
881		case 0x5:
882			switch (extmodel) {
883			case 0x0:	/* rev SH-B0/B3/C0/CG (SledgeHammer?) */
884				ret = "Opteron or Athlon 64 FX";
885				break;
886			case 0x1:	/* rev SH-D0 */
887			case 0x2:	/* rev SH-E4 */
888				ret = "Opteron";
889				break;
890			}
891			break;
892		case 0x7:
893			switch (extmodel) {
894			case 0x0:	/* rev SH-CG (ClawHammer) */
895			case 0x1:	/* rev SH-D0 */
896				ret = "Athlon 64";
897				break;
898			case 0x2:	/* rev DH-E4, SH-E4 */
899				ret = "Athlon 64 or Athlon 64 FX or Opteron";
900				break;
901			}
902			break;
903		case 0x8:
904			switch (extmodel) {
905			case 0x0:	/* rev CH-CG */
906			case 0x1:	/* rev CH-D0 */
907				ret = "Athlon 64 or Sempron";
908				break;
909			case 0x4:	/* rev BH-F2 */
910				ret = "Turion 64 X2";
911				break;
912			}
913			break;
914		case 0xb:
915			switch (extmodel) {
916			case 0x0:	/* rev CH-CG */
917			case 0x1:	/* rev CH-D0 */
918				ret = "Athlon 64";
919				break;
920			case 0x2:	/* rev BH-E4 (Manchester) */
921			case 0x4:	/* rev BH-F2 (Windsor) */
922				ret = "Athlon 64 X2";
923				break;
924			case 0x6:	/* rev BH-G1 (Brisbane) */
925				ret = "Athlon X2 or Athlon 64 X2";
926				break;
927			}
928			break;
929		case 0xc:
930			switch (extmodel) {
931			case 0x0:	/* rev DH-CG (Newcastle) */
932			case 0x1:	/* rev DH-D0 (Winchester) */
933			case 0x2:	/* rev DH-E3/E6 */
934				ret = "Athlon 64 or Sempron";
935				break;
936			}
937			break;
938		case 0xe:
939			switch (extmodel) {
940			case 0x0:	/* rev DH-CG (Newcastle?) */
941				ret = "Athlon 64 or Sempron";
942				break;
943			}
944			break;
945		case 0xf:
946			switch (extmodel) {
947			case 0x0:	/* rev DH-CG (Newcastle/Paris) */
948			case 0x1:	/* rev DH-D0 (Winchester/Victoria) */
949			case 0x2:	/* rev DH-E3/E6 (Venice/Palermo) */
950			case 0x4:	/* rev DH-F2 (Orleans/Manila) */
951			case 0x5:	/* rev DH-F2 (Orleans/Manila) */
952			case 0x6:	/* rev DH-G1 */
953				ret = "Athlon 64 or Sempron";
954				break;
955			}
956			break;
957		default:
958			ret = "Unknown AMD64 CPU";
959		}
960		break;
961	case 0x01:
962		ret = "Family 10h";
963		break;
964	case 0x02:
965		ret = "Family 11h";
966		break;
967	case 0x03:
968		ret = "Family 12h";
969		break;
970	case 0x05:
971		ret = "Family 14h";
972		break;
973	case 0x06:
974		ret = "Family 15h";
975		break;
976	default:
977		ret = "Unknown AMD64 CPU";
978		break;
979	}
980
981	return ret;
982}
983
984static void
985cpu_probe_base_features(struct cpu_info *ci)
986{
987	const struct x86_cache_info *cai;
988	u_int descs[4];
989	int iterations, i, j;
990	uint8_t desc;
991	uint32_t miscbytes;
992	uint32_t brand[12];
993
994	if (ci->ci_cpuid_level < 0)
995		return;
996
997	x86_cpuid(0, descs);
998	ci->ci_cpuid_level = descs[0];
999	ci->ci_vendor[0] = descs[1];
1000	ci->ci_vendor[2] = descs[2];
1001	ci->ci_vendor[1] = descs[3];
1002	ci->ci_vendor[3] = 0;
1003
1004	x86_cpuid(0x80000000, brand);
1005	if (brand[0] >= 0x80000004) {
1006		x86_cpuid(0x80000002, brand);
1007		x86_cpuid(0x80000003, brand + 4);
1008		x86_cpuid(0x80000004, brand + 8);
1009		for (i = 0; i < 48; i++)
1010			if (((char *) brand)[i] != ' ')
1011				break;
1012		memcpy(cpu_brand_string, ((char *) brand) + i, 48 - i);
1013	}
1014
1015	if (ci->ci_cpuid_level < 1)
1016		return;
1017
1018	x86_cpuid(1, descs);
1019	ci->ci_signature = descs[0];
1020	miscbytes = descs[1];
1021	ci->ci_feat_val[1] = descs[2];
1022	ci->ci_feat_val[0] = descs[3];
1023
1024	/* Brand is low order 8 bits of ebx */
1025	ci->ci_brand_id = miscbytes & 0xff;
1026	ci->ci_initapicid = (miscbytes >> 24) & 0xff;
1027	if (ci->ci_cpuid_level < 2)
1028		return;
1029
1030	/*
1031	 * Parse the cache info from `cpuid', if we have it.
1032	 * XXX This is kinda ugly, but hey, so is the architecture...
1033	 */
1034
1035	x86_cpuid(2, descs);
1036
1037	iterations = descs[0] & 0xff;
1038	while (iterations-- > 0) {
1039		for (i = 0; i < 4; i++) {
1040			if (descs[i] & 0x80000000)
1041				continue;
1042			for (j = 0; j < 4; j++) {
1043				if (i == 0 && j == 0)
1044					continue;
1045				desc = (descs[i] >> (j * 8)) & 0xff;
1046				if (desc == 0)
1047					continue;
1048				cai = cache_info_lookup(intel_cpuid_cache_info,
1049				    desc);
1050				if (cai != NULL)
1051					ci->ci_cinfo[cai->cai_index] = *cai;
1052			}
1053		}
1054		x86_cpuid(2, descs);
1055	}
1056
1057	if (ci->ci_cpuid_level < 3)
1058		return;
1059
1060	/*
1061	 * If the processor serial number misfeature is present and supported,
1062	 * extract it here.
1063	 */
1064	if ((ci->ci_feat_val[0] & CPUID_PN) != 0) {
1065		ci->ci_cpu_serial[0] = ci->ci_signature;
1066		x86_cpuid(3, descs);
1067		ci->ci_cpu_serial[2] = descs[2];
1068		ci->ci_cpu_serial[1] = descs[3];
1069	}
1070}
1071
1072static void
1073cpu_probe_features(struct cpu_info *ci)
1074{
1075	const struct cpu_cpuid_nameclass *cpup = NULL;
1076	int i, xmax, family;
1077
1078	cpu_probe_base_features(ci);
1079
1080	if (ci->ci_cpuid_level < 1)
1081		return;
1082
1083	xmax = __arraycount(i386_cpuid_cpus);
1084	for (i = 0; i < xmax; i++) {
1085		if (!strncmp((char *)ci->ci_vendor,
1086		    i386_cpuid_cpus[i].cpu_id, 12)) {
1087			cpup = &i386_cpuid_cpus[i];
1088			break;
1089		}
1090	}
1091
1092	if (cpup == NULL)
1093		return;
1094
1095	family = (ci->ci_signature >> 8) & 0xf;
1096
1097	if (family > CPU_MAXFAMILY) {
1098		family = CPU_MAXFAMILY;
1099	}
1100	i = family - CPU_MINFAMILY;
1101
1102	if (cpup->cpu_family[i].cpu_probe == NULL)
1103		return;
1104
1105	(*cpup->cpu_family[i].cpu_probe)(ci);
1106}
1107
1108static void
1109intel_family_new_probe(struct cpu_info *ci)
1110{
1111	uint32_t descs[4];
1112
1113	x86_cpuid(0x80000000, descs);
1114
1115	/*
1116	 * Determine extended feature flags.
1117	 */
1118	if (descs[0] >= 0x80000001) {
1119		x86_cpuid(0x80000001, descs);
1120		ci->ci_feat_val[2] |= descs[3];
1121		ci->ci_feat_val[3] |= descs[2];
1122	}
1123}
1124
1125static void
1126amd_family6_probe(struct cpu_info *ci)
1127{
1128	uint32_t descs[4];
1129	char *p;
1130	size_t i;
1131
1132	x86_cpuid(0x80000000, descs);
1133
1134	/*
1135	 * Determine the extended feature flags.
1136	 */
1137	if (descs[0] >= 0x80000001) {
1138		x86_cpuid(0x80000001, descs);
1139		ci->ci_feat_val[2] |= descs[3]; /* %edx */
1140		ci->ci_feat_val[3] = descs[2]; /* %ecx */
1141	}
1142
1143	if (*cpu_brand_string == '\0')
1144		return;
1145
1146	for (i = 1; i < __arraycount(amd_brand); i++)
1147		if ((p = strstr(cpu_brand_string, amd_brand[i])) != NULL) {
1148			ci->ci_brand_id = i;
1149			strlcpy(amd_brand_name, p, sizeof(amd_brand_name));
1150			break;
1151		}
1152}
1153
1154static void
1155amd_family5_setup(struct cpu_info *ci)
1156{
1157
1158	switch (CPUID2MODEL(ci->ci_signature)) {
1159	case 0:		/* AMD-K5 Model 0 */
1160		/*
1161		 * According to the AMD Processor Recognition App Note,
1162		 * the AMD-K5 Model 0 uses the wrong bit to indicate
1163		 * support for global PTEs, instead using bit 9 (APIC)
1164		 * rather than bit 13 (i.e. "0x200" vs. 0x2000".  Oops!).
1165		 */
1166		if (ci->ci_feat_val[0] & CPUID_APIC)
1167			ci->ci_feat_val[0] =
1168			    (ci->ci_feat_val[0] & ~CPUID_APIC) | CPUID_PGE;
1169		/*
1170		 * XXX But pmap_pg_g is already initialized -- need to kick
1171		 * XXX the pmap somehow.  How does the MP branch do this?
1172		 */
1173		break;
1174	}
1175}
1176
1177static void
1178tmx86_get_longrun_status(u_int *frequency, u_int *voltage, u_int *percentage)
1179{
1180	u_int descs[4];
1181
1182	x86_cpuid(0x80860007, descs);
1183	*frequency = descs[0];
1184	*voltage = descs[1];
1185	*percentage = descs[2];
1186}
1187
1188static void
1189transmeta_cpu_info(struct cpu_info *ci)
1190{
1191	u_int descs[4], nreg;
1192	u_int frequency, voltage, percentage;
1193
1194	x86_cpuid(0x80860000, descs);
1195	nreg = descs[0];
1196	if (nreg >= 0x80860001) {
1197		x86_cpuid(0x80860001, descs);
1198		aprint_verbose_dev(ci->ci_dev, "Processor revision %u.%u.%u.%u\n",
1199		    (descs[1] >> 24) & 0xff,
1200		    (descs[1] >> 16) & 0xff,
1201		    (descs[1] >> 8) & 0xff,
1202		    descs[1] & 0xff);
1203	}
1204	if (nreg >= 0x80860002) {
1205		x86_cpuid(0x80860002, descs);
1206		aprint_verbose_dev(ci->ci_dev, "Code Morphing Software Rev: %u.%u.%u-%u-%u\n",
1207		    (descs[1] >> 24) & 0xff,
1208		    (descs[1] >> 16) & 0xff,
1209		    (descs[1] >> 8) & 0xff,
1210		    descs[1] & 0xff,
1211		    descs[2]);
1212	}
1213	if (nreg >= 0x80860006) {
1214		union {
1215			char text[65];
1216			u_int descs[4][4];
1217		} info;
1218		int i;
1219
1220		for (i=0; i<4; i++) {
1221			x86_cpuid(0x80860003 + i, info.descs[i]);
1222		}
1223		info.text[64] = '\0';
1224		aprint_verbose_dev(ci->ci_dev, "%s\n", info.text);
1225	}
1226
1227	if (nreg >= 0x80860007) {
1228		tmx86_get_longrun_status(&frequency,
1229		    &voltage, &percentage);
1230		aprint_verbose_dev(ci->ci_dev, "LongRun <%dMHz %dmV %d%%>\n",
1231		    frequency, voltage, percentage);
1232	}
1233}
1234
1235void
1236identifycpu(const char *cpuname)
1237{
1238	const char *name = "", *modifier, *vendorname, *brand = "";
1239	int class = CPUCLASS_386, i, xmax;
1240	int modif, family, model, ext_model;
1241	const struct cpu_extend_nameclass *modlist;
1242	const struct cpu_cpuid_nameclass *cpup = NULL;
1243	const struct cpu_cpuid_family *cpufam;
1244	const char *feature_str[5];
1245	struct cpu_info *ci, cistore;
1246	extern int cpu;
1247	extern int cpu_info_level;
1248	size_t sz;
1249	char buf[512];
1250	char *bp;
1251
1252	ci = &cistore;
1253	memset(ci, 0, sizeof(*ci));
1254	ci->ci_dev = cpuname;
1255
1256	x86_identify();
1257	ci->ci_cpuid_level = cpu_info_level;
1258	cpu_probe_features(ci);
1259
1260	if (ci->ci_cpuid_level == -1) {
1261		if ((size_t)cpu >= __arraycount(i386_nocpuid_cpus))
1262			errx(1, "unknown cpu type %d", cpu);
1263		name = i386_nocpuid_cpus[cpu].cpu_name;
1264		cpu_vendor = i386_nocpuid_cpus[cpu].cpu_vendor;
1265		vendorname = i386_nocpuid_cpus[cpu].cpu_vendorname;
1266		class = i386_nocpuid_cpus[cpu].cpu_class;
1267		ci->ci_info = i386_nocpuid_cpus[cpu].cpu_info;
1268		modifier = "";
1269	} else {
1270		xmax = __arraycount(i386_cpuid_cpus);
1271		modif = (ci->ci_signature >> 12) & 0x3;
1272		family = CPUID2FAMILY(ci->ci_signature);
1273		if (family < CPU_MINFAMILY)
1274			errx(1, "identifycpu: strange family value");
1275		model = CPUID2MODEL(ci->ci_signature);
1276		ext_model = CPUID2EXTMODEL(ci->ci_signature);
1277
1278		for (i = 0; i < xmax; i++) {
1279			if (!strncmp((char *)ci->ci_vendor,
1280			    i386_cpuid_cpus[i].cpu_id, 12)) {
1281				cpup = &i386_cpuid_cpus[i];
1282				break;
1283			}
1284		}
1285
1286		if (cpup == NULL) {
1287			cpu_vendor = CPUVENDOR_UNKNOWN;
1288			if (ci->ci_vendor[0] != '\0')
1289				vendorname = (char *)&ci->ci_vendor[0];
1290			else
1291				vendorname = "Unknown";
1292			if (family >= CPU_MAXFAMILY)
1293				family = CPU_MINFAMILY;
1294			class = family - 3;
1295			modifier = "";
1296			name = "";
1297			ci->ci_info = NULL;
1298		} else {
1299			cpu_vendor = cpup->cpu_vendor;
1300			vendorname = cpup->cpu_vendorname;
1301			modifier = modifiers[modif];
1302			if (family > CPU_MAXFAMILY) {
1303				family = CPU_MAXFAMILY;
1304				model = CPU_DEFMODEL;
1305			} else if (model > CPU_MAXMODEL) {
1306				model = CPU_DEFMODEL;
1307				ext_model = 0;
1308			}
1309			cpufam = &cpup->cpu_family[family - CPU_MINFAMILY];
1310			if (cpufam->cpu_extended_names == NULL ||
1311			    ext_model == 0)
1312				name = cpufam->cpu_models[model];
1313			else {
1314				/*
1315				 * Scan list(s) of extended model names
1316				 */
1317				modlist = cpufam->cpu_extended_names;
1318				while (modlist->ext_model != 0) {
1319					if (modlist->ext_model == ext_model) {
1320						name =
1321						     modlist->cpu_models[model];
1322						break;
1323					}
1324					modlist++;
1325				}
1326			}
1327			if (name == NULL || *name == '\0')
1328			    name = cpufam->cpu_models[CPU_DEFMODEL];
1329			class = cpufam->cpu_class;
1330			ci->ci_info = cpufam->cpu_info;
1331
1332			if (cpu_vendor == CPUVENDOR_INTEL) {
1333				if (family == 6 && model >= 5) {
1334					const char *tmp;
1335					tmp = intel_family6_name(ci);
1336					if (tmp != NULL)
1337						name = tmp;
1338				}
1339				if (family == CPU_MAXFAMILY &&
1340				    ci->ci_brand_id <
1341				    __arraycount(i386_intel_brand) &&
1342				    i386_intel_brand[ci->ci_brand_id])
1343					name =
1344					     i386_intel_brand[ci->ci_brand_id];
1345			}
1346
1347			if (cpu_vendor == CPUVENDOR_AMD) {
1348				if (family == 6 && model >= 6) {
1349					if (ci->ci_brand_id == 1)
1350						/*
1351						 * It's Duron. We override the
1352						 * name, since it might have
1353						 * been misidentified as Athlon.
1354						 */
1355						name =
1356						    amd_brand[ci->ci_brand_id];
1357					else
1358						brand = amd_brand_name;
1359				}
1360				if (CPUID2FAMILY(ci->ci_signature) == 0xf) {
1361					/*
1362					 * Identify AMD64 CPU names.
1363					 * Note family value is clipped by
1364					 * CPU_MAXFAMILY.
1365					 */
1366					const char *tmp;
1367					tmp = amd_amd64_name(ci);
1368					if (tmp != NULL)
1369						name = tmp;
1370				}
1371			}
1372
1373			if (cpu_vendor == CPUVENDOR_IDT && family >= 6)
1374				vendorname = "VIA";
1375		}
1376	}
1377
1378	ci->ci_cpu_class = class;
1379
1380	sz = sizeof(ci->ci_tsc_freq);
1381	(void)sysctlbyname("machdep.tsc_freq", &ci->ci_tsc_freq, &sz, NULL, 0);
1382	sz = sizeof(use_pae);
1383	(void)sysctlbyname("machdep.pae", &use_pae, &sz, NULL, 0);
1384	largepagesize = (use_pae ? 2 * 1024 * 1024 : 4 * 1024 * 1024);
1385
1386	snprintf(cpu_model, sizeof(cpu_model), "%s%s%s%s%s%s%s (%s-class)",
1387	    vendorname,
1388	    *modifier ? " " : "", modifier,
1389	    *name ? " " : "", name,
1390	    *brand ? " " : "", brand,
1391	    classnames[class]);
1392	aprint_normal("%s: %s", cpuname, cpu_model);
1393
1394	if (ci->ci_tsc_freq != 0)
1395		aprint_normal(", %ju.%02ju MHz",
1396		    ((uintmax_t)ci->ci_tsc_freq + 4999) / 1000000,
1397		    (((uintmax_t)ci->ci_tsc_freq + 4999) / 10000) % 100);
1398	if (ci->ci_signature != 0)
1399		aprint_normal(", id 0x%x", ci->ci_signature);
1400	aprint_normal("\n");
1401
1402	if (ci->ci_info)
1403		(*ci->ci_info)(ci);
1404
1405	/*
1406	 * display CPU feature flags
1407	 */
1408
1409#define	MAX_FEATURE_LEN	60	/* XXX Need to find a better way to set this */
1410
1411	feature_str[0] = CPUID_FLAGS1;
1412	feature_str[1] = CPUID2_FLAGS1;
1413	feature_str[2] = CPUID_EXT_FLAGS;
1414	feature_str[3] = NULL;
1415	feature_str[4] = NULL;
1416
1417	switch (cpu_vendor) {
1418	case CPUVENDOR_AMD:
1419		feature_str[3] = CPUID_AMD_FLAGS4;
1420		break;
1421	case CPUVENDOR_INTEL:
1422		feature_str[2] = CPUID_INTEL_EXT_FLAGS;
1423		feature_str[3] = CPUID_INTEL_FLAGS4;
1424		break;
1425	case CPUVENDOR_IDT:
1426		feature_str[4] = CPUID_FLAGS_PADLOCK;
1427		break;
1428	default:
1429		break;
1430	}
1431
1432	for (i = 0; i <= 4; i++) {
1433		if (ci->ci_feat_val[i] && feature_str[i] != NULL) {
1434			snprintb_m(buf, sizeof(buf), feature_str[i],
1435				   ci->ci_feat_val[i], MAX_FEATURE_LEN);
1436			bp = buf;
1437			while (*bp != '\0') {
1438				aprint_verbose("%s: %sfeatures%c %s\n",
1439				    cpuname, (i == 4)?"padlock ":"",
1440				    (i == 4 || i == 0)?' ':'1' + i, bp);
1441				bp += strlen(bp) + 1;
1442			}
1443		}
1444	}
1445
1446	if (*cpu_brand_string != '\0')
1447		aprint_normal("%s: \"%s\"\n", cpuname, cpu_brand_string);
1448
1449	x86_print_cacheinfo(ci);
1450
1451	if (ci->ci_cpuid_level >= 3 && (ci->ci_feat_val[0] & CPUID_PN)) {
1452		aprint_verbose("%s: serial number %04X-%04X-%04X-%04X-%04X-%04X\n",
1453		    cpuname,
1454		    ci->ci_cpu_serial[0] / 65536, ci->ci_cpu_serial[0] % 65536,
1455		    ci->ci_cpu_serial[1] / 65536, ci->ci_cpu_serial[1] % 65536,
1456		    ci->ci_cpu_serial[2] / 65536, ci->ci_cpu_serial[2] % 65536);
1457	}
1458
1459	if (ci->ci_cpu_class == CPUCLASS_386) {
1460		errx(1, "NetBSD requires an 80486 or later processor");
1461	}
1462
1463	if (cpu == CPU_486DLC) {
1464#ifndef CYRIX_CACHE_WORKS
1465		aprint_error("WARNING: CYRIX 486DLC CACHE UNCHANGED.\n");
1466#else
1467#ifndef CYRIX_CACHE_REALLY_WORKS
1468		aprint_error("WARNING: CYRIX 486DLC CACHE ENABLED IN HOLD-FLUSH MODE.\n");
1469#else
1470		aprint_error("WARNING: CYRIX 486DLC CACHE ENABLED.\n");
1471#endif
1472#endif
1473	}
1474
1475	/*
1476	 * Everything past this point requires a Pentium or later.
1477	 */
1478	if (ci->ci_cpuid_level < 0)
1479		return;
1480
1481	identifycpu_cpuids(ci);
1482
1483#ifdef INTEL_CORETEMP
1484	if (cpu_vendor == CPUVENDOR_INTEL && ci->ci_cpuid_level >= 0x06)
1485		coretemp_register(ci);
1486#endif
1487
1488	if (cpu_vendor == CPUVENDOR_AMD) {
1489		uint32_t data[4];
1490
1491		x86_cpuid(0x80000000, data);
1492		if (data[0] >= 0x80000007)
1493			powernow_probe(ci);
1494
1495		if ((data[0] >= 0x8000000a)
1496		   && (ci->ci_feat_val[3] & CPUID_SVM) != 0) {
1497
1498			x86_cpuid(0x8000000a, data);
1499			aprint_verbose("%s: SVM Rev. %d\n", cpuname,
1500			    data[0] & 0xf);
1501			aprint_verbose("%s: SVM NASID %d\n", cpuname, data[1]);
1502			snprintb_m(buf, sizeof(buf), CPUID_AMD_SVM_FLAGS,
1503				   data[3], MAX_FEATURE_LEN);
1504			bp = buf;
1505			while (*bp != '\0') {
1506				aprint_verbose("%s: SVM features %s\n",
1507				    cpuname, bp);
1508				bp += strlen(bp) + 1;
1509			}
1510		}
1511	}
1512
1513#ifdef INTEL_ONDEMAND_CLOCKMOD
1514	clockmod_init();
1515#endif
1516
1517	aprint_normal_dev(ci->ci_dev, "family %02x model %02x "
1518	    "extfamily %02x extmodel %02x stepping %02x\n",
1519	    CPUID2FAMILY(ci->ci_signature), CPUID2MODEL(ci->ci_signature),
1520	    CPUID2EXTFAMILY(ci->ci_signature), CPUID2EXTMODEL(ci->ci_signature),
1521	    CPUID2STEPPING(ci->ci_signature));
1522}
1523
1524static const char *
1525print_cache_config(struct cpu_info *ci, int cache_tag, const char *name,
1526    const char *sep)
1527{
1528	struct x86_cache_info *cai = &ci->ci_cinfo[cache_tag];
1529	char human_num[HUMAN_BUFSIZE];
1530
1531	if (cai->cai_totalsize == 0)
1532		return sep;
1533
1534	if (sep == NULL)
1535		aprint_verbose_dev(ci->ci_dev, "");
1536	else
1537		aprint_verbose("%s", sep);
1538	if (name != NULL)
1539		aprint_verbose("%s ", name);
1540
1541	if (cai->cai_string != NULL) {
1542		aprint_verbose("%s ", cai->cai_string);
1543	} else {
1544		(void)humanize_number(human_num, sizeof(human_num),
1545			cai->cai_totalsize, "B", HN_AUTOSCALE, HN_NOSPACE);
1546		aprint_verbose("%s %dB/line ", human_num, cai->cai_linesize);
1547	}
1548	switch (cai->cai_associativity) {
1549	case    0:
1550		aprint_verbose("disabled");
1551		break;
1552	case    1:
1553		aprint_verbose("direct-mapped");
1554		break;
1555	case 0xff:
1556		aprint_verbose("fully associative");
1557		break;
1558	default:
1559		aprint_verbose("%d-way", cai->cai_associativity);
1560		break;
1561	}
1562	return ", ";
1563}
1564
1565static const char *
1566print_tlb_config(struct cpu_info *ci, int cache_tag, const char *name,
1567    const char *sep)
1568{
1569	struct x86_cache_info *cai = &ci->ci_cinfo[cache_tag];
1570	char human_num[HUMAN_BUFSIZE];
1571
1572	if (cai->cai_totalsize == 0)
1573		return sep;
1574
1575	if (sep == NULL)
1576		aprint_verbose_dev(ci->ci_dev, "");
1577	else
1578		aprint_verbose("%s", sep);
1579	if (name != NULL)
1580		aprint_verbose("%s ", name);
1581
1582	if (cai->cai_string != NULL) {
1583		aprint_verbose("%s", cai->cai_string);
1584	} else {
1585		(void)humanize_number(human_num, sizeof(human_num),
1586			cai->cai_linesize, "B", HN_AUTOSCALE, HN_NOSPACE);
1587		aprint_verbose("%d %s entries ", cai->cai_totalsize,
1588		    human_num);
1589		switch (cai->cai_associativity) {
1590		case 0:
1591			aprint_verbose("disabled");
1592			break;
1593		case 1:
1594			aprint_verbose("direct-mapped");
1595			break;
1596		case 0xff:
1597			aprint_verbose("fully associative");
1598			break;
1599		default:
1600			aprint_verbose("%d-way", cai->cai_associativity);
1601			break;
1602		}
1603	}
1604	return ", ";
1605}
1606
1607static const struct x86_cache_info *
1608cache_info_lookup(const struct x86_cache_info *cai, uint8_t desc)
1609{
1610	int i;
1611
1612	for (i = 0; cai[i].cai_desc != 0; i++) {
1613		if (cai[i].cai_desc == desc)
1614			return (&cai[i]);
1615	}
1616
1617	return (NULL);
1618}
1619
1620static const struct x86_cache_info amd_cpuid_l2cache_assoc_info[] =
1621    AMD_L2CACHE_INFO;
1622
1623static const struct x86_cache_info amd_cpuid_l3cache_assoc_info[] =
1624    AMD_L3CACHE_INFO;
1625
1626static void
1627amd_cpu_cacheinfo(struct cpu_info *ci)
1628{
1629	const struct x86_cache_info *cp;
1630	struct x86_cache_info *cai;
1631	int family, model;
1632	u_int descs[4];
1633	u_int lfunc;
1634
1635	family = (ci->ci_signature >> 8) & 15;
1636	model = CPUID2MODEL(ci->ci_signature);
1637
1638	/*
1639	 * K5 model 0 has none of this info.
1640	 */
1641	if (family == 5 && model == 0)
1642		return;
1643
1644	/*
1645	 * Get extended values for K8 and up.
1646	 */
1647	if (family == 0xf) {
1648		family += CPUID2EXTFAMILY(ci->ci_signature);
1649		model += CPUID2EXTMODEL(ci->ci_signature);
1650	}
1651
1652	/*
1653	 * Determine the largest extended function value.
1654	 */
1655	x86_cpuid(0x80000000, descs);
1656	lfunc = descs[0];
1657
1658	/*
1659	 * Determine L1 cache/TLB info.
1660	 */
1661	if (lfunc < 0x80000005) {
1662		/* No L1 cache info available. */
1663		return;
1664	}
1665
1666	x86_cpuid(0x80000005, descs);
1667
1668	/*
1669	 * K6-III and higher have large page TLBs.
1670	 */
1671	if ((family == 5 && model >= 9) || family >= 6) {
1672		cai = &ci->ci_cinfo[CAI_ITLB2];
1673		cai->cai_totalsize = AMD_L1_EAX_ITLB_ENTRIES(descs[0]);
1674		cai->cai_associativity = AMD_L1_EAX_ITLB_ASSOC(descs[0]);
1675		cai->cai_linesize = largepagesize;
1676
1677		cai = &ci->ci_cinfo[CAI_DTLB2];
1678		cai->cai_totalsize = AMD_L1_EAX_DTLB_ENTRIES(descs[0]);
1679		cai->cai_associativity = AMD_L1_EAX_DTLB_ASSOC(descs[0]);
1680		cai->cai_linesize = largepagesize;
1681	}
1682
1683	cai = &ci->ci_cinfo[CAI_ITLB];
1684	cai->cai_totalsize = AMD_L1_EBX_ITLB_ENTRIES(descs[1]);
1685	cai->cai_associativity = AMD_L1_EBX_ITLB_ASSOC(descs[1]);
1686	cai->cai_linesize = (4 * 1024);
1687
1688	cai = &ci->ci_cinfo[CAI_DTLB];
1689	cai->cai_totalsize = AMD_L1_EBX_DTLB_ENTRIES(descs[1]);
1690	cai->cai_associativity = AMD_L1_EBX_DTLB_ASSOC(descs[1]);
1691	cai->cai_linesize = (4 * 1024);
1692
1693	cai = &ci->ci_cinfo[CAI_DCACHE];
1694	cai->cai_totalsize = AMD_L1_ECX_DC_SIZE(descs[2]);
1695	cai->cai_associativity = AMD_L1_ECX_DC_ASSOC(descs[2]);
1696	cai->cai_linesize = AMD_L1_ECX_DC_LS(descs[2]);
1697
1698	cai = &ci->ci_cinfo[CAI_ICACHE];
1699	cai->cai_totalsize = AMD_L1_EDX_IC_SIZE(descs[3]);
1700	cai->cai_associativity = AMD_L1_EDX_IC_ASSOC(descs[3]);
1701	cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[3]);
1702
1703	/*
1704	 * Determine L2 cache/TLB info.
1705	 */
1706	if (lfunc < 0x80000006) {
1707		/* No L2 cache info available. */
1708		return;
1709	}
1710
1711	x86_cpuid(0x80000006, descs);
1712
1713	cai = &ci->ci_cinfo[CAI_L2_ITLB];
1714	cai->cai_totalsize = AMD_L2_EBX_IUTLB_ENTRIES(descs[1]);
1715	cai->cai_associativity = AMD_L2_EBX_IUTLB_ASSOC(descs[1]);
1716	cai->cai_linesize = (4 * 1024);
1717	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1718	    cai->cai_associativity);
1719	if (cp != NULL)
1720		cai->cai_associativity = cp->cai_associativity;
1721	else
1722		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1723
1724	cai = &ci->ci_cinfo[CAI_L2_ITLB2];
1725	cai->cai_totalsize = AMD_L2_EAX_IUTLB_ENTRIES(descs[0]);
1726	cai->cai_associativity = AMD_L2_EAX_IUTLB_ASSOC(descs[0]);
1727	cai->cai_linesize = largepagesize;
1728	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1729	    cai->cai_associativity);
1730	if (cp != NULL)
1731		cai->cai_associativity = cp->cai_associativity;
1732	else
1733		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1734
1735	cai = &ci->ci_cinfo[CAI_L2_DTLB];
1736	cai->cai_totalsize = AMD_L2_EBX_DTLB_ENTRIES(descs[1]);
1737	cai->cai_associativity = AMD_L2_EBX_DTLB_ASSOC(descs[1]);
1738	cai->cai_linesize = (4 * 1024);
1739	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1740	    cai->cai_associativity);
1741	if (cp != NULL)
1742		cai->cai_associativity = cp->cai_associativity;
1743	else
1744		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1745
1746	cai = &ci->ci_cinfo[CAI_L2_DTLB2];
1747	cai->cai_totalsize = AMD_L2_EAX_DTLB_ENTRIES(descs[0]);
1748	cai->cai_associativity = AMD_L2_EAX_DTLB_ASSOC(descs[0]);
1749	cai->cai_linesize = largepagesize;
1750	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1751	    cai->cai_associativity);
1752	if (cp != NULL)
1753		cai->cai_associativity = cp->cai_associativity;
1754	else
1755		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1756
1757	cai = &ci->ci_cinfo[CAI_L2CACHE];
1758	cai->cai_totalsize = AMD_L2_ECX_C_SIZE(descs[2]);
1759	cai->cai_associativity = AMD_L2_ECX_C_ASSOC(descs[2]);
1760	cai->cai_linesize = AMD_L2_ECX_C_LS(descs[2]);
1761
1762	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1763	    cai->cai_associativity);
1764	if (cp != NULL)
1765		cai->cai_associativity = cp->cai_associativity;
1766	else
1767		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1768
1769	/*
1770	 * Determine L3 cache info on AMD Family 10h and newer processors
1771	 */
1772	if (family >= 0x10) {
1773		cai = &ci->ci_cinfo[CAI_L3CACHE];
1774		cai->cai_totalsize = AMD_L3_EDX_C_SIZE(descs[3]);
1775		cai->cai_associativity = AMD_L3_EDX_C_ASSOC(descs[3]);
1776		cai->cai_linesize = AMD_L3_EDX_C_LS(descs[3]);
1777
1778		cp = cache_info_lookup(amd_cpuid_l3cache_assoc_info,
1779		    cai->cai_associativity);
1780		if (cp != NULL)
1781			cai->cai_associativity = cp->cai_associativity;
1782		else
1783			cai->cai_associativity = 0;	/* XXX Unkn/Rsvd */
1784	}
1785
1786	/*
1787	 * Determine 1GB TLB info.
1788	 */
1789	if (lfunc < 0x80000019) {
1790		/* No 1GB TLB info available. */
1791		return;
1792	}
1793
1794	x86_cpuid(0x80000019, descs);
1795
1796	cai = &ci->ci_cinfo[CAI_L1_1GBITLB];
1797	cai->cai_totalsize = AMD_L1_1GB_EAX_IUTLB_ENTRIES(descs[0]);
1798	cai->cai_associativity = AMD_L1_1GB_EAX_IUTLB_ASSOC(descs[0]);
1799	cai->cai_linesize = (1024 * 1024 * 1024);
1800	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1801	    cai->cai_associativity);
1802	if (cp != NULL)
1803		cai->cai_associativity = cp->cai_associativity;
1804	else
1805		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1806
1807	cai = &ci->ci_cinfo[CAI_L1_1GBDTLB];
1808	cai->cai_totalsize = AMD_L1_1GB_EAX_DTLB_ENTRIES(descs[0]);
1809	cai->cai_associativity = AMD_L1_1GB_EAX_DTLB_ASSOC(descs[0]);
1810	cai->cai_linesize = (1024 * 1024 * 1024);
1811	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1812	    cai->cai_associativity);
1813	if (cp != NULL)
1814		cai->cai_associativity = cp->cai_associativity;
1815	else
1816		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1817
1818	cai = &ci->ci_cinfo[CAI_L2_1GBITLB];
1819	cai->cai_totalsize = AMD_L2_1GB_EBX_IUTLB_ENTRIES(descs[1]);
1820	cai->cai_associativity = AMD_L2_1GB_EBX_IUTLB_ASSOC(descs[1]);
1821	cai->cai_linesize = (1024 * 1024 * 1024);
1822	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1823	    cai->cai_associativity);
1824	if (cp != NULL)
1825		cai->cai_associativity = cp->cai_associativity;
1826	else
1827		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1828
1829	cai = &ci->ci_cinfo[CAI_L2_1GBDTLB];
1830	cai->cai_totalsize = AMD_L2_1GB_EBX_DUTLB_ENTRIES(descs[1]);
1831	cai->cai_associativity = AMD_L2_1GB_EBX_DUTLB_ASSOC(descs[1]);
1832	cai->cai_linesize = (1024 * 1024 * 1024);
1833	cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info,
1834	    cai->cai_associativity);
1835	if (cp != NULL)
1836		cai->cai_associativity = cp->cai_associativity;
1837	else
1838		cai->cai_associativity = 0;	/* XXX Unknown/reserved */
1839}
1840
1841static void
1842via_cpu_cacheinfo(struct cpu_info *ci)
1843{
1844	struct x86_cache_info *cai;
1845	int family, model, stepping;
1846	u_int descs[4];
1847	u_int lfunc;
1848
1849	family = (ci->ci_signature >> 8) & 15;
1850	model = CPUID2MODEL(ci->ci_signature);
1851	stepping = CPUID2STEPPING(ci->ci_signature);
1852
1853	/*
1854	 * Determine the largest extended function value.
1855	 */
1856	x86_cpuid(0x80000000, descs);
1857	lfunc = descs[0];
1858
1859	/*
1860	 * Determine L1 cache/TLB info.
1861	 */
1862	if (lfunc < 0x80000005) {
1863		/* No L1 cache info available. */
1864		return;
1865	}
1866
1867	x86_cpuid(0x80000005, descs);
1868
1869	cai = &ci->ci_cinfo[CAI_ITLB];
1870	cai->cai_totalsize = VIA_L1_EBX_ITLB_ENTRIES(descs[1]);
1871	cai->cai_associativity = VIA_L1_EBX_ITLB_ASSOC(descs[1]);
1872	cai->cai_linesize = (4 * 1024);
1873
1874	cai = &ci->ci_cinfo[CAI_DTLB];
1875	cai->cai_totalsize = VIA_L1_EBX_DTLB_ENTRIES(descs[1]);
1876	cai->cai_associativity = VIA_L1_EBX_DTLB_ASSOC(descs[1]);
1877	cai->cai_linesize = (4 * 1024);
1878
1879	cai = &ci->ci_cinfo[CAI_DCACHE];
1880	cai->cai_totalsize = VIA_L1_ECX_DC_SIZE(descs[2]);
1881	cai->cai_associativity = VIA_L1_ECX_DC_ASSOC(descs[2]);
1882	cai->cai_linesize = VIA_L1_EDX_IC_LS(descs[2]);
1883	if (model == 9 && stepping == 8) {
1884		/* Erratum: stepping 8 reports 4 when it should be 2 */
1885		cai->cai_associativity = 2;
1886	}
1887
1888	cai = &ci->ci_cinfo[CAI_ICACHE];
1889	cai->cai_totalsize = VIA_L1_EDX_IC_SIZE(descs[3]);
1890	cai->cai_associativity = VIA_L1_EDX_IC_ASSOC(descs[3]);
1891	cai->cai_linesize = VIA_L1_EDX_IC_LS(descs[3]);
1892	if (model == 9 && stepping == 8) {
1893		/* Erratum: stepping 8 reports 4 when it should be 2 */
1894		cai->cai_associativity = 2;
1895	}
1896
1897	/*
1898	 * Determine L2 cache/TLB info.
1899	 */
1900	if (lfunc < 0x80000006) {
1901		/* No L2 cache info available. */
1902		return;
1903	}
1904
1905	x86_cpuid(0x80000006, descs);
1906
1907	cai = &ci->ci_cinfo[CAI_L2CACHE];
1908	if (model >= 9) {
1909		cai->cai_totalsize = VIA_L2N_ECX_C_SIZE(descs[2]);
1910		cai->cai_associativity = VIA_L2N_ECX_C_ASSOC(descs[2]);
1911		cai->cai_linesize = VIA_L2N_ECX_C_LS(descs[2]);
1912	} else {
1913		cai->cai_totalsize = VIA_L2_ECX_C_SIZE(descs[2]);
1914		cai->cai_associativity = VIA_L2_ECX_C_ASSOC(descs[2]);
1915		cai->cai_linesize = VIA_L2_ECX_C_LS(descs[2]);
1916	}
1917}
1918
1919static void
1920x86_print_cacheinfo(struct cpu_info *ci)
1921{
1922	const char *sep;
1923
1924	if (ci->ci_cinfo[CAI_ICACHE].cai_totalsize != 0 ||
1925	    ci->ci_cinfo[CAI_DCACHE].cai_totalsize != 0) {
1926		sep = print_cache_config(ci, CAI_ICACHE, "I-cache", NULL);
1927		sep = print_cache_config(ci, CAI_DCACHE, "D-cache", sep);
1928		if (sep != NULL)
1929			aprint_verbose("\n");
1930	}
1931	if (ci->ci_cinfo[CAI_L2CACHE].cai_totalsize != 0) {
1932		sep = print_cache_config(ci, CAI_L2CACHE, "L2 cache", NULL);
1933		if (sep != NULL)
1934			aprint_verbose("\n");
1935	}
1936	if (ci->ci_cinfo[CAI_L3CACHE].cai_totalsize != 0) {
1937		sep = print_cache_config(ci, CAI_L3CACHE, "L3 cache", NULL);
1938		if (sep != NULL)
1939			aprint_verbose("\n");
1940	}
1941	if (ci->ci_cinfo[CAI_ITLB].cai_totalsize != 0) {
1942		sep = print_tlb_config(ci, CAI_ITLB, "ITLB", NULL);
1943		sep = print_tlb_config(ci, CAI_ITLB2, NULL, sep);
1944		if (sep != NULL)
1945			aprint_verbose("\n");
1946	}
1947	if (ci->ci_cinfo[CAI_DTLB].cai_totalsize != 0) {
1948		sep = print_tlb_config(ci, CAI_DTLB, "DTLB", NULL);
1949		sep = print_tlb_config(ci, CAI_DTLB2, NULL, sep);
1950		if (sep != NULL)
1951			aprint_verbose("\n");
1952	}
1953	if (ci->ci_cinfo[CAI_L2_ITLB].cai_totalsize != 0) {
1954		sep = print_tlb_config(ci, CAI_L2_ITLB, "L2 ITLB", NULL);
1955		sep = print_tlb_config(ci, CAI_L2_ITLB2, NULL, sep);
1956		if (sep != NULL)
1957			aprint_verbose("\n");
1958	}
1959	if (ci->ci_cinfo[CAI_L2_DTLB].cai_totalsize != 0) {
1960		sep = print_tlb_config(ci, CAI_L2_DTLB, "L2 DTLB", NULL);
1961		sep = print_tlb_config(ci, CAI_L2_DTLB2, NULL, sep);
1962		if (sep != NULL)
1963			aprint_verbose("\n");
1964	}
1965	if (ci->ci_cinfo[CAI_L1_1GBITLB].cai_totalsize != 0) {
1966		sep = print_tlb_config(ci, CAI_L1_1GBITLB, "L1 1GB page ITLB", NULL);
1967		if (sep != NULL)
1968			aprint_verbose("\n");
1969	}
1970	if (ci->ci_cinfo[CAI_L1_1GBDTLB].cai_totalsize != 0) {
1971		sep = print_tlb_config(ci, CAI_L1_1GBDTLB, "L1 1GB page DTLB", NULL);
1972		if (sep != NULL)
1973			aprint_verbose("\n");
1974	}
1975	if (ci->ci_cinfo[CAI_L2_1GBITLB].cai_totalsize != 0) {
1976		sep = print_tlb_config(ci, CAI_L2_1GBITLB, "L2 1GB page ITLB", NULL);
1977		if (sep != NULL)
1978			aprint_verbose("\n");
1979	}
1980	if (ci->ci_cinfo[CAI_L2_1GBDTLB].cai_totalsize != 0) {
1981		sep = print_tlb_config(ci, CAI_L2_1GBDTLB, "L2 1GB page DTLB", NULL);
1982		if (sep != NULL)
1983			aprint_verbose("\n");
1984	}
1985}
1986
1987static void
1988powernow_probe(struct cpu_info *ci)
1989{
1990	uint32_t regs[4];
1991	char buf[256];
1992
1993	x86_cpuid(0x80000007, regs);
1994
1995	snprintb(buf, sizeof(buf), CPUID_APM_FLAGS, regs[3]);
1996	aprint_normal_dev(ci->ci_dev, "AMD Power Management features: %s\n",
1997	    buf);
1998}
1999