xref: /titanic_53/usr/src/uts/i86pc/os/cpuid.c (revision 7417cfdecea1902cef03c0d61a72df97d945925d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ee88d2b9Skchow  * Common Development and Distribution License (the "License").
6ee88d2b9Skchow  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
226e5580c9SFrank Van Der Linden  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
24cef70d2cSBill Holler /*
25cef70d2cSBill Holler  * Copyright (c) 2009, Intel Corporation.
26cef70d2cSBill Holler  * All rights reserved.
27cef70d2cSBill Holler  */
288031591dSSrihari Venkatesan /*
298031591dSSrihari Venkatesan  * Portions Copyright 2009 Advanced Micro Devices, Inc.
308031591dSSrihari Venkatesan  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Various routines to handle identification
347c478bd9Sstevel@tonic-gate  * and classification of x86 processors.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
397c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h>
407c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
417c478bd9Sstevel@tonic-gate #include <sys/systm.h>
427c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
437c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
457c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
467c478bd9Sstevel@tonic-gate #include <sys/processor.h>
475b8a6efeSbholler #include <sys/sysmacros.h>
48fb2f18f8Sesaxe #include <sys/pg.h>
497c478bd9Sstevel@tonic-gate #include <sys/fp.h>
507c478bd9Sstevel@tonic-gate #include <sys/controlregs.h>
517c478bd9Sstevel@tonic-gate #include <sys/auxv_386.h>
527c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
537c478bd9Sstevel@tonic-gate #include <sys/memnode.h>
548031591dSSrihari Venkatesan #include <sys/pci_cfgspace.h>
557c478bd9Sstevel@tonic-gate 
56e4b86885SCheng Sean Ye #ifdef __xpv
57e4b86885SCheng Sean Ye #include <sys/hypervisor.h>
58e774b42bSBill Holler #else
59e774b42bSBill Holler #include <sys/ontrap.h>
60e4b86885SCheng Sean Ye #endif
61e4b86885SCheng Sean Ye 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * Pass 0 of cpuid feature analysis happens in locore. It contains special code
647c478bd9Sstevel@tonic-gate  * to recognize Cyrix processors that are not cpuid-compliant, and to deal with
657c478bd9Sstevel@tonic-gate  * them accordingly. For most modern processors, feature detection occurs here
667c478bd9Sstevel@tonic-gate  * in pass 1.
677c478bd9Sstevel@tonic-gate  *
687c478bd9Sstevel@tonic-gate  * Pass 1 of cpuid feature analysis happens just at the beginning of mlsetup()
697c478bd9Sstevel@tonic-gate  * for the boot CPU and does the basic analysis that the early kernel needs.
707417cfdeSKuriakose Kuruvilla  * x86_featureset is set based on the return value of cpuid_pass1() of the boot
717c478bd9Sstevel@tonic-gate  * CPU.
727c478bd9Sstevel@tonic-gate  *
737c478bd9Sstevel@tonic-gate  * Pass 1 includes:
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  *	o Determining vendor/model/family/stepping and setting x86_type and
767c478bd9Sstevel@tonic-gate  *	  x86_vendor accordingly.
777c478bd9Sstevel@tonic-gate  *	o Processing the feature flags returned by the cpuid instruction while
787c478bd9Sstevel@tonic-gate  *	  applying any workarounds or tricks for the specific processor.
797c478bd9Sstevel@tonic-gate  *	o Mapping the feature flags into Solaris feature bits (X86_*).
807c478bd9Sstevel@tonic-gate  *	o Processing extended feature flags if supported by the processor,
817c478bd9Sstevel@tonic-gate  *	  again while applying specific processor knowledge.
827c478bd9Sstevel@tonic-gate  *	o Determining the CMT characteristics of the system.
837c478bd9Sstevel@tonic-gate  *
847c478bd9Sstevel@tonic-gate  * Pass 1 is done on non-boot CPUs during their initialization and the results
857c478bd9Sstevel@tonic-gate  * are used only as a meager attempt at ensuring that all processors within the
867c478bd9Sstevel@tonic-gate  * system support the same features.
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * Pass 2 of cpuid feature analysis happens just at the beginning
897c478bd9Sstevel@tonic-gate  * of startup().  It just copies in and corrects the remainder
907c478bd9Sstevel@tonic-gate  * of the cpuid data we depend on: standard cpuid functions that we didn't
917c478bd9Sstevel@tonic-gate  * need for pass1 feature analysis, and extended cpuid functions beyond the
927c478bd9Sstevel@tonic-gate  * simple feature processing done in pass1.
937c478bd9Sstevel@tonic-gate  *
947c478bd9Sstevel@tonic-gate  * Pass 3 of cpuid analysis is invoked after basic kernel services; in
957c478bd9Sstevel@tonic-gate  * particular kernel memory allocation has been made available. It creates a
967c478bd9Sstevel@tonic-gate  * readable brand string based on the data collected in the first two passes.
977c478bd9Sstevel@tonic-gate  *
987c478bd9Sstevel@tonic-gate  * Pass 4 of cpuid analysis is invoked after post_startup() when all
997c478bd9Sstevel@tonic-gate  * the support infrastructure for various hardware features has been
1007c478bd9Sstevel@tonic-gate  * initialized. It determines which processor features will be reported
1017c478bd9Sstevel@tonic-gate  * to userland via the aux vector.
1027c478bd9Sstevel@tonic-gate  *
1037c478bd9Sstevel@tonic-gate  * All passes are executed on all CPUs, but only the boot CPU determines what
1047c478bd9Sstevel@tonic-gate  * features the kernel will use.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Much of the worst junk in this file is for the support of processors
1077c478bd9Sstevel@tonic-gate  * that didn't really implement the cpuid instruction properly.
1087c478bd9Sstevel@tonic-gate  *
1097c478bd9Sstevel@tonic-gate  * NOTE: The accessor functions (cpuid_get*) are aware of, and ASSERT upon,
1107c478bd9Sstevel@tonic-gate  * the pass numbers.  Accordingly, changes to the pass code may require changes
1117c478bd9Sstevel@tonic-gate  * to the accessor code.
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate uint_t x86_vendor = X86_VENDOR_IntelClone;
1157c478bd9Sstevel@tonic-gate uint_t x86_type = X86_TYPE_OTHER;
11686c1f4dcSVikram Hegde uint_t x86_clflush_size = 0;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4046376;
1197c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4064495;
1207c478bd9Sstevel@tonic-gate 
1217417cfdeSKuriakose Kuruvilla #define	NUM_X86_FEATURES	33
1227417cfdeSKuriakose Kuruvilla void    *x86_featureset;
1237417cfdeSKuriakose Kuruvilla ulong_t x86_featureset0[BT_SIZEOFMAP(NUM_X86_FEATURES)];
1247417cfdeSKuriakose Kuruvilla 
1257417cfdeSKuriakose Kuruvilla char *x86_feature_names[NUM_X86_FEATURES] = {
1267417cfdeSKuriakose Kuruvilla 	"lgpg",
1277417cfdeSKuriakose Kuruvilla 	"tsc",
1287417cfdeSKuriakose Kuruvilla 	"msr",
1297417cfdeSKuriakose Kuruvilla 	"mtrr",
1307417cfdeSKuriakose Kuruvilla 	"pge",
1317417cfdeSKuriakose Kuruvilla 	"de",
1327417cfdeSKuriakose Kuruvilla 	"cmov",
1337417cfdeSKuriakose Kuruvilla 	"mmx",
1347417cfdeSKuriakose Kuruvilla 	"mca",
1357417cfdeSKuriakose Kuruvilla 	"pae",
1367417cfdeSKuriakose Kuruvilla 	"cv8",
1377417cfdeSKuriakose Kuruvilla 	"pat",
1387417cfdeSKuriakose Kuruvilla 	"sep",
1397417cfdeSKuriakose Kuruvilla 	"sse",
1407417cfdeSKuriakose Kuruvilla 	"sse2",
1417417cfdeSKuriakose Kuruvilla 	"htt",
1427417cfdeSKuriakose Kuruvilla 	"asysc",
1437417cfdeSKuriakose Kuruvilla 	"nx",
1447417cfdeSKuriakose Kuruvilla 	"sse3",
1457417cfdeSKuriakose Kuruvilla 	"cx16",
1467417cfdeSKuriakose Kuruvilla 	"cmp",
1477417cfdeSKuriakose Kuruvilla 	"tscp",
1487417cfdeSKuriakose Kuruvilla 	"mwait",
1497417cfdeSKuriakose Kuruvilla 	"sse4a",
1507417cfdeSKuriakose Kuruvilla 	"cpuid",
1517417cfdeSKuriakose Kuruvilla 	"ssse3",
1527417cfdeSKuriakose Kuruvilla 	"sse4_1",
1537417cfdeSKuriakose Kuruvilla 	"sse4_2",
1547417cfdeSKuriakose Kuruvilla 	"1gpg",
1557417cfdeSKuriakose Kuruvilla 	"clfsh",
1567417cfdeSKuriakose Kuruvilla 	"64",
1577417cfdeSKuriakose Kuruvilla 	"aes",
1587417cfdeSKuriakose Kuruvilla 	"pclmulqdq" };
1597417cfdeSKuriakose Kuruvilla 
1607417cfdeSKuriakose Kuruvilla static void *
1617417cfdeSKuriakose Kuruvilla init_x86_featureset(void)
1627417cfdeSKuriakose Kuruvilla {
1637417cfdeSKuriakose Kuruvilla 	return (kmem_zalloc(BT_SIZEOFMAP(NUM_X86_FEATURES), KM_SLEEP));
1647417cfdeSKuriakose Kuruvilla }
1657417cfdeSKuriakose Kuruvilla 
1667417cfdeSKuriakose Kuruvilla void
1677417cfdeSKuriakose Kuruvilla free_x86_featureset(void *featureset)
1687417cfdeSKuriakose Kuruvilla {
1697417cfdeSKuriakose Kuruvilla 	kmem_free(featureset, BT_SIZEOFMAP(NUM_X86_FEATURES));
1707417cfdeSKuriakose Kuruvilla }
1717417cfdeSKuriakose Kuruvilla 
1727417cfdeSKuriakose Kuruvilla boolean_t
1737417cfdeSKuriakose Kuruvilla is_x86_feature(void *featureset, uint_t feature)
1747417cfdeSKuriakose Kuruvilla {
1757417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1767417cfdeSKuriakose Kuruvilla 	return (BT_TEST((ulong_t *)featureset, feature));
1777417cfdeSKuriakose Kuruvilla }
1787417cfdeSKuriakose Kuruvilla 
1797417cfdeSKuriakose Kuruvilla void
1807417cfdeSKuriakose Kuruvilla add_x86_feature(void *featureset, uint_t feature)
1817417cfdeSKuriakose Kuruvilla {
1827417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1837417cfdeSKuriakose Kuruvilla 	BT_SET((ulong_t *)featureset, feature);
1847417cfdeSKuriakose Kuruvilla }
1857417cfdeSKuriakose Kuruvilla 
1867417cfdeSKuriakose Kuruvilla void
1877417cfdeSKuriakose Kuruvilla remove_x86_feature(void *featureset, uint_t feature)
1887417cfdeSKuriakose Kuruvilla {
1897417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1907417cfdeSKuriakose Kuruvilla 	BT_CLEAR((ulong_t *)featureset, feature);
1917417cfdeSKuriakose Kuruvilla }
1927417cfdeSKuriakose Kuruvilla 
1937417cfdeSKuriakose Kuruvilla boolean_t
1947417cfdeSKuriakose Kuruvilla compare_x86_featureset(void *setA, void *setB)
1957417cfdeSKuriakose Kuruvilla {
1967417cfdeSKuriakose Kuruvilla 	/*
1977417cfdeSKuriakose Kuruvilla 	 * We assume that the unused bits of the bitmap are always zero.
1987417cfdeSKuriakose Kuruvilla 	 */
1997417cfdeSKuriakose Kuruvilla 	if (memcmp(setA, setB, BT_SIZEOFMAP(NUM_X86_FEATURES)) == 0) {
2007417cfdeSKuriakose Kuruvilla 		return (B_TRUE);
2017417cfdeSKuriakose Kuruvilla 	} else {
2027417cfdeSKuriakose Kuruvilla 		return (B_FALSE);
2037417cfdeSKuriakose Kuruvilla 	}
2047417cfdeSKuriakose Kuruvilla }
2057417cfdeSKuriakose Kuruvilla 
2067417cfdeSKuriakose Kuruvilla void
2077417cfdeSKuriakose Kuruvilla print_x86_featureset(void *featureset)
2087417cfdeSKuriakose Kuruvilla {
2097417cfdeSKuriakose Kuruvilla 	uint_t i;
2107417cfdeSKuriakose Kuruvilla 
2117417cfdeSKuriakose Kuruvilla 	for (i = 0; i < NUM_X86_FEATURES; i++) {
2127417cfdeSKuriakose Kuruvilla 		if (is_x86_feature(featureset, i)) {
2137417cfdeSKuriakose Kuruvilla 			cmn_err(CE_CONT, "?x86_feature: %s\n",
2147417cfdeSKuriakose Kuruvilla 			    x86_feature_names[i]);
2157417cfdeSKuriakose Kuruvilla 		}
2167417cfdeSKuriakose Kuruvilla 	}
2177417cfdeSKuriakose Kuruvilla }
2187417cfdeSKuriakose Kuruvilla 
2197c478bd9Sstevel@tonic-gate uint_t enable486;
2207997e108SSurya Prakki /*
221b9bfdccdSStuart Maybee  * This is set to platform type Solaris is running on.
2227997e108SSurya Prakki  */
223349b53ddSStuart Maybee static int platform_type = -1;
224349b53ddSStuart Maybee 
225349b53ddSStuart Maybee #if !defined(__xpv)
226349b53ddSStuart Maybee /*
227349b53ddSStuart Maybee  * Variable to patch if hypervisor platform detection needs to be
228349b53ddSStuart Maybee  * disabled (e.g. platform_type will always be HW_NATIVE if this is 0).
229349b53ddSStuart Maybee  */
230349b53ddSStuart Maybee int enable_platform_detection = 1;
231349b53ddSStuart Maybee #endif
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /*
234f98fbcecSbholler  * monitor/mwait info.
2355b8a6efeSbholler  *
2365b8a6efeSbholler  * size_actual and buf_actual are the real address and size allocated to get
2375b8a6efeSbholler  * proper mwait_buf alignement.  buf_actual and size_actual should be passed
2385b8a6efeSbholler  * to kmem_free().  Currently kmem_alloc() and mwait happen to both use
2395b8a6efeSbholler  * processor cache-line alignment, but this is not guarantied in the furture.
240f98fbcecSbholler  */
241f98fbcecSbholler struct mwait_info {
242f98fbcecSbholler 	size_t		mon_min;	/* min size to avoid missed wakeups */
243f98fbcecSbholler 	size_t		mon_max;	/* size to avoid false wakeups */
2445b8a6efeSbholler 	size_t		size_actual;	/* size actually allocated */
2455b8a6efeSbholler 	void		*buf_actual;	/* memory actually allocated */
246f98fbcecSbholler 	uint32_t	support;	/* processor support of monitor/mwait */
247f98fbcecSbholler };
248f98fbcecSbholler 
249f98fbcecSbholler /*
2507c478bd9Sstevel@tonic-gate  * These constants determine how many of the elements of the
2517c478bd9Sstevel@tonic-gate  * cpuid we cache in the cpuid_info data structure; the
2527c478bd9Sstevel@tonic-gate  * remaining elements are accessible via the cpuid instruction.
2537c478bd9Sstevel@tonic-gate  */
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate #define	NMAX_CPI_STD	6		/* eax = 0 .. 5 */
2568031591dSSrihari Venkatesan #define	NMAX_CPI_EXTD	0x1c		/* eax = 0x80000000 .. 0x8000001b */
2578031591dSSrihari Venkatesan 
2588031591dSSrihari Venkatesan /*
2598031591dSSrihari Venkatesan  * Some terminology needs to be explained:
2608031591dSSrihari Venkatesan  *  - Socket: Something that can be plugged into a motherboard.
2618031591dSSrihari Venkatesan  *  - Package: Same as socket
2628031591dSSrihari Venkatesan  *  - Chip: Same as socket. Note that AMD's documentation uses term "chip"
2638031591dSSrihari Venkatesan  *    differently: there, chip is the same as processor node (below)
2648031591dSSrihari Venkatesan  *  - Processor node: Some AMD processors have more than one
2658031591dSSrihari Venkatesan  *    "subprocessor" embedded in a package. These subprocessors (nodes)
2668031591dSSrihari Venkatesan  *    are fully-functional processors themselves with cores, caches,
2678031591dSSrihari Venkatesan  *    memory controllers, PCI configuration spaces. They are connected
2688031591dSSrihari Venkatesan  *    inside the package with Hypertransport links. On single-node
2698031591dSSrihari Venkatesan  *    processors, processor node is equivalent to chip/socket/package.
2708031591dSSrihari Venkatesan  */
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate struct cpuid_info {
2737c478bd9Sstevel@tonic-gate 	uint_t cpi_pass;		/* last pass completed */
2747c478bd9Sstevel@tonic-gate 	/*
2757c478bd9Sstevel@tonic-gate 	 * standard function information
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	uint_t cpi_maxeax;		/* fn 0: %eax */
2787c478bd9Sstevel@tonic-gate 	char cpi_vendorstr[13];		/* fn 0: %ebx:%ecx:%edx */
2797c478bd9Sstevel@tonic-gate 	uint_t cpi_vendor;		/* enum of cpi_vendorstr */
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	uint_t cpi_family;		/* fn 1: extended family */
2827c478bd9Sstevel@tonic-gate 	uint_t cpi_model;		/* fn 1: extended model */
2837c478bd9Sstevel@tonic-gate 	uint_t cpi_step;		/* fn 1: stepping */
2848031591dSSrihari Venkatesan 	chipid_t cpi_chipid;		/* fn 1: %ebx:  Intel: chip # */
2858031591dSSrihari Venkatesan 					/*		AMD: package/socket # */
2867c478bd9Sstevel@tonic-gate 	uint_t cpi_brandid;		/* fn 1: %ebx: brand ID */
2877c478bd9Sstevel@tonic-gate 	int cpi_clogid;			/* fn 1: %ebx: thread # */
2888949bcd6Sandrei 	uint_t cpi_ncpu_per_chip;	/* fn 1: %ebx: logical cpu count */
2897c478bd9Sstevel@tonic-gate 	uint8_t cpi_cacheinfo[16];	/* fn 2: intel-style cache desc */
2907c478bd9Sstevel@tonic-gate 	uint_t cpi_ncache;		/* fn 2: number of elements */
291d129bde2Sesaxe 	uint_t cpi_ncpu_shr_last_cache;	/* fn 4: %eax: ncpus sharing cache */
292d129bde2Sesaxe 	id_t cpi_last_lvl_cacheid;	/* fn 4: %eax: derived cache id */
293d129bde2Sesaxe 	uint_t cpi_std_4_size;		/* fn 4: number of fn 4 elements */
294d129bde2Sesaxe 	struct cpuid_regs **cpi_std_4;	/* fn 4: %ecx == 0 .. fn4_size */
2958949bcd6Sandrei 	struct cpuid_regs cpi_std[NMAX_CPI_STD];	/* 0 .. 5 */
2967c478bd9Sstevel@tonic-gate 	/*
2977c478bd9Sstevel@tonic-gate 	 * extended function information
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate 	uint_t cpi_xmaxeax;		/* fn 0x80000000: %eax */
3007c478bd9Sstevel@tonic-gate 	char cpi_brandstr[49];		/* fn 0x8000000[234] */
3017c478bd9Sstevel@tonic-gate 	uint8_t cpi_pabits;		/* fn 0x80000006: %eax */
3027c478bd9Sstevel@tonic-gate 	uint8_t	cpi_vabits;		/* fn 0x80000006: %eax */
3038031591dSSrihari Venkatesan 	struct	cpuid_regs cpi_extd[NMAX_CPI_EXTD];	/* 0x800000XX */
3048031591dSSrihari Venkatesan 
30510569901Sgavinm 	id_t cpi_coreid;		/* same coreid => strands share core */
30610569901Sgavinm 	int cpi_pkgcoreid;		/* core number within single package */
3078949bcd6Sandrei 	uint_t cpi_ncore_per_chip;	/* AMD: fn 0x80000008: %ecx[7-0] */
3088949bcd6Sandrei 					/* Intel: fn 4: %eax[31-26] */
3097c478bd9Sstevel@tonic-gate 	/*
3107c478bd9Sstevel@tonic-gate 	 * supported feature information
3117c478bd9Sstevel@tonic-gate 	 */
312ae115bc7Smrj 	uint32_t cpi_support[5];
3137c478bd9Sstevel@tonic-gate #define	STD_EDX_FEATURES	0
3147c478bd9Sstevel@tonic-gate #define	AMD_EDX_FEATURES	1
3157c478bd9Sstevel@tonic-gate #define	TM_EDX_FEATURES		2
3167c478bd9Sstevel@tonic-gate #define	STD_ECX_FEATURES	3
317ae115bc7Smrj #define	AMD_ECX_FEATURES	4
3188a40a695Sgavinm 	/*
3198a40a695Sgavinm 	 * Synthesized information, where known.
3208a40a695Sgavinm 	 */
3218a40a695Sgavinm 	uint32_t cpi_chiprev;		/* See X86_CHIPREV_* in x86_archext.h */
3228a40a695Sgavinm 	const char *cpi_chiprevstr;	/* May be NULL if chiprev unknown */
3238a40a695Sgavinm 	uint32_t cpi_socket;		/* Chip package/socket type */
324f98fbcecSbholler 
325f98fbcecSbholler 	struct mwait_info cpi_mwait;	/* fn 5: monitor/mwait info */
326b6917abeSmishra 	uint32_t cpi_apicid;
3278031591dSSrihari Venkatesan 	uint_t cpi_procnodeid;		/* AMD: nodeID on HT, Intel: chipid */
3288031591dSSrihari Venkatesan 	uint_t cpi_procnodes_per_pkg;	/* AMD: # of nodes in the package */
3298031591dSSrihari Venkatesan 					/* Intel: 1 */
3307c478bd9Sstevel@tonic-gate };
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate static struct cpuid_info cpuid_info0;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * These bit fields are defined by the Intel Application Note AP-485
3377c478bd9Sstevel@tonic-gate  * "Intel Processor Identification and the CPUID Instruction"
3387c478bd9Sstevel@tonic-gate  */
3397c478bd9Sstevel@tonic-gate #define	CPI_FAMILY_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 27, 20)
3407c478bd9Sstevel@tonic-gate #define	CPI_MODEL_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 19, 16)
3417c478bd9Sstevel@tonic-gate #define	CPI_TYPE(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 13, 12)
3427c478bd9Sstevel@tonic-gate #define	CPI_FAMILY(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 11, 8)
3437c478bd9Sstevel@tonic-gate #define	CPI_STEP(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 3, 0)
3447c478bd9Sstevel@tonic-gate #define	CPI_MODEL(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 7, 4)
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_EDX(cpi)		((cpi)->cpi_std[1].cp_edx)
3477c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_ECX(cpi)		((cpi)->cpi_std[1].cp_ecx)
3487c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_EDX(cpi)	((cpi)->cpi_extd[1].cp_edx)
3497c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_ECX(cpi)	((cpi)->cpi_extd[1].cp_ecx)
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate #define	CPI_BRANDID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 7, 0)
3527c478bd9Sstevel@tonic-gate #define	CPI_CHUNKS(cpi)		BITX((cpi)->cpi_std[1].cp_ebx, 15, 7)
3537c478bd9Sstevel@tonic-gate #define	CPI_CPU_COUNT(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 23, 16)
3547c478bd9Sstevel@tonic-gate #define	CPI_APIC_ID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 31, 24)
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate #define	CPI_MAXEAX_MAX		0x100		/* sanity control */
3577c478bd9Sstevel@tonic-gate #define	CPI_XMAXEAX_MAX		0x80000100
358d129bde2Sesaxe #define	CPI_FN4_ECX_MAX		0x20		/* sanity: max fn 4 levels */
359b6917abeSmishra #define	CPI_FNB_ECX_MAX		0x20		/* sanity: max fn B levels */
360d129bde2Sesaxe 
361d129bde2Sesaxe /*
362d129bde2Sesaxe  * Function 4 (Deterministic Cache Parameters) macros
363d129bde2Sesaxe  * Defined by Intel Application Note AP-485
364d129bde2Sesaxe  */
365d129bde2Sesaxe #define	CPI_NUM_CORES(regs)		BITX((regs)->cp_eax, 31, 26)
366d129bde2Sesaxe #define	CPI_NTHR_SHR_CACHE(regs)	BITX((regs)->cp_eax, 25, 14)
367d129bde2Sesaxe #define	CPI_FULL_ASSOC_CACHE(regs)	BITX((regs)->cp_eax, 9, 9)
368d129bde2Sesaxe #define	CPI_SELF_INIT_CACHE(regs)	BITX((regs)->cp_eax, 8, 8)
369d129bde2Sesaxe #define	CPI_CACHE_LVL(regs)		BITX((regs)->cp_eax, 7, 5)
370d129bde2Sesaxe #define	CPI_CACHE_TYPE(regs)		BITX((regs)->cp_eax, 4, 0)
371b6917abeSmishra #define	CPI_CPU_LEVEL_TYPE(regs)	BITX((regs)->cp_ecx, 15, 8)
372d129bde2Sesaxe 
373d129bde2Sesaxe #define	CPI_CACHE_WAYS(regs)		BITX((regs)->cp_ebx, 31, 22)
374d129bde2Sesaxe #define	CPI_CACHE_PARTS(regs)		BITX((regs)->cp_ebx, 21, 12)
375d129bde2Sesaxe #define	CPI_CACHE_COH_LN_SZ(regs)	BITX((regs)->cp_ebx, 11, 0)
376d129bde2Sesaxe 
377d129bde2Sesaxe #define	CPI_CACHE_SETS(regs)		BITX((regs)->cp_ecx, 31, 0)
378d129bde2Sesaxe 
379d129bde2Sesaxe #define	CPI_PREFCH_STRIDE(regs)		BITX((regs)->cp_edx, 9, 0)
380d129bde2Sesaxe 
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
3835ff02082Sdmick  * A couple of shorthand macros to identify "later" P6-family chips
3845ff02082Sdmick  * like the Pentium M and Core.  First, the "older" P6-based stuff
3855ff02082Sdmick  * (loosely defined as "pre-Pentium-4"):
3865ff02082Sdmick  * P6, PII, Mobile PII, PII Xeon, PIII, Mobile PIII, PIII Xeon
3875ff02082Sdmick  */
3885ff02082Sdmick 
3895ff02082Sdmick #define	IS_LEGACY_P6(cpi) (			\
3905ff02082Sdmick 	cpi->cpi_family == 6 && 		\
3915ff02082Sdmick 		(cpi->cpi_model == 1 ||		\
3925ff02082Sdmick 		cpi->cpi_model == 3 ||		\
3935ff02082Sdmick 		cpi->cpi_model == 5 ||		\
3945ff02082Sdmick 		cpi->cpi_model == 6 ||		\
3955ff02082Sdmick 		cpi->cpi_model == 7 ||		\
3965ff02082Sdmick 		cpi->cpi_model == 8 ||		\
3975ff02082Sdmick 		cpi->cpi_model == 0xA ||	\
3985ff02082Sdmick 		cpi->cpi_model == 0xB)		\
3995ff02082Sdmick )
4005ff02082Sdmick 
4015ff02082Sdmick /* A "new F6" is everything with family 6 that's not the above */
4025ff02082Sdmick #define	IS_NEW_F6(cpi) ((cpi->cpi_family == 6) && !IS_LEGACY_P6(cpi))
4035ff02082Sdmick 
404bf91205bSksadhukh /* Extended family/model support */
405bf91205bSksadhukh #define	IS_EXTENDED_MODEL_INTEL(cpi) (cpi->cpi_family == 0x6 || \
406bf91205bSksadhukh 	cpi->cpi_family >= 0xf)
407bf91205bSksadhukh 
4085ff02082Sdmick /*
409f98fbcecSbholler  * Info for monitor/mwait idle loop.
410f98fbcecSbholler  *
411f98fbcecSbholler  * See cpuid section of "Intel 64 and IA-32 Architectures Software Developer's
412f98fbcecSbholler  * Manual Volume 2A: Instruction Set Reference, A-M" #25366-022US, November
413f98fbcecSbholler  * 2006.
414f98fbcecSbholler  * See MONITOR/MWAIT section of "AMD64 Architecture Programmer's Manual
415f98fbcecSbholler  * Documentation Updates" #33633, Rev 2.05, December 2006.
416f98fbcecSbholler  */
417f98fbcecSbholler #define	MWAIT_SUPPORT		(0x00000001)	/* mwait supported */
418f98fbcecSbholler #define	MWAIT_EXTENSIONS	(0x00000002)	/* extenstion supported */
419f98fbcecSbholler #define	MWAIT_ECX_INT_ENABLE	(0x00000004)	/* ecx 1 extension supported */
420f98fbcecSbholler #define	MWAIT_SUPPORTED(cpi)	((cpi)->cpi_std[1].cp_ecx & CPUID_INTC_ECX_MON)
421f98fbcecSbholler #define	MWAIT_INT_ENABLE(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x2)
422f98fbcecSbholler #define	MWAIT_EXTENSION(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x1)
423f98fbcecSbholler #define	MWAIT_SIZE_MIN(cpi)	BITX((cpi)->cpi_std[5].cp_eax, 15, 0)
424f98fbcecSbholler #define	MWAIT_SIZE_MAX(cpi)	BITX((cpi)->cpi_std[5].cp_ebx, 15, 0)
425f98fbcecSbholler /*
426f98fbcecSbholler  * Number of sub-cstates for a given c-state.
427f98fbcecSbholler  */
428f98fbcecSbholler #define	MWAIT_NUM_SUBC_STATES(cpi, c_state)			\
429f98fbcecSbholler 	BITX((cpi)->cpi_std[5].cp_edx, c_state + 3, c_state)
430f98fbcecSbholler 
4318a40a695Sgavinm /*
432e4b86885SCheng Sean Ye  * Functions we consune from cpuid_subr.c;  don't publish these in a header
433e4b86885SCheng Sean Ye  * file to try and keep people using the expected cpuid_* interfaces.
4348a40a695Sgavinm  */
435e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t);
43689e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t);
437e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t);
438e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t);
439e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *);
4408a40a695Sgavinm 
4418a40a695Sgavinm /*
442ae115bc7Smrj  * Apply up various platform-dependent restrictions where the
443ae115bc7Smrj  * underlying platform restrictions mean the CPU can be marked
444ae115bc7Smrj  * as less capable than its cpuid instruction would imply.
445ae115bc7Smrj  */
446843e1988Sjohnlev #if defined(__xpv)
447843e1988Sjohnlev static void
448843e1988Sjohnlev platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp)
449843e1988Sjohnlev {
450843e1988Sjohnlev 	switch (eax) {
451e4b86885SCheng Sean Ye 	case 1: {
452e4b86885SCheng Sean Ye 		uint32_t mcamask = DOMAIN_IS_INITDOMAIN(xen_info) ?
453e4b86885SCheng Sean Ye 		    0 : CPUID_INTC_EDX_MCA;
454843e1988Sjohnlev 		cp->cp_edx &=
455e4b86885SCheng Sean Ye 		    ~(mcamask |
456e4b86885SCheng Sean Ye 		    CPUID_INTC_EDX_PSE |
457843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
458843e1988Sjohnlev 		    CPUID_INTC_EDX_SEP | CPUID_INTC_EDX_MTRR |
459843e1988Sjohnlev 		    CPUID_INTC_EDX_PGE | CPUID_INTC_EDX_PAT |
460843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
461843e1988Sjohnlev 		    CPUID_INTC_EDX_PSE36 | CPUID_INTC_EDX_HTT);
462843e1988Sjohnlev 		break;
463e4b86885SCheng Sean Ye 	}
464ae115bc7Smrj 
465843e1988Sjohnlev 	case 0x80000001:
466843e1988Sjohnlev 		cp->cp_edx &=
467843e1988Sjohnlev 		    ~(CPUID_AMD_EDX_PSE |
468843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
469843e1988Sjohnlev 		    CPUID_AMD_EDX_MTRR | CPUID_AMD_EDX_PGE |
470843e1988Sjohnlev 		    CPUID_AMD_EDX_PAT | CPUID_AMD_EDX_PSE36 |
471843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
472843e1988Sjohnlev 		    CPUID_AMD_EDX_TSCP);
473843e1988Sjohnlev 		cp->cp_ecx &= ~CPUID_AMD_ECX_CMP_LGCY;
474843e1988Sjohnlev 		break;
475843e1988Sjohnlev 	default:
476843e1988Sjohnlev 		break;
477843e1988Sjohnlev 	}
478843e1988Sjohnlev 
479843e1988Sjohnlev 	switch (vendor) {
480843e1988Sjohnlev 	case X86_VENDOR_Intel:
481843e1988Sjohnlev 		switch (eax) {
482843e1988Sjohnlev 		case 4:
483843e1988Sjohnlev 			/*
484843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
485843e1988Sjohnlev 			 */
486843e1988Sjohnlev 			cp->cp_eax &= 0x03fffffff;
487843e1988Sjohnlev 			break;
488843e1988Sjohnlev 		default:
489843e1988Sjohnlev 			break;
490843e1988Sjohnlev 		}
491843e1988Sjohnlev 		break;
492843e1988Sjohnlev 	case X86_VENDOR_AMD:
493843e1988Sjohnlev 		switch (eax) {
4942ef50f01SJoe Bonasera 
4952ef50f01SJoe Bonasera 		case 0x80000001:
4962ef50f01SJoe Bonasera 			cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D;
4972ef50f01SJoe Bonasera 			break;
4982ef50f01SJoe Bonasera 
499843e1988Sjohnlev 		case 0x80000008:
500843e1988Sjohnlev 			/*
501843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
502843e1988Sjohnlev 			 */
503843e1988Sjohnlev 			cp->cp_ecx &= 0xffffff00;
504843e1988Sjohnlev 			break;
505843e1988Sjohnlev 		default:
506843e1988Sjohnlev 			break;
507843e1988Sjohnlev 		}
508843e1988Sjohnlev 		break;
509843e1988Sjohnlev 	default:
510843e1988Sjohnlev 		break;
511843e1988Sjohnlev 	}
512843e1988Sjohnlev }
513843e1988Sjohnlev #else
514ae115bc7Smrj #define	platform_cpuid_mangle(vendor, eax, cp)	/* nothing */
515843e1988Sjohnlev #endif
516ae115bc7Smrj 
517ae115bc7Smrj /*
5187c478bd9Sstevel@tonic-gate  *  Some undocumented ways of patching the results of the cpuid
5197c478bd9Sstevel@tonic-gate  *  instruction to permit running Solaris 10 on future cpus that
5207c478bd9Sstevel@tonic-gate  *  we don't currently support.  Could be set to non-zero values
5217c478bd9Sstevel@tonic-gate  *  via settings in eeprom.
5227c478bd9Sstevel@tonic-gate  */
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_include;
5257c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_exclude;
5267c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_include;
5277c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_exclude;
5287c478bd9Sstevel@tonic-gate 
529a3114836SGerry Liu /*
530a3114836SGerry Liu  * Allocate space for mcpu_cpi in the machcpu structure for all non-boot CPUs.
531a3114836SGerry Liu  */
532ae115bc7Smrj void
533ae115bc7Smrj cpuid_alloc_space(cpu_t *cpu)
534ae115bc7Smrj {
535ae115bc7Smrj 	/*
536ae115bc7Smrj 	 * By convention, cpu0 is the boot cpu, which is set up
537ae115bc7Smrj 	 * before memory allocation is available.  All other cpus get
538ae115bc7Smrj 	 * their cpuid_info struct allocated here.
539ae115bc7Smrj 	 */
540ae115bc7Smrj 	ASSERT(cpu->cpu_id != 0);
541a3114836SGerry Liu 	ASSERT(cpu->cpu_m.mcpu_cpi == NULL);
542ae115bc7Smrj 	cpu->cpu_m.mcpu_cpi =
543ae115bc7Smrj 	    kmem_zalloc(sizeof (*cpu->cpu_m.mcpu_cpi), KM_SLEEP);
544ae115bc7Smrj }
545ae115bc7Smrj 
546ae115bc7Smrj void
547ae115bc7Smrj cpuid_free_space(cpu_t *cpu)
548ae115bc7Smrj {
549d129bde2Sesaxe 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
550d129bde2Sesaxe 	int i;
551d129bde2Sesaxe 
552a3114836SGerry Liu 	ASSERT(cpi != NULL);
553a3114836SGerry Liu 	ASSERT(cpi != &cpuid_info0);
554d129bde2Sesaxe 
555d129bde2Sesaxe 	/*
556d129bde2Sesaxe 	 * Free up any function 4 related dynamic storage
557d129bde2Sesaxe 	 */
558d129bde2Sesaxe 	for (i = 1; i < cpi->cpi_std_4_size; i++)
559d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4[i], sizeof (struct cpuid_regs));
560d129bde2Sesaxe 	if (cpi->cpi_std_4_size > 0)
561d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4,
562d129bde2Sesaxe 		    cpi->cpi_std_4_size * sizeof (struct cpuid_regs *));
563d129bde2Sesaxe 
564a3114836SGerry Liu 	kmem_free(cpi, sizeof (*cpi));
565a3114836SGerry Liu 	cpu->cpu_m.mcpu_cpi = NULL;
566ae115bc7Smrj }
567ae115bc7Smrj 
568551bc2a6Smrj #if !defined(__xpv)
569551bc2a6Smrj 
570551bc2a6Smrj static void
571b9bfdccdSStuart Maybee determine_platform()
572551bc2a6Smrj {
573551bc2a6Smrj 	struct cpuid_regs cp;
574551bc2a6Smrj 	char *xen_str;
5756e5580c9SFrank Van Der Linden 	uint32_t xen_signature[4], base;
576551bc2a6Smrj 
577349b53ddSStuart Maybee 	platform_type = HW_NATIVE;
578349b53ddSStuart Maybee 
579349b53ddSStuart Maybee 	if (!enable_platform_detection)
580349b53ddSStuart Maybee 		return;
581349b53ddSStuart Maybee 
582551bc2a6Smrj 	/*
583551bc2a6Smrj 	 * In a fully virtualized domain, Xen's pseudo-cpuid function
5846e5580c9SFrank Van Der Linden 	 * returns a string representing the Xen signature in %ebx, %ecx,
5856e5580c9SFrank Van Der Linden 	 * and %edx. %eax contains the maximum supported cpuid function.
5866e5580c9SFrank Van Der Linden 	 * We need at least a (base + 2) leaf value to do what we want
5876e5580c9SFrank Van Der Linden 	 * to do. Try different base values, since the hypervisor might
5886e5580c9SFrank Van Der Linden 	 * use a different one depending on whether hyper-v emulation
5896e5580c9SFrank Van Der Linden 	 * is switched on by default or not.
590551bc2a6Smrj 	 */
5916e5580c9SFrank Van Der Linden 	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
5926e5580c9SFrank Van Der Linden 		cp.cp_eax = base;
593551bc2a6Smrj 		(void) __cpuid_insn(&cp);
594551bc2a6Smrj 		xen_signature[0] = cp.cp_ebx;
595551bc2a6Smrj 		xen_signature[1] = cp.cp_ecx;
596551bc2a6Smrj 		xen_signature[2] = cp.cp_edx;
597551bc2a6Smrj 		xen_signature[3] = 0;
598551bc2a6Smrj 		xen_str = (char *)xen_signature;
5996e5580c9SFrank Van Der Linden 		if (strcmp("XenVMMXenVMM", xen_str) == 0 &&
6006e5580c9SFrank Van Der Linden 		    cp.cp_eax >= (base + 2)) {
601b9bfdccdSStuart Maybee 			platform_type = HW_XEN_HVM;
6026e5580c9SFrank Van Der Linden 			return;
603551bc2a6Smrj 		}
604b9bfdccdSStuart Maybee 	}
605b9bfdccdSStuart Maybee 
6066e5580c9SFrank Van Der Linden 	if (vmware_platform()) /* running under vmware hypervisor? */
6076e5580c9SFrank Van Der Linden 		platform_type = HW_VMWARE;
6086e5580c9SFrank Van Der Linden }
6096e5580c9SFrank Van Der Linden 
610b9bfdccdSStuart Maybee int
611b9bfdccdSStuart Maybee get_hwenv(void)
612b9bfdccdSStuart Maybee {
613349b53ddSStuart Maybee 	if (platform_type == -1)
614349b53ddSStuart Maybee 		determine_platform();
615349b53ddSStuart Maybee 
616b9bfdccdSStuart Maybee 	return (platform_type);
617b9bfdccdSStuart Maybee }
618b9bfdccdSStuart Maybee 
619b9bfdccdSStuart Maybee int
620b9bfdccdSStuart Maybee is_controldom(void)
621b9bfdccdSStuart Maybee {
622b9bfdccdSStuart Maybee 	return (0);
623b9bfdccdSStuart Maybee }
624b9bfdccdSStuart Maybee 
625b9bfdccdSStuart Maybee #else
626b9bfdccdSStuart Maybee 
627b9bfdccdSStuart Maybee int
628b9bfdccdSStuart Maybee get_hwenv(void)
629b9bfdccdSStuart Maybee {
630b9bfdccdSStuart Maybee 	return (HW_XEN_PV);
631b9bfdccdSStuart Maybee }
632b9bfdccdSStuart Maybee 
633b9bfdccdSStuart Maybee int
634b9bfdccdSStuart Maybee is_controldom(void)
635b9bfdccdSStuart Maybee {
636b9bfdccdSStuart Maybee 	return (DOMAIN_IS_INITDOMAIN(xen_info));
637b9bfdccdSStuart Maybee }
638b9bfdccdSStuart Maybee 
639551bc2a6Smrj #endif	/* __xpv */
640551bc2a6Smrj 
6418031591dSSrihari Venkatesan static void
6427417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu_t *cpu, void *feature)
6438031591dSSrihari Venkatesan {
6448031591dSSrihari Venkatesan 	uint_t i;
6458031591dSSrihari Venkatesan 	uint_t chipid_shift = 0;
6468031591dSSrihari Venkatesan 	uint_t coreid_shift = 0;
6478031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
6488031591dSSrihari Venkatesan 
6498031591dSSrihari Venkatesan 	for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1)
6508031591dSSrihari Venkatesan 		chipid_shift++;
6518031591dSSrihari Venkatesan 
6528031591dSSrihari Venkatesan 	cpi->cpi_chipid = cpi->cpi_apicid >> chipid_shift;
6538031591dSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_apicid & ((1 << chipid_shift) - 1);
6548031591dSSrihari Venkatesan 
6557417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(feature, X86FSET_CMP)) {
6568031591dSSrihari Venkatesan 		/*
6578031591dSSrihari Venkatesan 		 * Multi-core (and possibly multi-threaded)
6588031591dSSrihari Venkatesan 		 * processors.
6598031591dSSrihari Venkatesan 		 */
6608031591dSSrihari Venkatesan 		uint_t ncpu_per_core;
6618031591dSSrihari Venkatesan 		if (cpi->cpi_ncore_per_chip == 1)
6628031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip;
6638031591dSSrihari Venkatesan 		else if (cpi->cpi_ncore_per_chip > 1)
6648031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip /
6658031591dSSrihari Venkatesan 			    cpi->cpi_ncore_per_chip;
6668031591dSSrihari Venkatesan 		/*
6678031591dSSrihari Venkatesan 		 * 8bit APIC IDs on dual core Pentiums
6688031591dSSrihari Venkatesan 		 * look like this:
6698031591dSSrihari Venkatesan 		 *
6708031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
6718031591dSSrihari Venkatesan 		 * | Physical Package ID   |  MC  |  HT  |
6728031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
6738031591dSSrihari Venkatesan 		 * <------- chipid -------->
6748031591dSSrihari Venkatesan 		 * <------- coreid --------------->
6758031591dSSrihari Venkatesan 		 *			   <--- clogid -->
6768031591dSSrihari Venkatesan 		 *			   <------>
6778031591dSSrihari Venkatesan 		 *			   pkgcoreid
6788031591dSSrihari Venkatesan 		 *
6798031591dSSrihari Venkatesan 		 * Where the number of bits necessary to
6808031591dSSrihari Venkatesan 		 * represent MC and HT fields together equals
6818031591dSSrihari Venkatesan 		 * to the minimum number of bits necessary to
6828031591dSSrihari Venkatesan 		 * store the value of cpi->cpi_ncpu_per_chip.
6838031591dSSrihari Venkatesan 		 * Of those bits, the MC part uses the number
6848031591dSSrihari Venkatesan 		 * of bits necessary to store the value of
6858031591dSSrihari Venkatesan 		 * cpi->cpi_ncore_per_chip.
6868031591dSSrihari Venkatesan 		 */
6878031591dSSrihari Venkatesan 		for (i = 1; i < ncpu_per_core; i <<= 1)
6888031591dSSrihari Venkatesan 			coreid_shift++;
6898031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_apicid >> coreid_shift;
6908031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
6917417cfdeSKuriakose Kuruvilla 	} else if (is_x86_feature(feature, X86FSET_HTT)) {
6928031591dSSrihari Venkatesan 		/*
6938031591dSSrihari Venkatesan 		 * Single-core multi-threaded processors.
6948031591dSSrihari Venkatesan 		 */
6958031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_chipid;
6968031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = 0;
6978031591dSSrihari Venkatesan 	}
6988031591dSSrihari Venkatesan 	cpi->cpi_procnodeid = cpi->cpi_chipid;
6998031591dSSrihari Venkatesan }
7008031591dSSrihari Venkatesan 
7018031591dSSrihari Venkatesan static void
7028031591dSSrihari Venkatesan cpuid_amd_getids(cpu_t *cpu)
7038031591dSSrihari Venkatesan {
7041fbe4a4fSSrihari Venkatesan 	int i, first_half, coreidsz;
7058031591dSSrihari Venkatesan 	uint32_t nb_caps_reg;
7068031591dSSrihari Venkatesan 	uint_t node2_1;
7078031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
7088031591dSSrihari Venkatesan 
7098031591dSSrihari Venkatesan 	/*
7108031591dSSrihari Venkatesan 	 * AMD CMP chips currently have a single thread per core.
7118031591dSSrihari Venkatesan 	 *
7128031591dSSrihari Venkatesan 	 * Since no two cpus share a core we must assign a distinct coreid
7138031591dSSrihari Venkatesan 	 * per cpu, and we do this by using the cpu_id.  This scheme does not,
7148031591dSSrihari Venkatesan 	 * however, guarantee that sibling cores of a chip will have sequential
7158031591dSSrihari Venkatesan 	 * coreids starting at a multiple of the number of cores per chip -
7168031591dSSrihari Venkatesan 	 * that is usually the case, but if the ACPI MADT table is presented
7178031591dSSrihari Venkatesan 	 * in a different order then we need to perform a few more gymnastics
7188031591dSSrihari Venkatesan 	 * for the pkgcoreid.
7198031591dSSrihari Venkatesan 	 *
7208031591dSSrihari Venkatesan 	 * All processors in the system have the same number of enabled
7218031591dSSrihari Venkatesan 	 * cores. Cores within a processor are always numbered sequentially
7228031591dSSrihari Venkatesan 	 * from 0 regardless of how many or which are disabled, and there
7238031591dSSrihari Venkatesan 	 * is no way for operating system to discover the real core id when some
7248031591dSSrihari Venkatesan 	 * are disabled.
7258031591dSSrihari Venkatesan 	 */
7268031591dSSrihari Venkatesan 
7278031591dSSrihari Venkatesan 	cpi->cpi_coreid = cpu->cpu_id;
7288031591dSSrihari Venkatesan 
7298031591dSSrihari Venkatesan 	if (cpi->cpi_xmaxeax >= 0x80000008) {
7308031591dSSrihari Venkatesan 
7318031591dSSrihari Venkatesan 		coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12);
7328031591dSSrihari Venkatesan 
7338031591dSSrihari Venkatesan 		/*
7348031591dSSrihari Venkatesan 		 * In AMD parlance chip is really a node while Solaris
7358031591dSSrihari Venkatesan 		 * sees chip as equivalent to socket/package.
7368031591dSSrihari Venkatesan 		 */
7378031591dSSrihari Venkatesan 		cpi->cpi_ncore_per_chip =
7388031591dSSrihari Venkatesan 		    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
7391fbe4a4fSSrihari Venkatesan 		if (coreidsz == 0) {
7408031591dSSrihari Venkatesan 			/* Use legacy method */
7411fbe4a4fSSrihari Venkatesan 			for (i = 1; i < cpi->cpi_ncore_per_chip; i <<= 1)
7421fbe4a4fSSrihari Venkatesan 				coreidsz++;
7431fbe4a4fSSrihari Venkatesan 			if (coreidsz == 0)
7441fbe4a4fSSrihari Venkatesan 				coreidsz = 1;
7451fbe4a4fSSrihari Venkatesan 		}
7468031591dSSrihari Venkatesan 	} else {
7478031591dSSrihari Venkatesan 		/* Assume single-core part */
7481fbe4a4fSSrihari Venkatesan 		cpi->cpi_ncore_per_chip = 1;
749*72b70389SJakub Jermar 		coreidsz = 1;
7508031591dSSrihari Venkatesan 	}
7518031591dSSrihari Venkatesan 
7521fbe4a4fSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_pkgcoreid =
7531fbe4a4fSSrihari Venkatesan 	    cpi->cpi_apicid & ((1<<coreidsz) - 1);
7548031591dSSrihari Venkatesan 	cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip;
7558031591dSSrihari Venkatesan 
7568031591dSSrihari Venkatesan 	/* Get nodeID */
7578031591dSSrihari Venkatesan 	if (cpi->cpi_family == 0xf) {
7581fbe4a4fSSrihari Venkatesan 		cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
7598031591dSSrihari Venkatesan 		cpi->cpi_chipid = cpi->cpi_procnodeid;
7608031591dSSrihari Venkatesan 	} else if (cpi->cpi_family == 0x10) {
7618031591dSSrihari Venkatesan 		/*
7628031591dSSrihari Venkatesan 		 * See if we are a multi-node processor.
7638031591dSSrihari Venkatesan 		 * All processors in the system have the same number of nodes
7648031591dSSrihari Venkatesan 		 */
7658031591dSSrihari Venkatesan 		nb_caps_reg =  pci_getl_func(0, 24, 3, 0xe8);
7668031591dSSrihari Venkatesan 		if ((cpi->cpi_model < 8) || BITX(nb_caps_reg, 29, 29) == 0) {
7678031591dSSrihari Venkatesan 			/* Single-node */
7681fbe4a4fSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5,
7691fbe4a4fSSrihari Venkatesan 			    coreidsz);
7708031591dSSrihari Venkatesan 			cpi->cpi_chipid = cpi->cpi_procnodeid;
7718031591dSSrihari Venkatesan 		} else {
7728031591dSSrihari Venkatesan 
7738031591dSSrihari Venkatesan 			/*
7748031591dSSrihari Venkatesan 			 * Multi-node revision D (2 nodes per package
7758031591dSSrihari Venkatesan 			 * are supported)
7768031591dSSrihari Venkatesan 			 */
7778031591dSSrihari Venkatesan 			cpi->cpi_procnodes_per_pkg = 2;
7788031591dSSrihari Venkatesan 
7798031591dSSrihari Venkatesan 			first_half = (cpi->cpi_pkgcoreid <=
7808031591dSSrihari Venkatesan 			    (cpi->cpi_ncore_per_chip/2 - 1));
7818031591dSSrihari Venkatesan 
7828031591dSSrihari Venkatesan 			if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) {
7838031591dSSrihari Venkatesan 				/* We are BSP */
7848031591dSSrihari Venkatesan 				cpi->cpi_procnodeid = (first_half ? 0 : 1);
7858031591dSSrihari Venkatesan 				cpi->cpi_chipid = cpi->cpi_procnodeid >> 1;
7868031591dSSrihari Venkatesan 			} else {
7878031591dSSrihari Venkatesan 
7888031591dSSrihari Venkatesan 				/* We are AP */
7898031591dSSrihari Venkatesan 				/* NodeId[2:1] bits to use for reading F3xe8 */
7908031591dSSrihari Venkatesan 				node2_1 = BITX(cpi->cpi_apicid, 5, 4) << 1;
7918031591dSSrihari Venkatesan 
7928031591dSSrihari Venkatesan 				nb_caps_reg =
7938031591dSSrihari Venkatesan 				    pci_getl_func(0, 24 + node2_1, 3, 0xe8);
7948031591dSSrihari Venkatesan 
7958031591dSSrihari Venkatesan 				/*
7968031591dSSrihari Venkatesan 				 * Check IntNodeNum bit (31:30, but bit 31 is
7978031591dSSrihari Venkatesan 				 * always 0 on dual-node processors)
7988031591dSSrihari Venkatesan 				 */
7998031591dSSrihari Venkatesan 				if (BITX(nb_caps_reg, 30, 30) == 0)
8008031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
8018031591dSSrihari Venkatesan 					    !first_half;
8028031591dSSrihari Venkatesan 				else
8038031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
8048031591dSSrihari Venkatesan 					    first_half;
8058031591dSSrihari Venkatesan 
8068031591dSSrihari Venkatesan 				cpi->cpi_chipid = cpi->cpi_procnodeid >> 1;
8078031591dSSrihari Venkatesan 			}
8088031591dSSrihari Venkatesan 		}
8098031591dSSrihari Venkatesan 	} else if (cpi->cpi_family >= 0x11) {
8108031591dSSrihari Venkatesan 		cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
8118031591dSSrihari Venkatesan 		cpi->cpi_chipid = cpi->cpi_procnodeid;
8128031591dSSrihari Venkatesan 	} else {
8138031591dSSrihari Venkatesan 		cpi->cpi_procnodeid = 0;
8148031591dSSrihari Venkatesan 		cpi->cpi_chipid = cpi->cpi_procnodeid;
8158031591dSSrihari Venkatesan 	}
8168031591dSSrihari Venkatesan }
8178031591dSSrihari Venkatesan 
8187417cfdeSKuriakose Kuruvilla void *
8197c478bd9Sstevel@tonic-gate cpuid_pass1(cpu_t *cpu)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate 	uint32_t mask_ecx, mask_edx;
8227417cfdeSKuriakose Kuruvilla 	void *featureset;
8237c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
8248949bcd6Sandrei 	struct cpuid_regs *cp;
8257c478bd9Sstevel@tonic-gate 	int xcpuid;
826843e1988Sjohnlev #if !defined(__xpv)
8275b8a6efeSbholler 	extern int idle_cpu_prefer_mwait;
828843e1988Sjohnlev #endif
829ae115bc7Smrj 
83089e921d5SKuriakose Kuruvilla 
83189e921d5SKuriakose Kuruvilla #if !defined(__xpv)
83289e921d5SKuriakose Kuruvilla 	determine_platform();
83389e921d5SKuriakose Kuruvilla #endif
8347c478bd9Sstevel@tonic-gate 	/*
835a3114836SGerry Liu 	 * Space statically allocated for BSP, ensure pointer is set
8367c478bd9Sstevel@tonic-gate 	 */
8377417cfdeSKuriakose Kuruvilla 	if (cpu->cpu_id == 0) {
8387417cfdeSKuriakose Kuruvilla 		if (cpu->cpu_m.mcpu_cpi == NULL)
839ae115bc7Smrj 			cpu->cpu_m.mcpu_cpi = &cpuid_info0;
8407417cfdeSKuriakose Kuruvilla 		featureset = x86_featureset0;
8417417cfdeSKuriakose Kuruvilla 	} else {
8427417cfdeSKuriakose Kuruvilla 		featureset = init_x86_featureset();
8437417cfdeSKuriakose Kuruvilla 	}
8447417cfdeSKuriakose Kuruvilla 
8457417cfdeSKuriakose Kuruvilla 	add_x86_feature(featureset, X86FSET_CPUID);
8467417cfdeSKuriakose Kuruvilla 
847ae115bc7Smrj 	cpi = cpu->cpu_m.mcpu_cpi;
848ae115bc7Smrj 	ASSERT(cpi != NULL);
8497c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[0];
8508949bcd6Sandrei 	cp->cp_eax = 0;
8518949bcd6Sandrei 	cpi->cpi_maxeax = __cpuid_insn(cp);
8527c478bd9Sstevel@tonic-gate 	{
8537c478bd9Sstevel@tonic-gate 		uint32_t *iptr = (uint32_t *)cpi->cpi_vendorstr;
8547c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ebx;
8557c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_edx;
8567c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ecx;
8577c478bd9Sstevel@tonic-gate 		*(char *)&cpi->cpi_vendorstr[12] = '\0';
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 
860e4b86885SCheng Sean Ye 	cpi->cpi_vendor = _cpuid_vendorstr_to_vendorcode(cpi->cpi_vendorstr);
8617c478bd9Sstevel@tonic-gate 	x86_vendor = cpi->cpi_vendor; /* for compatibility */
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	/*
8647c478bd9Sstevel@tonic-gate 	 * Limit the range in case of weird hardware
8657c478bd9Sstevel@tonic-gate 	 */
8667c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax > CPI_MAXEAX_MAX)
8677c478bd9Sstevel@tonic-gate 		cpi->cpi_maxeax = CPI_MAXEAX_MAX;
8687c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
8697c478bd9Sstevel@tonic-gate 		goto pass1_done;
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[1];
8728949bcd6Sandrei 	cp->cp_eax = 1;
8738949bcd6Sandrei 	(void) __cpuid_insn(cp);
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	/*
8767c478bd9Sstevel@tonic-gate 	 * Extract identifying constants for easy access.
8777c478bd9Sstevel@tonic-gate 	 */
8787c478bd9Sstevel@tonic-gate 	cpi->cpi_model = CPI_MODEL(cpi);
8797c478bd9Sstevel@tonic-gate 	cpi->cpi_family = CPI_FAMILY(cpi);
8807c478bd9Sstevel@tonic-gate 
8815ff02082Sdmick 	if (cpi->cpi_family == 0xf)
8827c478bd9Sstevel@tonic-gate 		cpi->cpi_family += CPI_FAMILY_XTD(cpi);
8835ff02082Sdmick 
88468c91426Sdmick 	/*
885875b116eSkchow 	 * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
88668c91426Sdmick 	 * Intel, and presumably everyone else, uses model == 0xf, as
88768c91426Sdmick 	 * one would expect (max value means possible overflow).  Sigh.
88868c91426Sdmick 	 */
88968c91426Sdmick 
89068c91426Sdmick 	switch (cpi->cpi_vendor) {
891bf91205bSksadhukh 	case X86_VENDOR_Intel:
892bf91205bSksadhukh 		if (IS_EXTENDED_MODEL_INTEL(cpi))
893bf91205bSksadhukh 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
894447af253Sksadhukh 		break;
89568c91426Sdmick 	case X86_VENDOR_AMD:
896875b116eSkchow 		if (CPI_FAMILY(cpi) == 0xf)
89768c91426Sdmick 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
89868c91426Sdmick 		break;
89968c91426Sdmick 	default:
9005ff02082Sdmick 		if (cpi->cpi_model == 0xf)
9017c478bd9Sstevel@tonic-gate 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
90268c91426Sdmick 		break;
90368c91426Sdmick 	}
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	cpi->cpi_step = CPI_STEP(cpi);
9067c478bd9Sstevel@tonic-gate 	cpi->cpi_brandid = CPI_BRANDID(cpi);
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	/*
9097c478bd9Sstevel@tonic-gate 	 * *default* assumptions:
9107c478bd9Sstevel@tonic-gate 	 * - believe %edx feature word
9117c478bd9Sstevel@tonic-gate 	 * - ignore %ecx feature word
9127c478bd9Sstevel@tonic-gate 	 * - 32-bit virtual and physical addressing
9137c478bd9Sstevel@tonic-gate 	 */
9147c478bd9Sstevel@tonic-gate 	mask_edx = 0xffffffff;
9157c478bd9Sstevel@tonic-gate 	mask_ecx = 0;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	cpi->cpi_pabits = cpi->cpi_vabits = 32;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
9207c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
9217c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
9227c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P5;
9235ff02082Sdmick 		else if (IS_LEGACY_P6(cpi)) {
9247c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P6;
9257c478bd9Sstevel@tonic-gate 			pentiumpro_bug4046376 = 1;
9267c478bd9Sstevel@tonic-gate 			pentiumpro_bug4064495 = 1;
9277c478bd9Sstevel@tonic-gate 			/*
9287c478bd9Sstevel@tonic-gate 			 * Clear the SEP bit when it was set erroneously
9297c478bd9Sstevel@tonic-gate 			 */
9307c478bd9Sstevel@tonic-gate 			if (cpi->cpi_model < 3 && cpi->cpi_step < 3)
9317c478bd9Sstevel@tonic-gate 				cp->cp_edx &= ~CPUID_INTC_EDX_SEP;
9325ff02082Sdmick 		} else if (IS_NEW_F6(cpi) || cpi->cpi_family == 0xf) {
9337c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P4;
9347c478bd9Sstevel@tonic-gate 			/*
9357c478bd9Sstevel@tonic-gate 			 * We don't currently depend on any of the %ecx
9367c478bd9Sstevel@tonic-gate 			 * features until Prescott, so we'll only check
9377c478bd9Sstevel@tonic-gate 			 * this from P4 onwards.  We might want to revisit
9387c478bd9Sstevel@tonic-gate 			 * that idea later.
9397c478bd9Sstevel@tonic-gate 			 */
9407c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
9417c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family > 0xf)
9427c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
9437c622d23Sbholler 		/*
9447c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
9457c622d23Sbholler 		 * to obtain the monitor linesize.
9467c622d23Sbholler 		 */
9477c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
9487c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
9497c478bd9Sstevel@tonic-gate 		break;
9507c478bd9Sstevel@tonic-gate 	case X86_VENDOR_IntelClone:
9517c478bd9Sstevel@tonic-gate 	default:
9527c478bd9Sstevel@tonic-gate 		break;
9537c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
9547c478bd9Sstevel@tonic-gate #if defined(OPTERON_ERRATUM_108)
9557c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 0xf && cpi->cpi_model == 0xe) {
9567c478bd9Sstevel@tonic-gate 			cp->cp_eax = (0xf0f & cp->cp_eax) | 0xc0;
9577c478bd9Sstevel@tonic-gate 			cpi->cpi_model = 0xc;
9587c478bd9Sstevel@tonic-gate 		} else
9597c478bd9Sstevel@tonic-gate #endif
9607c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5) {
9617c478bd9Sstevel@tonic-gate 			/*
9627c478bd9Sstevel@tonic-gate 			 * AMD K5 and K6
9637c478bd9Sstevel@tonic-gate 			 *
9647c478bd9Sstevel@tonic-gate 			 * These CPUs have an incomplete implementation
9657c478bd9Sstevel@tonic-gate 			 * of MCA/MCE which we mask away.
9667c478bd9Sstevel@tonic-gate 			 */
9678949bcd6Sandrei 			mask_edx &= ~(CPUID_INTC_EDX_MCE | CPUID_INTC_EDX_MCA);
9688949bcd6Sandrei 
9697c478bd9Sstevel@tonic-gate 			/*
9707c478bd9Sstevel@tonic-gate 			 * Model 0 uses the wrong (APIC) bit
9717c478bd9Sstevel@tonic-gate 			 * to indicate PGE.  Fix it here.
9727c478bd9Sstevel@tonic-gate 			 */
9738949bcd6Sandrei 			if (cpi->cpi_model == 0) {
9747c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x200) {
9757c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x200;
9767c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_INTC_EDX_PGE;
9777c478bd9Sstevel@tonic-gate 				}
9787c478bd9Sstevel@tonic-gate 			}
9798949bcd6Sandrei 
9808949bcd6Sandrei 			/*
9818949bcd6Sandrei 			 * Early models had problems w/ MMX; disable.
9828949bcd6Sandrei 			 */
9838949bcd6Sandrei 			if (cpi->cpi_model < 6)
9848949bcd6Sandrei 				mask_edx &= ~CPUID_INTC_EDX_MMX;
9858949bcd6Sandrei 		}
9868949bcd6Sandrei 
9878949bcd6Sandrei 		/*
9888949bcd6Sandrei 		 * For newer families, SSE3 and CX16, at least, are valid;
9898949bcd6Sandrei 		 * enable all
9908949bcd6Sandrei 		 */
9918949bcd6Sandrei 		if (cpi->cpi_family >= 0xf)
9928949bcd6Sandrei 			mask_ecx = 0xffffffff;
9937c622d23Sbholler 		/*
9947c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
9957c622d23Sbholler 		 * to obtain the monitor linesize.
9967c622d23Sbholler 		 */
9977c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
9987c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
9995b8a6efeSbholler 
1000843e1988Sjohnlev #if !defined(__xpv)
10015b8a6efeSbholler 		/*
10025b8a6efeSbholler 		 * Do not use MONITOR/MWAIT to halt in the idle loop on any AMD
10035b8a6efeSbholler 		 * processors.  AMD does not intend MWAIT to be used in the cpu
10045b8a6efeSbholler 		 * idle loop on current and future processors.  10h and future
10055b8a6efeSbholler 		 * AMD processors use more power in MWAIT than HLT.
10065b8a6efeSbholler 		 * Pre-family-10h Opterons do not have the MWAIT instruction.
10075b8a6efeSbholler 		 */
10085b8a6efeSbholler 		idle_cpu_prefer_mwait = 0;
1009843e1988Sjohnlev #endif
10105b8a6efeSbholler 
10117c478bd9Sstevel@tonic-gate 		break;
10127c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
10137c478bd9Sstevel@tonic-gate 		/*
10147c478bd9Sstevel@tonic-gate 		 * workaround the NT workaround in CMS 4.1
10157c478bd9Sstevel@tonic-gate 		 */
10167c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4 &&
10177c478bd9Sstevel@tonic-gate 		    (cpi->cpi_step == 2 || cpi->cpi_step == 3))
10187c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
10197c478bd9Sstevel@tonic-gate 		break;
10207c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
10217c478bd9Sstevel@tonic-gate 		/*
10227c478bd9Sstevel@tonic-gate 		 * workaround the NT workarounds again
10237c478bd9Sstevel@tonic-gate 		 */
10247c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 6)
10257c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
10267c478bd9Sstevel@tonic-gate 		break;
10277c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
10287c478bd9Sstevel@tonic-gate 		/*
10297c478bd9Sstevel@tonic-gate 		 * We rely heavily on the probing in locore
10307c478bd9Sstevel@tonic-gate 		 * to actually figure out what parts, if any,
10317c478bd9Sstevel@tonic-gate 		 * of the Cyrix cpuid instruction to believe.
10327c478bd9Sstevel@tonic-gate 		 */
10337c478bd9Sstevel@tonic-gate 		switch (x86_type) {
10347c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_486:
10357c478bd9Sstevel@tonic-gate 			mask_edx = 0;
10367c478bd9Sstevel@tonic-gate 			break;
10377c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86:
10387c478bd9Sstevel@tonic-gate 			mask_edx = 0;
10397c478bd9Sstevel@tonic-gate 			break;
10407c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86L:
10417c478bd9Sstevel@tonic-gate 			mask_edx =
10427c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
10437c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8;
10447c478bd9Sstevel@tonic-gate 			break;
10457c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86MX:
10467c478bd9Sstevel@tonic-gate 			mask_edx =
10477c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
10487c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
10497c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
10507c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
10517c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
10527c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
10537c478bd9Sstevel@tonic-gate 			break;
10547c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_GXm:
10557c478bd9Sstevel@tonic-gate 			mask_edx =
10567c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
10577c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
10587c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
10597c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
10607c478bd9Sstevel@tonic-gate 			break;
10617c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MediaGX:
10627c478bd9Sstevel@tonic-gate 			break;
10637c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MII:
10647c478bd9Sstevel@tonic-gate 		case X86_TYPE_VIA_CYRIX_III:
10657c478bd9Sstevel@tonic-gate 			mask_edx =
10667c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
10677c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_TSC |
10687c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
10697c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
10707c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
10717c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
10727c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
10737c478bd9Sstevel@tonic-gate 			break;
10747c478bd9Sstevel@tonic-gate 		default:
10757c478bd9Sstevel@tonic-gate 			break;
10767c478bd9Sstevel@tonic-gate 		}
10777c478bd9Sstevel@tonic-gate 		break;
10787c478bd9Sstevel@tonic-gate 	}
10797c478bd9Sstevel@tonic-gate 
1080843e1988Sjohnlev #if defined(__xpv)
1081843e1988Sjohnlev 	/*
1082843e1988Sjohnlev 	 * Do not support MONITOR/MWAIT under a hypervisor
1083843e1988Sjohnlev 	 */
1084843e1988Sjohnlev 	mask_ecx &= ~CPUID_INTC_ECX_MON;
1085843e1988Sjohnlev #endif	/* __xpv */
1086843e1988Sjohnlev 
10877c478bd9Sstevel@tonic-gate 	/*
10887c478bd9Sstevel@tonic-gate 	 * Now we've figured out the masks that determine
10897c478bd9Sstevel@tonic-gate 	 * which bits we choose to believe, apply the masks
10907c478bd9Sstevel@tonic-gate 	 * to the feature words, then map the kernel's view
10917c478bd9Sstevel@tonic-gate 	 * of these feature words into its feature word.
10927c478bd9Sstevel@tonic-gate 	 */
10937c478bd9Sstevel@tonic-gate 	cp->cp_edx &= mask_edx;
10947c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= mask_ecx;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	/*
1097ae115bc7Smrj 	 * apply any platform restrictions (we don't call this
1098ae115bc7Smrj 	 * immediately after __cpuid_insn here, because we need the
1099ae115bc7Smrj 	 * workarounds applied above first)
11007c478bd9Sstevel@tonic-gate 	 */
1101ae115bc7Smrj 	platform_cpuid_mangle(cpi->cpi_vendor, 1, cp);
11027c478bd9Sstevel@tonic-gate 
1103ae115bc7Smrj 	/*
1104ae115bc7Smrj 	 * fold in overrides from the "eeprom" mechanism
1105ae115bc7Smrj 	 */
11067c478bd9Sstevel@tonic-gate 	cp->cp_edx |= cpuid_feature_edx_include;
11077c478bd9Sstevel@tonic-gate 	cp->cp_edx &= ~cpuid_feature_edx_exclude;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	cp->cp_ecx |= cpuid_feature_ecx_include;
11107c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= ~cpuid_feature_ecx_exclude;
11117c478bd9Sstevel@tonic-gate 
11127417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PSE) {
11137417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_LARGEPAGE);
11147417cfdeSKuriakose Kuruvilla 	}
11157417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_TSC) {
11167417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_TSC);
11177417cfdeSKuriakose Kuruvilla 	}
11187417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MSR) {
11197417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MSR);
11207417cfdeSKuriakose Kuruvilla 	}
11217417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MTRR) {
11227417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MTRR);
11237417cfdeSKuriakose Kuruvilla 	}
11247417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PGE) {
11257417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PGE);
11267417cfdeSKuriakose Kuruvilla 	}
11277417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CMOV) {
11287417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMOV);
11297417cfdeSKuriakose Kuruvilla 	}
11307417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MMX) {
11317417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MMX);
11327417cfdeSKuriakose Kuruvilla 	}
11337c478bd9Sstevel@tonic-gate 	if ((cp->cp_edx & CPUID_INTC_EDX_MCE) != 0 &&
11347417cfdeSKuriakose Kuruvilla 	    (cp->cp_edx & CPUID_INTC_EDX_MCA) != 0) {
11357417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MCA);
11367417cfdeSKuriakose Kuruvilla 	}
11377417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAE) {
11387417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAE);
11397417cfdeSKuriakose Kuruvilla 	}
11407417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CX8) {
11417417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX8);
11427417cfdeSKuriakose Kuruvilla 	}
11437417cfdeSKuriakose Kuruvilla 	if (cp->cp_ecx & CPUID_INTC_ECX_CX16) {
11447417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX16);
11457417cfdeSKuriakose Kuruvilla 	}
11467417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAT) {
11477417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAT);
11487417cfdeSKuriakose Kuruvilla 	}
11497417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_SEP) {
11507417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_SEP);
11517417cfdeSKuriakose Kuruvilla 	}
11527c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_FXSR) {
11537c478bd9Sstevel@tonic-gate 		/*
11547c478bd9Sstevel@tonic-gate 		 * In our implementation, fxsave/fxrstor
11557c478bd9Sstevel@tonic-gate 		 * are prerequisites before we'll even
11567c478bd9Sstevel@tonic-gate 		 * try and do SSE things.
11577c478bd9Sstevel@tonic-gate 		 */
11587417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE) {
11597417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE);
11607417cfdeSKuriakose Kuruvilla 		}
11617417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE2) {
11627417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE2);
11637417cfdeSKuriakose Kuruvilla 		}
11647417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) {
11657417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE3);
11667417cfdeSKuriakose Kuruvilla 		}
1167d0f8ff6eSkk208521 		if (cpi->cpi_vendor == X86_VENDOR_Intel) {
11687417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) {
11697417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSSE3);
11707417cfdeSKuriakose Kuruvilla 			}
11717417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) {
11727417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4_1);
11737417cfdeSKuriakose Kuruvilla 			}
11747417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) {
11757417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4_2);
11767417cfdeSKuriakose Kuruvilla 			}
11777417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_AES) {
11787417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_AES);
11797417cfdeSKuriakose Kuruvilla 			}
11807417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) {
11817417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_PCLMULQDQ);
1182d0f8ff6eSkk208521 			}
11837c478bd9Sstevel@tonic-gate 		}
11847417cfdeSKuriakose Kuruvilla 	}
11857417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_DE) {
11867417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_DE);
11877417cfdeSKuriakose Kuruvilla 	}
11881d1a3942SBill Holler #if !defined(__xpv)
1189f98fbcecSbholler 	if (cp->cp_ecx & CPUID_INTC_ECX_MON) {
11901d1a3942SBill Holler 
11911d1a3942SBill Holler 		/*
11921d1a3942SBill Holler 		 * We require the CLFLUSH instruction for erratum workaround
11931d1a3942SBill Holler 		 * to use MONITOR/MWAIT.
11941d1a3942SBill Holler 		 */
11951d1a3942SBill Holler 		if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
1196f98fbcecSbholler 			cpi->cpi_mwait.support |= MWAIT_SUPPORT;
11977417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_MWAIT);
11981d1a3942SBill Holler 		} else {
11991d1a3942SBill Holler 			extern int idle_cpu_assert_cflush_monitor;
12001d1a3942SBill Holler 
12011d1a3942SBill Holler 			/*
12021d1a3942SBill Holler 			 * All processors we are aware of which have
12031d1a3942SBill Holler 			 * MONITOR/MWAIT also have CLFLUSH.
12041d1a3942SBill Holler 			 */
12051d1a3942SBill Holler 			if (idle_cpu_assert_cflush_monitor) {
12061d1a3942SBill Holler 				ASSERT((cp->cp_ecx & CPUID_INTC_ECX_MON) &&
12071d1a3942SBill Holler 				    (cp->cp_edx & CPUID_INTC_EDX_CLFSH));
1208f98fbcecSbholler 			}
12091d1a3942SBill Holler 		}
12101d1a3942SBill Holler 	}
12111d1a3942SBill Holler #endif	/* __xpv */
12127c478bd9Sstevel@tonic-gate 
121386c1f4dcSVikram Hegde 	/*
121486c1f4dcSVikram Hegde 	 * Only need it first time, rest of the cpus would follow suite.
121586c1f4dcSVikram Hegde 	 * we only capture this for the bootcpu.
121686c1f4dcSVikram Hegde 	 */
121786c1f4dcSVikram Hegde 	if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
12187417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CLFSH);
121986c1f4dcSVikram Hegde 		x86_clflush_size = (BITX(cp->cp_ebx, 15, 8) * 8);
122086c1f4dcSVikram Hegde 	}
12217417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_PAE))
12227c478bd9Sstevel@tonic-gate 		cpi->cpi_pabits = 36;
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	/*
12257c478bd9Sstevel@tonic-gate 	 * Hyperthreading configuration is slightly tricky on Intel
12267c478bd9Sstevel@tonic-gate 	 * and pure clones, and even trickier on AMD.
12277c478bd9Sstevel@tonic-gate 	 *
12287c478bd9Sstevel@tonic-gate 	 * (AMD chose to set the HTT bit on their CMP processors,
12297c478bd9Sstevel@tonic-gate 	 * even though they're not actually hyperthreaded.  Thus it
12307c478bd9Sstevel@tonic-gate 	 * takes a bit more work to figure out what's really going
1231ae115bc7Smrj 	 * on ... see the handling of the CMP_LGCY bit below)
12327c478bd9Sstevel@tonic-gate 	 */
12337c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_HTT) {
12347c478bd9Sstevel@tonic-gate 		cpi->cpi_ncpu_per_chip = CPI_CPU_COUNT(cpi);
12357c478bd9Sstevel@tonic-gate 		if (cpi->cpi_ncpu_per_chip > 1)
12367417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_HTT);
12378949bcd6Sandrei 	} else {
12388949bcd6Sandrei 		cpi->cpi_ncpu_per_chip = 1;
12397c478bd9Sstevel@tonic-gate 	}
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	/*
12427c478bd9Sstevel@tonic-gate 	 * Work on the "extended" feature information, doing
12437c478bd9Sstevel@tonic-gate 	 * some basic initialization for cpuid_pass2()
12447c478bd9Sstevel@tonic-gate 	 */
12457c478bd9Sstevel@tonic-gate 	xcpuid = 0;
12467c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
12477c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
12485ff02082Sdmick 		if (IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf)
12497c478bd9Sstevel@tonic-gate 			xcpuid++;
12507c478bd9Sstevel@tonic-gate 		break;
12517c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
12527c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
12537c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
12547c478bd9Sstevel@tonic-gate 			xcpuid++;
12557c478bd9Sstevel@tonic-gate 		break;
12567c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
12577c478bd9Sstevel@tonic-gate 		/*
12587c478bd9Sstevel@tonic-gate 		 * Only these Cyrix CPUs are -known- to support
12597c478bd9Sstevel@tonic-gate 		 * extended cpuid operations.
12607c478bd9Sstevel@tonic-gate 		 */
12617c478bd9Sstevel@tonic-gate 		if (x86_type == X86_TYPE_VIA_CYRIX_III ||
12627c478bd9Sstevel@tonic-gate 		    x86_type == X86_TYPE_CYRIX_GXm)
12637c478bd9Sstevel@tonic-gate 			xcpuid++;
12647c478bd9Sstevel@tonic-gate 		break;
12657c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
12667c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
12677c478bd9Sstevel@tonic-gate 	default:
12687c478bd9Sstevel@tonic-gate 		xcpuid++;
12697c478bd9Sstevel@tonic-gate 		break;
12707c478bd9Sstevel@tonic-gate 	}
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	if (xcpuid) {
12737c478bd9Sstevel@tonic-gate 		cp = &cpi->cpi_extd[0];
12748949bcd6Sandrei 		cp->cp_eax = 0x80000000;
12758949bcd6Sandrei 		cpi->cpi_xmaxeax = __cpuid_insn(cp);
12767c478bd9Sstevel@tonic-gate 	}
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax & 0x80000000) {
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax > CPI_XMAXEAX_MAX)
12817c478bd9Sstevel@tonic-gate 			cpi->cpi_xmaxeax = CPI_XMAXEAX_MAX;
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
12847c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
12857c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
12867c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000001)
12877c478bd9Sstevel@tonic-gate 				break;
12887c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[1];
12898949bcd6Sandrei 			cp->cp_eax = 0x80000001;
12908949bcd6Sandrei 			(void) __cpuid_insn(cp);
1291ae115bc7Smrj 
12927c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
12937c478bd9Sstevel@tonic-gate 			    cpi->cpi_family == 5 &&
12947c478bd9Sstevel@tonic-gate 			    cpi->cpi_model == 6 &&
12957c478bd9Sstevel@tonic-gate 			    cpi->cpi_step == 6) {
12967c478bd9Sstevel@tonic-gate 				/*
12977c478bd9Sstevel@tonic-gate 				 * K6 model 6 uses bit 10 to indicate SYSC
12987c478bd9Sstevel@tonic-gate 				 * Later models use bit 11. Fix it here.
12997c478bd9Sstevel@tonic-gate 				 */
13007c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x400) {
13017c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x400;
13027c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_AMD_EDX_SYSC;
13037c478bd9Sstevel@tonic-gate 				}
13047c478bd9Sstevel@tonic-gate 			}
13057c478bd9Sstevel@tonic-gate 
1306ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000001, cp);
1307ae115bc7Smrj 
13087c478bd9Sstevel@tonic-gate 			/*
13097c478bd9Sstevel@tonic-gate 			 * Compute the additions to the kernel's feature word.
13107c478bd9Sstevel@tonic-gate 			 */
13117417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_NX) {
13127417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_NX);
13137417cfdeSKuriakose Kuruvilla 			}
13147c478bd9Sstevel@tonic-gate 
131519397407SSherry Moore 			/*
131619397407SSherry Moore 			 * Regardless whether or not we boot 64-bit,
131719397407SSherry Moore 			 * we should have a way to identify whether
131819397407SSherry Moore 			 * the CPU is capable of running 64-bit.
131919397407SSherry Moore 			 */
13207417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_LM) {
13217417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_64);
13227417cfdeSKuriakose Kuruvilla 			}
132319397407SSherry Moore 
132402bc52beSkchow #if defined(__amd64)
132502bc52beSkchow 			/* 1 GB large page - enable only for 64 bit kernel */
13267417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_1GPG) {
13277417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_1GPG);
13287417cfdeSKuriakose Kuruvilla 			}
132902bc52beSkchow #endif
133002bc52beSkchow 
1331f8801251Skk208521 			if ((cpi->cpi_vendor == X86_VENDOR_AMD) &&
1332f8801251Skk208521 			    (cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_FXSR) &&
13337417cfdeSKuriakose Kuruvilla 			    (cp->cp_ecx & CPUID_AMD_ECX_SSE4A)) {
13347417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4A);
13357417cfdeSKuriakose Kuruvilla 			}
1336f8801251Skk208521 
13377c478bd9Sstevel@tonic-gate 			/*
1338ae115bc7Smrj 			 * If both the HTT and CMP_LGCY bits are set,
13398949bcd6Sandrei 			 * then we're not actually HyperThreaded.  Read
13408949bcd6Sandrei 			 * "AMD CPUID Specification" for more details.
13417c478bd9Sstevel@tonic-gate 			 */
13427c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
13437417cfdeSKuriakose Kuruvilla 			    is_x86_feature(featureset, X86FSET_HTT) &&
1344ae115bc7Smrj 			    (cp->cp_ecx & CPUID_AMD_ECX_CMP_LGCY)) {
13457417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_HTT);
13467417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_CMP);
13478949bcd6Sandrei 			}
1348ae115bc7Smrj #if defined(__amd64)
13497c478bd9Sstevel@tonic-gate 			/*
13507c478bd9Sstevel@tonic-gate 			 * It's really tricky to support syscall/sysret in
13517c478bd9Sstevel@tonic-gate 			 * the i386 kernel; we rely on sysenter/sysexit
13527c478bd9Sstevel@tonic-gate 			 * instead.  In the amd64 kernel, things are -way-
13537c478bd9Sstevel@tonic-gate 			 * better.
13547c478bd9Sstevel@tonic-gate 			 */
13557417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_SYSC) {
13567417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_ASYSC);
13577417cfdeSKuriakose Kuruvilla 			}
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 			/*
13607c478bd9Sstevel@tonic-gate 			 * While we're thinking about system calls, note
13617c478bd9Sstevel@tonic-gate 			 * that AMD processors don't support sysenter
13627c478bd9Sstevel@tonic-gate 			 * in long mode at all, so don't try to program them.
13637c478bd9Sstevel@tonic-gate 			 */
13647417cfdeSKuriakose Kuruvilla 			if (x86_vendor == X86_VENDOR_AMD) {
13657417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_SEP);
13667417cfdeSKuriakose Kuruvilla 			}
13677c478bd9Sstevel@tonic-gate #endif
13687417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_TSCP) {
13697417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_TSCP);
13707417cfdeSKuriakose Kuruvilla 			}
13717c478bd9Sstevel@tonic-gate 			break;
13727c478bd9Sstevel@tonic-gate 		default:
13737c478bd9Sstevel@tonic-gate 			break;
13747c478bd9Sstevel@tonic-gate 		}
13757c478bd9Sstevel@tonic-gate 
13768949bcd6Sandrei 		/*
13778949bcd6Sandrei 		 * Get CPUID data about processor cores and hyperthreads.
13788949bcd6Sandrei 		 */
13797c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
13807c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
13818949bcd6Sandrei 			if (cpi->cpi_maxeax >= 4) {
13828949bcd6Sandrei 				cp = &cpi->cpi_std[4];
13838949bcd6Sandrei 				cp->cp_eax = 4;
13848949bcd6Sandrei 				cp->cp_ecx = 0;
13858949bcd6Sandrei 				(void) __cpuid_insn(cp);
1386ae115bc7Smrj 				platform_cpuid_mangle(cpi->cpi_vendor, 4, cp);
13878949bcd6Sandrei 			}
13888949bcd6Sandrei 			/*FALLTHROUGH*/
13897c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
13907c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000008)
13917c478bd9Sstevel@tonic-gate 				break;
13927c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[8];
13938949bcd6Sandrei 			cp->cp_eax = 0x80000008;
13948949bcd6Sandrei 			(void) __cpuid_insn(cp);
1395ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000008, cp);
1396ae115bc7Smrj 
13977c478bd9Sstevel@tonic-gate 			/*
13987c478bd9Sstevel@tonic-gate 			 * Virtual and physical address limits from
13997c478bd9Sstevel@tonic-gate 			 * cpuid override previously guessed values.
14007c478bd9Sstevel@tonic-gate 			 */
14017c478bd9Sstevel@tonic-gate 			cpi->cpi_pabits = BITX(cp->cp_eax, 7, 0);
14027c478bd9Sstevel@tonic-gate 			cpi->cpi_vabits = BITX(cp->cp_eax, 15, 8);
14037c478bd9Sstevel@tonic-gate 			break;
14047c478bd9Sstevel@tonic-gate 		default:
14057c478bd9Sstevel@tonic-gate 			break;
14067c478bd9Sstevel@tonic-gate 		}
14078949bcd6Sandrei 
1408d129bde2Sesaxe 		/*
1409d129bde2Sesaxe 		 * Derive the number of cores per chip
1410d129bde2Sesaxe 		 */
14118949bcd6Sandrei 		switch (cpi->cpi_vendor) {
14128949bcd6Sandrei 		case X86_VENDOR_Intel:
14138949bcd6Sandrei 			if (cpi->cpi_maxeax < 4) {
14148949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
14158949bcd6Sandrei 				break;
14168949bcd6Sandrei 			} else {
14178949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
14188949bcd6Sandrei 				    BITX((cpi)->cpi_std[4].cp_eax, 31, 26) + 1;
14198949bcd6Sandrei 			}
14208949bcd6Sandrei 			break;
14218949bcd6Sandrei 		case X86_VENDOR_AMD:
14228949bcd6Sandrei 			if (cpi->cpi_xmaxeax < 0x80000008) {
14238949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
14248949bcd6Sandrei 				break;
14258949bcd6Sandrei 			} else {
142610569901Sgavinm 				/*
142710569901Sgavinm 				 * On family 0xf cpuid fn 2 ECX[7:0] "NC" is
142810569901Sgavinm 				 * 1 less than the number of physical cores on
142910569901Sgavinm 				 * the chip.  In family 0x10 this value can
143010569901Sgavinm 				 * be affected by "downcoring" - it reflects
143110569901Sgavinm 				 * 1 less than the number of cores actually
143210569901Sgavinm 				 * enabled on this node.
143310569901Sgavinm 				 */
14348949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
14358949bcd6Sandrei 				    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
14368949bcd6Sandrei 			}
14378949bcd6Sandrei 			break;
14388949bcd6Sandrei 		default:
14398949bcd6Sandrei 			cpi->cpi_ncore_per_chip = 1;
14408949bcd6Sandrei 			break;
14417c478bd9Sstevel@tonic-gate 		}
14420e751525SEric Saxe 
14430e751525SEric Saxe 		/*
14440e751525SEric Saxe 		 * Get CPUID data about TSC Invariance in Deep C-State.
14450e751525SEric Saxe 		 */
14460e751525SEric Saxe 		switch (cpi->cpi_vendor) {
14470e751525SEric Saxe 		case X86_VENDOR_Intel:
14480e751525SEric Saxe 			if (cpi->cpi_maxeax >= 7) {
14490e751525SEric Saxe 				cp = &cpi->cpi_extd[7];
14500e751525SEric Saxe 				cp->cp_eax = 0x80000007;
14510e751525SEric Saxe 				cp->cp_ecx = 0;
14520e751525SEric Saxe 				(void) __cpuid_insn(cp);
14530e751525SEric Saxe 			}
14540e751525SEric Saxe 			break;
14550e751525SEric Saxe 		default:
14560e751525SEric Saxe 			break;
14570e751525SEric Saxe 		}
1458fa2e767eSgavinm 	} else {
1459fa2e767eSgavinm 		cpi->cpi_ncore_per_chip = 1;
14608949bcd6Sandrei 	}
14618949bcd6Sandrei 
14628949bcd6Sandrei 	/*
14638949bcd6Sandrei 	 * If more than one core, then this processor is CMP.
14648949bcd6Sandrei 	 */
14657417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncore_per_chip > 1) {
14667417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMP);
14677417cfdeSKuriakose Kuruvilla 	}
1468ae115bc7Smrj 
14698949bcd6Sandrei 	/*
14708949bcd6Sandrei 	 * If the number of cores is the same as the number
14718949bcd6Sandrei 	 * of CPUs, then we cannot have HyperThreading.
14728949bcd6Sandrei 	 */
14737417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncpu_per_chip == cpi->cpi_ncore_per_chip) {
14747417cfdeSKuriakose Kuruvilla 		remove_x86_feature(featureset, X86FSET_HTT);
14757417cfdeSKuriakose Kuruvilla 	}
14768949bcd6Sandrei 
14778031591dSSrihari Venkatesan 	cpi->cpi_apicid = CPI_APIC_ID(cpi);
14788031591dSSrihari Venkatesan 	cpi->cpi_procnodes_per_pkg = 1;
14797417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE &&
14807417cfdeSKuriakose Kuruvilla 	    is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) {
14818949bcd6Sandrei 		/*
14828949bcd6Sandrei 		 * Single-core single-threaded processors.
14838949bcd6Sandrei 		 */
14847c478bd9Sstevel@tonic-gate 		cpi->cpi_chipid = -1;
14857c478bd9Sstevel@tonic-gate 		cpi->cpi_clogid = 0;
14868949bcd6Sandrei 		cpi->cpi_coreid = cpu->cpu_id;
148710569901Sgavinm 		cpi->cpi_pkgcoreid = 0;
14888031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_AMD)
14898031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 3, 0);
14908031591dSSrihari Venkatesan 		else
14918031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
14927c478bd9Sstevel@tonic-gate 	} else if (cpi->cpi_ncpu_per_chip > 1) {
14938031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_Intel)
14947417cfdeSKuriakose Kuruvilla 			cpuid_intel_getids(cpu, featureset);
14958031591dSSrihari Venkatesan 		else if (cpi->cpi_vendor == X86_VENDOR_AMD)
14968031591dSSrihari Venkatesan 			cpuid_amd_getids(cpu);
14978031591dSSrihari Venkatesan 		else {
14988949bcd6Sandrei 			/*
14998949bcd6Sandrei 			 * All other processors are currently
15008949bcd6Sandrei 			 * assumed to have single cores.
15018949bcd6Sandrei 			 */
15028949bcd6Sandrei 			cpi->cpi_coreid = cpi->cpi_chipid;
150310569901Sgavinm 			cpi->cpi_pkgcoreid = 0;
15048031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
15058949bcd6Sandrei 		}
15067c478bd9Sstevel@tonic-gate 	}
15077c478bd9Sstevel@tonic-gate 
15088a40a695Sgavinm 	/*
15098a40a695Sgavinm 	 * Synthesize chip "revision" and socket type
15108a40a695Sgavinm 	 */
1511e4b86885SCheng Sean Ye 	cpi->cpi_chiprev = _cpuid_chiprev(cpi->cpi_vendor, cpi->cpi_family,
1512e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
1513e4b86885SCheng Sean Ye 	cpi->cpi_chiprevstr = _cpuid_chiprevstr(cpi->cpi_vendor,
1514e4b86885SCheng Sean Ye 	    cpi->cpi_family, cpi->cpi_model, cpi->cpi_step);
1515e4b86885SCheng Sean Ye 	cpi->cpi_socket = _cpuid_skt(cpi->cpi_vendor, cpi->cpi_family,
1516e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
15178a40a695Sgavinm 
15187c478bd9Sstevel@tonic-gate pass1_done:
15197c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 1;
15207417cfdeSKuriakose Kuruvilla 	return (featureset);
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate /*
15247c478bd9Sstevel@tonic-gate  * Make copies of the cpuid table entries we depend on, in
15257c478bd9Sstevel@tonic-gate  * part for ease of parsing now, in part so that we have only
15267c478bd9Sstevel@tonic-gate  * one place to correct any of it, in part for ease of
15277c478bd9Sstevel@tonic-gate  * later export to userland, and in part so we can look at
15287c478bd9Sstevel@tonic-gate  * this stuff in a crash dump.
15297c478bd9Sstevel@tonic-gate  */
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15327c478bd9Sstevel@tonic-gate void
15337c478bd9Sstevel@tonic-gate cpuid_pass2(cpu_t *cpu)
15347c478bd9Sstevel@tonic-gate {
15357c478bd9Sstevel@tonic-gate 	uint_t n, nmax;
15367c478bd9Sstevel@tonic-gate 	int i;
15378949bcd6Sandrei 	struct cpuid_regs *cp;
15387c478bd9Sstevel@tonic-gate 	uint8_t *dp;
15397c478bd9Sstevel@tonic-gate 	uint32_t *iptr;
15407c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 1);
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
15457c478bd9Sstevel@tonic-gate 		goto pass2_done;
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_maxeax + 1) > NMAX_CPI_STD)
15487c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_STD;
15497c478bd9Sstevel@tonic-gate 	/*
15507c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
15517c478bd9Sstevel@tonic-gate 	 */
15527c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_std[2]; n < nmax; n++, cp++) {
15538949bcd6Sandrei 		cp->cp_eax = n;
1554d129bde2Sesaxe 
1555d129bde2Sesaxe 		/*
1556d129bde2Sesaxe 		 * CPUID function 4 expects %ecx to be initialized
1557d129bde2Sesaxe 		 * with an index which indicates which cache to return
1558d129bde2Sesaxe 		 * information about. The OS is expected to call function 4
1559d129bde2Sesaxe 		 * with %ecx set to 0, 1, 2, ... until it returns with
1560d129bde2Sesaxe 		 * EAX[4:0] set to 0, which indicates there are no more
1561d129bde2Sesaxe 		 * caches.
1562d129bde2Sesaxe 		 *
1563d129bde2Sesaxe 		 * Here, populate cpi_std[4] with the information returned by
1564d129bde2Sesaxe 		 * function 4 when %ecx == 0, and do the rest in cpuid_pass3()
1565d129bde2Sesaxe 		 * when dynamic memory allocation becomes available.
1566d129bde2Sesaxe 		 *
1567d129bde2Sesaxe 		 * Note: we need to explicitly initialize %ecx here, since
1568d129bde2Sesaxe 		 * function 4 may have been previously invoked.
1569d129bde2Sesaxe 		 */
1570d129bde2Sesaxe 		if (n == 4)
1571d129bde2Sesaxe 			cp->cp_ecx = 0;
1572d129bde2Sesaxe 
15738949bcd6Sandrei 		(void) __cpuid_insn(cp);
1574ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, n, cp);
15757c478bd9Sstevel@tonic-gate 		switch (n) {
15767c478bd9Sstevel@tonic-gate 		case 2:
15777c478bd9Sstevel@tonic-gate 			/*
15787c478bd9Sstevel@tonic-gate 			 * "the lower 8 bits of the %eax register
15797c478bd9Sstevel@tonic-gate 			 * contain a value that identifies the number
15807c478bd9Sstevel@tonic-gate 			 * of times the cpuid [instruction] has to be
15817c478bd9Sstevel@tonic-gate 			 * executed to obtain a complete image of the
15827c478bd9Sstevel@tonic-gate 			 * processor's caching systems."
15837c478bd9Sstevel@tonic-gate 			 *
15847c478bd9Sstevel@tonic-gate 			 * How *do* they make this stuff up?
15857c478bd9Sstevel@tonic-gate 			 */
15867c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache = sizeof (*cp) *
15877c478bd9Sstevel@tonic-gate 			    BITX(cp->cp_eax, 7, 0);
15887c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache == 0)
15897c478bd9Sstevel@tonic-gate 				break;
15907c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache--;	/* skip count byte */
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 			/*
15937c478bd9Sstevel@tonic-gate 			 * Well, for now, rather than attempt to implement
15947c478bd9Sstevel@tonic-gate 			 * this slightly dubious algorithm, we just look
15957c478bd9Sstevel@tonic-gate 			 * at the first 15 ..
15967c478bd9Sstevel@tonic-gate 			 */
15977c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache > (sizeof (*cp) - 1))
15987c478bd9Sstevel@tonic-gate 				cpi->cpi_ncache = sizeof (*cp) - 1;
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 			dp = cpi->cpi_cacheinfo;
16017c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_eax, 31, 31) == 0) {
16027c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_eax;
160363d3f7dfSkk208521 				for (i = 1; i < 4; i++)
16047c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16057c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16067c478bd9Sstevel@tonic-gate 			}
16077c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ebx, 31, 31) == 0) {
16087c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ebx;
16097c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
16107c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16117c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16127c478bd9Sstevel@tonic-gate 			}
16137c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ecx, 31, 31) == 0) {
16147c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ecx;
16157c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
16167c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16177c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16187c478bd9Sstevel@tonic-gate 			}
16197c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_edx, 31, 31) == 0) {
16207c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_edx;
16217c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
16227c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16237c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16247c478bd9Sstevel@tonic-gate 			}
16257c478bd9Sstevel@tonic-gate 			break;
1626f98fbcecSbholler 
16277c478bd9Sstevel@tonic-gate 		case 3:	/* Processor serial number, if PSN supported */
1628f98fbcecSbholler 			break;
1629f98fbcecSbholler 
16307c478bd9Sstevel@tonic-gate 		case 4:	/* Deterministic cache parameters */
1631f98fbcecSbholler 			break;
1632f98fbcecSbholler 
16337c478bd9Sstevel@tonic-gate 		case 5:	/* Monitor/Mwait parameters */
16345b8a6efeSbholler 		{
16355b8a6efeSbholler 			size_t mwait_size;
1636f98fbcecSbholler 
1637f98fbcecSbholler 			/*
1638f98fbcecSbholler 			 * check cpi_mwait.support which was set in cpuid_pass1
1639f98fbcecSbholler 			 */
1640f98fbcecSbholler 			if (!(cpi->cpi_mwait.support & MWAIT_SUPPORT))
1641f98fbcecSbholler 				break;
1642f98fbcecSbholler 
16435b8a6efeSbholler 			/*
16445b8a6efeSbholler 			 * Protect ourself from insane mwait line size.
16455b8a6efeSbholler 			 * Workaround for incomplete hardware emulator(s).
16465b8a6efeSbholler 			 */
16475b8a6efeSbholler 			mwait_size = (size_t)MWAIT_SIZE_MAX(cpi);
16485b8a6efeSbholler 			if (mwait_size < sizeof (uint32_t) ||
16495b8a6efeSbholler 			    !ISP2(mwait_size)) {
16505b8a6efeSbholler #if DEBUG
16515b8a6efeSbholler 				cmn_err(CE_NOTE, "Cannot handle cpu %d mwait "
16525d8efbbcSSaurabh Misra 				    "size %ld", cpu->cpu_id, (long)mwait_size);
16535b8a6efeSbholler #endif
16545b8a6efeSbholler 				break;
16555b8a6efeSbholler 			}
16565b8a6efeSbholler 
1657f98fbcecSbholler 			cpi->cpi_mwait.mon_min = (size_t)MWAIT_SIZE_MIN(cpi);
16585b8a6efeSbholler 			cpi->cpi_mwait.mon_max = mwait_size;
1659f98fbcecSbholler 			if (MWAIT_EXTENSION(cpi)) {
1660f98fbcecSbholler 				cpi->cpi_mwait.support |= MWAIT_EXTENSIONS;
1661f98fbcecSbholler 				if (MWAIT_INT_ENABLE(cpi))
1662f98fbcecSbholler 					cpi->cpi_mwait.support |=
1663f98fbcecSbholler 					    MWAIT_ECX_INT_ENABLE;
1664f98fbcecSbholler 			}
1665f98fbcecSbholler 			break;
16665b8a6efeSbholler 		}
16677c478bd9Sstevel@tonic-gate 		default:
16687c478bd9Sstevel@tonic-gate 			break;
16697c478bd9Sstevel@tonic-gate 		}
16707c478bd9Sstevel@tonic-gate 	}
16717c478bd9Sstevel@tonic-gate 
1672b6917abeSmishra 	if (cpi->cpi_maxeax >= 0xB && cpi->cpi_vendor == X86_VENDOR_Intel) {
16735d8efbbcSSaurabh Misra 		struct cpuid_regs regs;
16745d8efbbcSSaurabh Misra 
16755d8efbbcSSaurabh Misra 		cp = &regs;
1676b6917abeSmishra 		cp->cp_eax = 0xB;
16775d8efbbcSSaurabh Misra 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
1678b6917abeSmishra 
1679b6917abeSmishra 		(void) __cpuid_insn(cp);
1680b6917abeSmishra 
1681b6917abeSmishra 		/*
1682b6917abeSmishra 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
1683b6917abeSmishra 		 * indicates that the extended topology enumeration leaf is
1684b6917abeSmishra 		 * available.
1685b6917abeSmishra 		 */
1686b6917abeSmishra 		if (cp->cp_ebx) {
1687b6917abeSmishra 			uint32_t x2apic_id;
1688b6917abeSmishra 			uint_t coreid_shift = 0;
1689b6917abeSmishra 			uint_t ncpu_per_core = 1;
1690b6917abeSmishra 			uint_t chipid_shift = 0;
1691b6917abeSmishra 			uint_t ncpu_per_chip = 1;
1692b6917abeSmishra 			uint_t i;
1693b6917abeSmishra 			uint_t level;
1694b6917abeSmishra 
1695b6917abeSmishra 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
1696b6917abeSmishra 				cp->cp_eax = 0xB;
1697b6917abeSmishra 				cp->cp_ecx = i;
1698b6917abeSmishra 
1699b6917abeSmishra 				(void) __cpuid_insn(cp);
1700b6917abeSmishra 				level = CPI_CPU_LEVEL_TYPE(cp);
1701b6917abeSmishra 
1702b6917abeSmishra 				if (level == 1) {
1703b6917abeSmishra 					x2apic_id = cp->cp_edx;
1704b6917abeSmishra 					coreid_shift = BITX(cp->cp_eax, 4, 0);
1705b6917abeSmishra 					ncpu_per_core = BITX(cp->cp_ebx, 15, 0);
1706b6917abeSmishra 				} else if (level == 2) {
1707b6917abeSmishra 					x2apic_id = cp->cp_edx;
1708b6917abeSmishra 					chipid_shift = BITX(cp->cp_eax, 4, 0);
1709b6917abeSmishra 					ncpu_per_chip = BITX(cp->cp_ebx, 15, 0);
1710b6917abeSmishra 				}
1711b6917abeSmishra 			}
1712b6917abeSmishra 
1713b6917abeSmishra 			cpi->cpi_apicid = x2apic_id;
1714b6917abeSmishra 			cpi->cpi_ncpu_per_chip = ncpu_per_chip;
1715b6917abeSmishra 			cpi->cpi_ncore_per_chip = ncpu_per_chip /
1716b6917abeSmishra 			    ncpu_per_core;
1717b6917abeSmishra 			cpi->cpi_chipid = x2apic_id >> chipid_shift;
1718b6917abeSmishra 			cpi->cpi_clogid = x2apic_id & ((1 << chipid_shift) - 1);
1719b6917abeSmishra 			cpi->cpi_coreid = x2apic_id >> coreid_shift;
1720b6917abeSmishra 			cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
1721b6917abeSmishra 		}
17225d8efbbcSSaurabh Misra 
17235d8efbbcSSaurabh Misra 		/* Make cp NULL so that we don't stumble on others */
17245d8efbbcSSaurabh Misra 		cp = NULL;
1725b6917abeSmishra 	}
1726b6917abeSmishra 
17277c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0)
17287c478bd9Sstevel@tonic-gate 		goto pass2_done;
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_xmaxeax - 0x80000000 + 1) > NMAX_CPI_EXTD)
17317c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_EXTD;
17327c478bd9Sstevel@tonic-gate 	/*
17337c478bd9Sstevel@tonic-gate 	 * Copy the extended properties, fixing them as we go.
17347c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
17357c478bd9Sstevel@tonic-gate 	 */
17367c478bd9Sstevel@tonic-gate 	iptr = (void *)cpi->cpi_brandstr;
17377c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_extd[2]; n < nmax; cp++, n++) {
17388949bcd6Sandrei 		cp->cp_eax = 0x80000000 + n;
17398949bcd6Sandrei 		(void) __cpuid_insn(cp);
1740ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, 0x80000000 + n, cp);
17417c478bd9Sstevel@tonic-gate 		switch (n) {
17427c478bd9Sstevel@tonic-gate 		case 2:
17437c478bd9Sstevel@tonic-gate 		case 3:
17447c478bd9Sstevel@tonic-gate 		case 4:
17457c478bd9Sstevel@tonic-gate 			/*
17467c478bd9Sstevel@tonic-gate 			 * Extract the brand string
17477c478bd9Sstevel@tonic-gate 			 */
17487c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_eax;
17497c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ebx;
17507c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ecx;
17517c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_edx;
17527c478bd9Sstevel@tonic-gate 			break;
17537c478bd9Sstevel@tonic-gate 		case 5:
17547c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
17557c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
17567c478bd9Sstevel@tonic-gate 				/*
17577c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
17587c478bd9Sstevel@tonic-gate 				 * parts to report the sizes of the
17597c478bd9Sstevel@tonic-gate 				 * TLB for large pages. Before then,
17607c478bd9Sstevel@tonic-gate 				 * we don't trust the data.
17617c478bd9Sstevel@tonic-gate 				 */
17627c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
17637c478bd9Sstevel@tonic-gate 				    (cpi->cpi_family == 6 &&
17647c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1))
17657c478bd9Sstevel@tonic-gate 					cp->cp_eax = 0;
17667c478bd9Sstevel@tonic-gate 				break;
17677c478bd9Sstevel@tonic-gate 			default:
17687c478bd9Sstevel@tonic-gate 				break;
17697c478bd9Sstevel@tonic-gate 			}
17707c478bd9Sstevel@tonic-gate 			break;
17717c478bd9Sstevel@tonic-gate 		case 6:
17727c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
17737c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
17747c478bd9Sstevel@tonic-gate 				/*
17757c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
17767c478bd9Sstevel@tonic-gate 				 * AMD parts with L2 TLB's.
17777c478bd9Sstevel@tonic-gate 				 * Before then, don't trust the data.
17787c478bd9Sstevel@tonic-gate 				 */
17797c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
17807c478bd9Sstevel@tonic-gate 				    cpi->cpi_family == 6 &&
17817c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1)
17827c478bd9Sstevel@tonic-gate 					cp->cp_eax = cp->cp_ebx = 0;
17837c478bd9Sstevel@tonic-gate 				/*
17847c478bd9Sstevel@tonic-gate 				 * AMD Duron rev A0 reports L2
17857c478bd9Sstevel@tonic-gate 				 * cache size incorrectly as 1K
17867c478bd9Sstevel@tonic-gate 				 * when it is really 64K
17877c478bd9Sstevel@tonic-gate 				 */
17887c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family == 6 &&
17897c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 3 &&
17907c478bd9Sstevel@tonic-gate 				    cpi->cpi_step == 0) {
17917c478bd9Sstevel@tonic-gate 					cp->cp_ecx &= 0xffff;
17927c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 0x400000;
17937c478bd9Sstevel@tonic-gate 				}
17947c478bd9Sstevel@tonic-gate 				break;
17957c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Cyrix:	/* VIA C3 */
17967c478bd9Sstevel@tonic-gate 				/*
17977c478bd9Sstevel@tonic-gate 				 * VIA C3 processors are a bit messed
17987c478bd9Sstevel@tonic-gate 				 * up w.r.t. encoding cache sizes in %ecx
17997c478bd9Sstevel@tonic-gate 				 */
18007c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family != 6)
18017c478bd9Sstevel@tonic-gate 					break;
18027c478bd9Sstevel@tonic-gate 				/*
18037c478bd9Sstevel@tonic-gate 				 * model 7 and 8 were incorrectly encoded
18047c478bd9Sstevel@tonic-gate 				 *
18057c478bd9Sstevel@tonic-gate 				 * xxx is model 8 really broken?
18067c478bd9Sstevel@tonic-gate 				 */
18077c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 7 ||
18087c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 8)
18097c478bd9Sstevel@tonic-gate 					cp->cp_ecx =
18107c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 31, 24) << 16 |
18117c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 23, 16) << 12 |
18127c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 15, 8) << 8 |
18137c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 7, 0);
18147c478bd9Sstevel@tonic-gate 				/*
18157c478bd9Sstevel@tonic-gate 				 * model 9 stepping 1 has wrong associativity
18167c478bd9Sstevel@tonic-gate 				 */
18177c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 9 && cpi->cpi_step == 1)
18187c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 8 << 12;
18197c478bd9Sstevel@tonic-gate 				break;
18207c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Intel:
18217c478bd9Sstevel@tonic-gate 				/*
18227c478bd9Sstevel@tonic-gate 				 * Extended L2 Cache features function.
18237c478bd9Sstevel@tonic-gate 				 * First appeared on Prescott.
18247c478bd9Sstevel@tonic-gate 				 */
18257c478bd9Sstevel@tonic-gate 			default:
18267c478bd9Sstevel@tonic-gate 				break;
18277c478bd9Sstevel@tonic-gate 			}
18287c478bd9Sstevel@tonic-gate 			break;
18297c478bd9Sstevel@tonic-gate 		default:
18307c478bd9Sstevel@tonic-gate 			break;
18317c478bd9Sstevel@tonic-gate 		}
18327c478bd9Sstevel@tonic-gate 	}
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate pass2_done:
18357c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 2;
18367c478bd9Sstevel@tonic-gate }
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate static const char *
18397c478bd9Sstevel@tonic-gate intel_cpubrand(const struct cpuid_info *cpi)
18407c478bd9Sstevel@tonic-gate {
18417c478bd9Sstevel@tonic-gate 	int i;
18427c478bd9Sstevel@tonic-gate 
18437417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
18447c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
18457c478bd9Sstevel@tonic-gate 		return ("i486");
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
18487c478bd9Sstevel@tonic-gate 	case 5:
18497c478bd9Sstevel@tonic-gate 		return ("Intel Pentium(r)");
18507c478bd9Sstevel@tonic-gate 	case 6:
18517c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
18527c478bd9Sstevel@tonic-gate 			uint_t celeron, xeon;
18538949bcd6Sandrei 			const struct cpuid_regs *cp;
18547c478bd9Sstevel@tonic-gate 		case 0:
18557c478bd9Sstevel@tonic-gate 		case 1:
18567c478bd9Sstevel@tonic-gate 		case 2:
18577c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) Pro");
18587c478bd9Sstevel@tonic-gate 		case 3:
18597c478bd9Sstevel@tonic-gate 		case 4:
18607c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) II");
18617c478bd9Sstevel@tonic-gate 		case 6:
18627c478bd9Sstevel@tonic-gate 			return ("Intel Celeron(r)");
18637c478bd9Sstevel@tonic-gate 		case 5:
18647c478bd9Sstevel@tonic-gate 		case 7:
18657c478bd9Sstevel@tonic-gate 			celeron = xeon = 0;
18667c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_std[2];	/* cache info */
18677c478bd9Sstevel@tonic-gate 
186863d3f7dfSkk208521 			for (i = 1; i < 4; i++) {
18697c478bd9Sstevel@tonic-gate 				uint_t tmp;
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_eax >> (8 * i)) & 0xff;
18727c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
18737c478bd9Sstevel@tonic-gate 					celeron++;
18747c478bd9Sstevel@tonic-gate 				if (tmp >= 0x44 && tmp <= 0x45)
18757c478bd9Sstevel@tonic-gate 					xeon++;
18767c478bd9Sstevel@tonic-gate 			}
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 			for (i = 0; i < 2; i++) {
18797c478bd9Sstevel@tonic-gate 				uint_t tmp;
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ebx >> (8 * i)) & 0xff;
18827c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
18837c478bd9Sstevel@tonic-gate 					celeron++;
18847c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
18857c478bd9Sstevel@tonic-gate 					xeon++;
18867c478bd9Sstevel@tonic-gate 			}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
18897c478bd9Sstevel@tonic-gate 				uint_t tmp;
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ecx >> (8 * i)) & 0xff;
18927c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
18937c478bd9Sstevel@tonic-gate 					celeron++;
18947c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
18957c478bd9Sstevel@tonic-gate 					xeon++;
18967c478bd9Sstevel@tonic-gate 			}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
18997c478bd9Sstevel@tonic-gate 				uint_t tmp;
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_edx >> (8 * i)) & 0xff;
19027c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
19037c478bd9Sstevel@tonic-gate 					celeron++;
19047c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
19057c478bd9Sstevel@tonic-gate 					xeon++;
19067c478bd9Sstevel@tonic-gate 			}
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 			if (celeron)
19097c478bd9Sstevel@tonic-gate 				return ("Intel Celeron(r)");
19107c478bd9Sstevel@tonic-gate 			if (xeon)
19117c478bd9Sstevel@tonic-gate 				return (cpi->cpi_model == 5 ?
19127c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) II Xeon(tm)" :
19137c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) III Xeon(tm)");
19147c478bd9Sstevel@tonic-gate 			return (cpi->cpi_model == 5 ?
19157c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) II or Pentium(r) II Xeon(tm)" :
19167c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) III or Pentium(r) III Xeon(tm)");
19177c478bd9Sstevel@tonic-gate 		default:
19187c478bd9Sstevel@tonic-gate 			break;
19197c478bd9Sstevel@tonic-gate 		}
19207c478bd9Sstevel@tonic-gate 	default:
19217c478bd9Sstevel@tonic-gate 		break;
19227c478bd9Sstevel@tonic-gate 	}
19237c478bd9Sstevel@tonic-gate 
19245ff02082Sdmick 	/* BrandID is present if the field is nonzero */
19255ff02082Sdmick 	if (cpi->cpi_brandid != 0) {
19267c478bd9Sstevel@tonic-gate 		static const struct {
19277c478bd9Sstevel@tonic-gate 			uint_t bt_bid;
19287c478bd9Sstevel@tonic-gate 			const char *bt_str;
19297c478bd9Sstevel@tonic-gate 		} brand_tbl[] = {
19307c478bd9Sstevel@tonic-gate 			{ 0x1,	"Intel(r) Celeron(r)" },
19317c478bd9Sstevel@tonic-gate 			{ 0x2,	"Intel(r) Pentium(r) III" },
19327c478bd9Sstevel@tonic-gate 			{ 0x3,	"Intel(r) Pentium(r) III Xeon(tm)" },
19337c478bd9Sstevel@tonic-gate 			{ 0x4,	"Intel(r) Pentium(r) III" },
19347c478bd9Sstevel@tonic-gate 			{ 0x6,	"Mobile Intel(r) Pentium(r) III" },
19357c478bd9Sstevel@tonic-gate 			{ 0x7,	"Mobile Intel(r) Celeron(r)" },
19367c478bd9Sstevel@tonic-gate 			{ 0x8,	"Intel(r) Pentium(r) 4" },
19377c478bd9Sstevel@tonic-gate 			{ 0x9,	"Intel(r) Pentium(r) 4" },
19387c478bd9Sstevel@tonic-gate 			{ 0xa,	"Intel(r) Celeron(r)" },
19397c478bd9Sstevel@tonic-gate 			{ 0xb,	"Intel(r) Xeon(tm)" },
19407c478bd9Sstevel@tonic-gate 			{ 0xc,	"Intel(r) Xeon(tm) MP" },
19417c478bd9Sstevel@tonic-gate 			{ 0xe,	"Mobile Intel(r) Pentium(r) 4" },
19425ff02082Sdmick 			{ 0xf,	"Mobile Intel(r) Celeron(r)" },
19435ff02082Sdmick 			{ 0x11, "Mobile Genuine Intel(r)" },
19445ff02082Sdmick 			{ 0x12, "Intel(r) Celeron(r) M" },
19455ff02082Sdmick 			{ 0x13, "Mobile Intel(r) Celeron(r)" },
19465ff02082Sdmick 			{ 0x14, "Intel(r) Celeron(r)" },
19475ff02082Sdmick 			{ 0x15, "Mobile Genuine Intel(r)" },
19485ff02082Sdmick 			{ 0x16,	"Intel(r) Pentium(r) M" },
19495ff02082Sdmick 			{ 0x17, "Mobile Intel(r) Celeron(r)" }
19507c478bd9Sstevel@tonic-gate 		};
19517c478bd9Sstevel@tonic-gate 		uint_t btblmax = sizeof (brand_tbl) / sizeof (brand_tbl[0]);
19527c478bd9Sstevel@tonic-gate 		uint_t sgn;
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 		sgn = (cpi->cpi_family << 8) |
19557c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model << 4) | cpi->cpi_step;
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 		for (i = 0; i < btblmax; i++)
19587c478bd9Sstevel@tonic-gate 			if (brand_tbl[i].bt_bid == cpi->cpi_brandid)
19597c478bd9Sstevel@tonic-gate 				break;
19607c478bd9Sstevel@tonic-gate 		if (i < btblmax) {
19617c478bd9Sstevel@tonic-gate 			if (sgn == 0x6b1 && cpi->cpi_brandid == 3)
19627c478bd9Sstevel@tonic-gate 				return ("Intel(r) Celeron(r)");
19637c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xb)
19647c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm) MP");
19657c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xe)
19667c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm)");
19677c478bd9Sstevel@tonic-gate 			return (brand_tbl[i].bt_str);
19687c478bd9Sstevel@tonic-gate 		}
19697c478bd9Sstevel@tonic-gate 	}
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	return (NULL);
19727c478bd9Sstevel@tonic-gate }
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate static const char *
19757c478bd9Sstevel@tonic-gate amd_cpubrand(const struct cpuid_info *cpi)
19767c478bd9Sstevel@tonic-gate {
19777417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
19787c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
19797c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
19827c478bd9Sstevel@tonic-gate 	case 5:
19837c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
19847c478bd9Sstevel@tonic-gate 		case 0:
19857c478bd9Sstevel@tonic-gate 		case 1:
19867c478bd9Sstevel@tonic-gate 		case 2:
19877c478bd9Sstevel@tonic-gate 		case 3:
19887c478bd9Sstevel@tonic-gate 		case 4:
19897c478bd9Sstevel@tonic-gate 		case 5:
19907c478bd9Sstevel@tonic-gate 			return ("AMD-K5(r)");
19917c478bd9Sstevel@tonic-gate 		case 6:
19927c478bd9Sstevel@tonic-gate 		case 7:
19937c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)");
19947c478bd9Sstevel@tonic-gate 		case 8:
19957c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-2");
19967c478bd9Sstevel@tonic-gate 		case 9:
19977c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-III");
19987c478bd9Sstevel@tonic-gate 		default:
19997c478bd9Sstevel@tonic-gate 			return ("AMD (family 5)");
20007c478bd9Sstevel@tonic-gate 		}
20017c478bd9Sstevel@tonic-gate 	case 6:
20027c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
20037c478bd9Sstevel@tonic-gate 		case 1:
20047c478bd9Sstevel@tonic-gate 			return ("AMD-K7(tm)");
20057c478bd9Sstevel@tonic-gate 		case 0:
20067c478bd9Sstevel@tonic-gate 		case 2:
20077c478bd9Sstevel@tonic-gate 		case 4:
20087c478bd9Sstevel@tonic-gate 			return ("AMD Athlon(tm)");
20097c478bd9Sstevel@tonic-gate 		case 3:
20107c478bd9Sstevel@tonic-gate 		case 7:
20117c478bd9Sstevel@tonic-gate 			return ("AMD Duron(tm)");
20127c478bd9Sstevel@tonic-gate 		case 6:
20137c478bd9Sstevel@tonic-gate 		case 8:
20147c478bd9Sstevel@tonic-gate 		case 10:
20157c478bd9Sstevel@tonic-gate 			/*
20167c478bd9Sstevel@tonic-gate 			 * Use the L2 cache size to distinguish
20177c478bd9Sstevel@tonic-gate 			 */
20187c478bd9Sstevel@tonic-gate 			return ((cpi->cpi_extd[6].cp_ecx >> 16) >= 256 ?
20197c478bd9Sstevel@tonic-gate 			    "AMD Athlon(tm)" : "AMD Duron(tm)");
20207c478bd9Sstevel@tonic-gate 		default:
20217c478bd9Sstevel@tonic-gate 			return ("AMD (family 6)");
20227c478bd9Sstevel@tonic-gate 		}
20237c478bd9Sstevel@tonic-gate 	default:
20247c478bd9Sstevel@tonic-gate 		break;
20257c478bd9Sstevel@tonic-gate 	}
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 	if (cpi->cpi_family == 0xf && cpi->cpi_model == 5 &&
20287c478bd9Sstevel@tonic-gate 	    cpi->cpi_brandid != 0) {
20297c478bd9Sstevel@tonic-gate 		switch (BITX(cpi->cpi_brandid, 7, 5)) {
20307c478bd9Sstevel@tonic-gate 		case 3:
20317c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) UP 1xx");
20327c478bd9Sstevel@tonic-gate 		case 4:
20337c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) DP 2xx");
20347c478bd9Sstevel@tonic-gate 		case 5:
20357c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) MP 8xx");
20367c478bd9Sstevel@tonic-gate 		default:
20377c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm)");
20387c478bd9Sstevel@tonic-gate 		}
20397c478bd9Sstevel@tonic-gate 	}
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 	return (NULL);
20427c478bd9Sstevel@tonic-gate }
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate static const char *
20457c478bd9Sstevel@tonic-gate cyrix_cpubrand(struct cpuid_info *cpi, uint_t type)
20467c478bd9Sstevel@tonic-gate {
20477417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
20487c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5 ||
20497c478bd9Sstevel@tonic-gate 	    type == X86_TYPE_CYRIX_486)
20507c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	switch (type) {
20537c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86:
20547c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86");
20557c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86L:
20567c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86L");
20577c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86MX:
20587c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86MX");
20597c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_GXm:
20607c478bd9Sstevel@tonic-gate 		return ("Cyrix GXm");
20617c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MediaGX:
20627c478bd9Sstevel@tonic-gate 		return ("Cyrix MediaGX");
20637c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MII:
20647c478bd9Sstevel@tonic-gate 		return ("Cyrix M2");
20657c478bd9Sstevel@tonic-gate 	case X86_TYPE_VIA_CYRIX_III:
20667c478bd9Sstevel@tonic-gate 		return ("VIA Cyrix M3");
20677c478bd9Sstevel@tonic-gate 	default:
20687c478bd9Sstevel@tonic-gate 		/*
20697c478bd9Sstevel@tonic-gate 		 * Have another wild guess ..
20707c478bd9Sstevel@tonic-gate 		 */
20717c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 4 && cpi->cpi_model == 9)
20727c478bd9Sstevel@tonic-gate 			return ("Cyrix 5x86");
20737c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_family == 5) {
20747c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
20757c478bd9Sstevel@tonic-gate 			case 2:
20767c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86");	/* Cyrix M1 */
20777c478bd9Sstevel@tonic-gate 			case 4:
20787c478bd9Sstevel@tonic-gate 				return ("Cyrix MediaGX");
20797c478bd9Sstevel@tonic-gate 			default:
20807c478bd9Sstevel@tonic-gate 				break;
20817c478bd9Sstevel@tonic-gate 			}
20827c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family == 6) {
20837c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
20847c478bd9Sstevel@tonic-gate 			case 0:
20857c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86MX"); /* Cyrix M2? */
20867c478bd9Sstevel@tonic-gate 			case 5:
20877c478bd9Sstevel@tonic-gate 			case 6:
20887c478bd9Sstevel@tonic-gate 			case 7:
20897c478bd9Sstevel@tonic-gate 			case 8:
20907c478bd9Sstevel@tonic-gate 			case 9:
20917c478bd9Sstevel@tonic-gate 				return ("VIA C3");
20927c478bd9Sstevel@tonic-gate 			default:
20937c478bd9Sstevel@tonic-gate 				break;
20947c478bd9Sstevel@tonic-gate 			}
20957c478bd9Sstevel@tonic-gate 		}
20967c478bd9Sstevel@tonic-gate 		break;
20977c478bd9Sstevel@tonic-gate 	}
20987c478bd9Sstevel@tonic-gate 	return (NULL);
20997c478bd9Sstevel@tonic-gate }
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate /*
21027c478bd9Sstevel@tonic-gate  * This only gets called in the case that the CPU extended
21037c478bd9Sstevel@tonic-gate  * feature brand string (0x80000002, 0x80000003, 0x80000004)
21047c478bd9Sstevel@tonic-gate  * aren't available, or contain null bytes for some reason.
21057c478bd9Sstevel@tonic-gate  */
21067c478bd9Sstevel@tonic-gate static void
21077c478bd9Sstevel@tonic-gate fabricate_brandstr(struct cpuid_info *cpi)
21087c478bd9Sstevel@tonic-gate {
21097c478bd9Sstevel@tonic-gate 	const char *brand = NULL;
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
21127c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
21137c478bd9Sstevel@tonic-gate 		brand = intel_cpubrand(cpi);
21147c478bd9Sstevel@tonic-gate 		break;
21157c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
21167c478bd9Sstevel@tonic-gate 		brand = amd_cpubrand(cpi);
21177c478bd9Sstevel@tonic-gate 		break;
21187c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
21197c478bd9Sstevel@tonic-gate 		brand = cyrix_cpubrand(cpi, x86_type);
21207c478bd9Sstevel@tonic-gate 		break;
21217c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NexGen:
21227c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
21237c478bd9Sstevel@tonic-gate 			brand = "NexGen Nx586";
21247c478bd9Sstevel@tonic-gate 		break;
21257c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
21267c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
21277c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
21287c478bd9Sstevel@tonic-gate 			case 4:
21297c478bd9Sstevel@tonic-gate 				brand = "Centaur C6";
21307c478bd9Sstevel@tonic-gate 				break;
21317c478bd9Sstevel@tonic-gate 			case 8:
21327c478bd9Sstevel@tonic-gate 				brand = "Centaur C2";
21337c478bd9Sstevel@tonic-gate 				break;
21347c478bd9Sstevel@tonic-gate 			case 9:
21357c478bd9Sstevel@tonic-gate 				brand = "Centaur C3";
21367c478bd9Sstevel@tonic-gate 				break;
21377c478bd9Sstevel@tonic-gate 			default:
21387c478bd9Sstevel@tonic-gate 				break;
21397c478bd9Sstevel@tonic-gate 			}
21407c478bd9Sstevel@tonic-gate 		break;
21417c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Rise:
21427c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 &&
21437c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model == 0 || cpi->cpi_model == 2))
21447c478bd9Sstevel@tonic-gate 			brand = "Rise mP6";
21457c478bd9Sstevel@tonic-gate 		break;
21467c478bd9Sstevel@tonic-gate 	case X86_VENDOR_SiS:
21477c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
21487c478bd9Sstevel@tonic-gate 			brand = "SiS 55x";
21497c478bd9Sstevel@tonic-gate 		break;
21507c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
21517c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4)
21527c478bd9Sstevel@tonic-gate 			brand = "Transmeta Crusoe TM3x00 or TM5x00";
21537c478bd9Sstevel@tonic-gate 		break;
21547c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NSC:
21557c478bd9Sstevel@tonic-gate 	case X86_VENDOR_UMC:
21567c478bd9Sstevel@tonic-gate 	default:
21577c478bd9Sstevel@tonic-gate 		break;
21587c478bd9Sstevel@tonic-gate 	}
21597c478bd9Sstevel@tonic-gate 	if (brand) {
21607c478bd9Sstevel@tonic-gate 		(void) strcpy((char *)cpi->cpi_brandstr, brand);
21617c478bd9Sstevel@tonic-gate 		return;
21627c478bd9Sstevel@tonic-gate 	}
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	/*
21657c478bd9Sstevel@tonic-gate 	 * If all else fails ...
21667c478bd9Sstevel@tonic-gate 	 */
21677c478bd9Sstevel@tonic-gate 	(void) snprintf(cpi->cpi_brandstr, sizeof (cpi->cpi_brandstr),
21687c478bd9Sstevel@tonic-gate 	    "%s %d.%d.%d", cpi->cpi_vendorstr, cpi->cpi_family,
21697c478bd9Sstevel@tonic-gate 	    cpi->cpi_model, cpi->cpi_step);
21707c478bd9Sstevel@tonic-gate }
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate /*
21737c478bd9Sstevel@tonic-gate  * This routine is called just after kernel memory allocation
21747c478bd9Sstevel@tonic-gate  * becomes available on cpu0, and as part of mp_startup() on
21757c478bd9Sstevel@tonic-gate  * the other cpus.
21767c478bd9Sstevel@tonic-gate  *
2177d129bde2Sesaxe  * Fixup the brand string, and collect any information from cpuid
2178d129bde2Sesaxe  * that requires dynamicically allocated storage to represent.
21797c478bd9Sstevel@tonic-gate  */
21807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21817c478bd9Sstevel@tonic-gate void
21827c478bd9Sstevel@tonic-gate cpuid_pass3(cpu_t *cpu)
21837c478bd9Sstevel@tonic-gate {
2184d129bde2Sesaxe 	int	i, max, shft, level, size;
2185d129bde2Sesaxe 	struct cpuid_regs regs;
2186d129bde2Sesaxe 	struct cpuid_regs *cp;
21877c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 2);
21907c478bd9Sstevel@tonic-gate 
2191d129bde2Sesaxe 	/*
2192d129bde2Sesaxe 	 * Function 4: Deterministic cache parameters
2193d129bde2Sesaxe 	 *
2194d129bde2Sesaxe 	 * Take this opportunity to detect the number of threads
2195d129bde2Sesaxe 	 * sharing the last level cache, and construct a corresponding
2196d129bde2Sesaxe 	 * cache id. The respective cpuid_info members are initialized
2197d129bde2Sesaxe 	 * to the default case of "no last level cache sharing".
2198d129bde2Sesaxe 	 */
2199d129bde2Sesaxe 	cpi->cpi_ncpu_shr_last_cache = 1;
2200d129bde2Sesaxe 	cpi->cpi_last_lvl_cacheid = cpu->cpu_id;
2201d129bde2Sesaxe 
2202d129bde2Sesaxe 	if (cpi->cpi_maxeax >= 4 && cpi->cpi_vendor == X86_VENDOR_Intel) {
2203d129bde2Sesaxe 
2204d129bde2Sesaxe 		/*
2205d129bde2Sesaxe 		 * Find the # of elements (size) returned by fn 4, and along
2206d129bde2Sesaxe 		 * the way detect last level cache sharing details.
2207d129bde2Sesaxe 		 */
2208d129bde2Sesaxe 		bzero(&regs, sizeof (regs));
2209d129bde2Sesaxe 		cp = &regs;
2210d129bde2Sesaxe 		for (i = 0, max = 0; i < CPI_FN4_ECX_MAX; i++) {
2211d129bde2Sesaxe 			cp->cp_eax = 4;
2212d129bde2Sesaxe 			cp->cp_ecx = i;
2213d129bde2Sesaxe 
2214d129bde2Sesaxe 			(void) __cpuid_insn(cp);
2215d129bde2Sesaxe 
2216d129bde2Sesaxe 			if (CPI_CACHE_TYPE(cp) == 0)
2217d129bde2Sesaxe 				break;
2218d129bde2Sesaxe 			level = CPI_CACHE_LVL(cp);
2219d129bde2Sesaxe 			if (level > max) {
2220d129bde2Sesaxe 				max = level;
2221d129bde2Sesaxe 				cpi->cpi_ncpu_shr_last_cache =
2222d129bde2Sesaxe 				    CPI_NTHR_SHR_CACHE(cp) + 1;
2223d129bde2Sesaxe 			}
2224d129bde2Sesaxe 		}
2225d129bde2Sesaxe 		cpi->cpi_std_4_size = size = i;
2226d129bde2Sesaxe 
2227d129bde2Sesaxe 		/*
2228d129bde2Sesaxe 		 * Allocate the cpi_std_4 array. The first element
2229d129bde2Sesaxe 		 * references the regs for fn 4, %ecx == 0, which
2230d129bde2Sesaxe 		 * cpuid_pass2() stashed in cpi->cpi_std[4].
2231d129bde2Sesaxe 		 */
2232d129bde2Sesaxe 		if (size > 0) {
2233d129bde2Sesaxe 			cpi->cpi_std_4 =
2234d129bde2Sesaxe 			    kmem_alloc(size * sizeof (cp), KM_SLEEP);
2235d129bde2Sesaxe 			cpi->cpi_std_4[0] = &cpi->cpi_std[4];
2236d129bde2Sesaxe 
2237d129bde2Sesaxe 			/*
2238d129bde2Sesaxe 			 * Allocate storage to hold the additional regs
2239d129bde2Sesaxe 			 * for function 4, %ecx == 1 .. cpi_std_4_size.
2240d129bde2Sesaxe 			 *
2241d129bde2Sesaxe 			 * The regs for fn 4, %ecx == 0 has already
2242d129bde2Sesaxe 			 * been allocated as indicated above.
2243d129bde2Sesaxe 			 */
2244d129bde2Sesaxe 			for (i = 1; i < size; i++) {
2245d129bde2Sesaxe 				cp = cpi->cpi_std_4[i] =
2246d129bde2Sesaxe 				    kmem_zalloc(sizeof (regs), KM_SLEEP);
2247d129bde2Sesaxe 				cp->cp_eax = 4;
2248d129bde2Sesaxe 				cp->cp_ecx = i;
2249d129bde2Sesaxe 
2250d129bde2Sesaxe 				(void) __cpuid_insn(cp);
2251d129bde2Sesaxe 			}
2252d129bde2Sesaxe 		}
2253d129bde2Sesaxe 		/*
2254d129bde2Sesaxe 		 * Determine the number of bits needed to represent
2255d129bde2Sesaxe 		 * the number of CPUs sharing the last level cache.
2256d129bde2Sesaxe 		 *
2257d129bde2Sesaxe 		 * Shift off that number of bits from the APIC id to
2258d129bde2Sesaxe 		 * derive the cache id.
2259d129bde2Sesaxe 		 */
2260d129bde2Sesaxe 		shft = 0;
2261d129bde2Sesaxe 		for (i = 1; i < cpi->cpi_ncpu_shr_last_cache; i <<= 1)
2262d129bde2Sesaxe 			shft++;
2263b6917abeSmishra 		cpi->cpi_last_lvl_cacheid = cpi->cpi_apicid >> shft;
2264d129bde2Sesaxe 	}
2265d129bde2Sesaxe 
2266d129bde2Sesaxe 	/*
2267d129bde2Sesaxe 	 * Now fixup the brand string
2268d129bde2Sesaxe 	 */
22697c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0) {
22707c478bd9Sstevel@tonic-gate 		fabricate_brandstr(cpi);
2271d129bde2Sesaxe 	} else {
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 		/*
22747c478bd9Sstevel@tonic-gate 		 * If we successfully extracted a brand string from the cpuid
22757c478bd9Sstevel@tonic-gate 		 * instruction, clean it up by removing leading spaces and
22767c478bd9Sstevel@tonic-gate 		 * similar junk.
22777c478bd9Sstevel@tonic-gate 		 */
22787c478bd9Sstevel@tonic-gate 		if (cpi->cpi_brandstr[0]) {
22797c478bd9Sstevel@tonic-gate 			size_t maxlen = sizeof (cpi->cpi_brandstr);
22807c478bd9Sstevel@tonic-gate 			char *src, *dst;
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 			dst = src = (char *)cpi->cpi_brandstr;
22837c478bd9Sstevel@tonic-gate 			src[maxlen - 1] = '\0';
22847c478bd9Sstevel@tonic-gate 			/*
22857c478bd9Sstevel@tonic-gate 			 * strip leading spaces
22867c478bd9Sstevel@tonic-gate 			 */
22877c478bd9Sstevel@tonic-gate 			while (*src == ' ')
22887c478bd9Sstevel@tonic-gate 				src++;
22897c478bd9Sstevel@tonic-gate 			/*
22907c478bd9Sstevel@tonic-gate 			 * Remove any 'Genuine' or "Authentic" prefixes
22917c478bd9Sstevel@tonic-gate 			 */
22927c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Genuine ", 8) == 0)
22937c478bd9Sstevel@tonic-gate 				src += 8;
22947c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Authentic ", 10) == 0)
22957c478bd9Sstevel@tonic-gate 				src += 10;
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 			/*
22987c478bd9Sstevel@tonic-gate 			 * Now do an in-place copy.
22997c478bd9Sstevel@tonic-gate 			 * Map (R) to (r) and (TM) to (tm).
23007c478bd9Sstevel@tonic-gate 			 * The era of teletypes is long gone, and there's
23017c478bd9Sstevel@tonic-gate 			 * -really- no need to shout.
23027c478bd9Sstevel@tonic-gate 			 */
23037c478bd9Sstevel@tonic-gate 			while (*src != '\0') {
23047c478bd9Sstevel@tonic-gate 				if (src[0] == '(') {
23057c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "R)", 2) == 0) {
23067c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(r)", 3);
23077c478bd9Sstevel@tonic-gate 						src += 3;
23087c478bd9Sstevel@tonic-gate 						dst += 3;
23097c478bd9Sstevel@tonic-gate 						continue;
23107c478bd9Sstevel@tonic-gate 					}
23117c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "TM)", 3) == 0) {
23127c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(tm)", 4);
23137c478bd9Sstevel@tonic-gate 						src += 4;
23147c478bd9Sstevel@tonic-gate 						dst += 4;
23157c478bd9Sstevel@tonic-gate 						continue;
23167c478bd9Sstevel@tonic-gate 					}
23177c478bd9Sstevel@tonic-gate 				}
23187c478bd9Sstevel@tonic-gate 				*dst++ = *src++;
23197c478bd9Sstevel@tonic-gate 			}
23207c478bd9Sstevel@tonic-gate 			*dst = '\0';
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 			/*
23237c478bd9Sstevel@tonic-gate 			 * Finally, remove any trailing spaces
23247c478bd9Sstevel@tonic-gate 			 */
23257c478bd9Sstevel@tonic-gate 			while (--dst > cpi->cpi_brandstr)
23267c478bd9Sstevel@tonic-gate 				if (*dst == ' ')
23277c478bd9Sstevel@tonic-gate 					*dst = '\0';
23287c478bd9Sstevel@tonic-gate 				else
23297c478bd9Sstevel@tonic-gate 					break;
23307c478bd9Sstevel@tonic-gate 		} else
23317c478bd9Sstevel@tonic-gate 			fabricate_brandstr(cpi);
2332d129bde2Sesaxe 	}
23337c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 3;
23347c478bd9Sstevel@tonic-gate }
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate /*
23377c478bd9Sstevel@tonic-gate  * This routine is called out of bind_hwcap() much later in the life
23387c478bd9Sstevel@tonic-gate  * of the kernel (post_startup()).  The job of this routine is to resolve
23397c478bd9Sstevel@tonic-gate  * the hardware feature support and kernel support for those features into
23407c478bd9Sstevel@tonic-gate  * what we're actually going to tell applications via the aux vector.
23417c478bd9Sstevel@tonic-gate  */
23427c478bd9Sstevel@tonic-gate uint_t
23437c478bd9Sstevel@tonic-gate cpuid_pass4(cpu_t *cpu)
23447c478bd9Sstevel@tonic-gate {
23457c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
23467c478bd9Sstevel@tonic-gate 	uint_t hwcap_flags = 0;
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
23497c478bd9Sstevel@tonic-gate 		cpu = CPU;
23507c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 3);
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax >= 1) {
23557c478bd9Sstevel@tonic-gate 		uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES];
23567c478bd9Sstevel@tonic-gate 		uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES];
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_EDX(cpi);
23597c478bd9Sstevel@tonic-gate 		*ecx = CPI_FEATURES_ECX(cpi);
23607c478bd9Sstevel@tonic-gate 
23617c478bd9Sstevel@tonic-gate 		/*
23627c478bd9Sstevel@tonic-gate 		 * [these require explicit kernel support]
23637c478bd9Sstevel@tonic-gate 		 */
23647417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SEP))
23657c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SEP;
23667c478bd9Sstevel@tonic-gate 
23677417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE))
23687c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE);
23697417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE2))
23707c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SSE2;
23717c478bd9Sstevel@tonic-gate 
23727417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_HTT))
23737c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_HTT;
23747c478bd9Sstevel@tonic-gate 
23757417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE3))
23767c478bd9Sstevel@tonic-gate 			*ecx &= ~CPUID_INTC_ECX_SSE3;
23777c478bd9Sstevel@tonic-gate 
2378d0f8ff6eSkk208521 		if (cpi->cpi_vendor == X86_VENDOR_Intel) {
23797417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSSE3))
2380d0f8ff6eSkk208521 				*ecx &= ~CPUID_INTC_ECX_SSSE3;
23817417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1))
2382d0f8ff6eSkk208521 				*ecx &= ~CPUID_INTC_ECX_SSE4_1;
23837417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2))
2384d0f8ff6eSkk208521 				*ecx &= ~CPUID_INTC_ECX_SSE4_2;
23857417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_AES))
2386a50a8b93SKuriakose Kuruvilla 				*ecx &= ~CPUID_INTC_ECX_AES;
23877417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ))
23887417cfdeSKuriakose Kuruvilla 				*ecx &= ~CPUID_INTC_ECX_PCLMULQDQ;
2389d0f8ff6eSkk208521 		}
2390d0f8ff6eSkk208521 
23917c478bd9Sstevel@tonic-gate 		/*
23927c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond x87 fp context]
23937c478bd9Sstevel@tonic-gate 		 */
23947c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
23957c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FPU | CPUID_INTC_EDX_MMX);
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 		/*
23987c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to things that we
23997c478bd9Sstevel@tonic-gate 		 * think userland will care about.
24007c478bd9Sstevel@tonic-gate 		 */
24017c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SEP)
24027c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SEP;
24037c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE)
24047c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FXSR | AV_386_SSE;
24057c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE2)
24067c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE2;
24077c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_SSE3)
24087c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE3;
2409d0f8ff6eSkk208521 		if (cpi->cpi_vendor == X86_VENDOR_Intel) {
2410d0f8ff6eSkk208521 			if (*ecx & CPUID_INTC_ECX_SSSE3)
2411d0f8ff6eSkk208521 				hwcap_flags |= AV_386_SSSE3;
2412d0f8ff6eSkk208521 			if (*ecx & CPUID_INTC_ECX_SSE4_1)
2413d0f8ff6eSkk208521 				hwcap_flags |= AV_386_SSE4_1;
2414d0f8ff6eSkk208521 			if (*ecx & CPUID_INTC_ECX_SSE4_2)
2415d0f8ff6eSkk208521 				hwcap_flags |= AV_386_SSE4_2;
24165087e485SKrishnendu Sadhukhan - Sun Microsystems 			if (*ecx & CPUID_INTC_ECX_MOVBE)
24175087e485SKrishnendu Sadhukhan - Sun Microsystems 				hwcap_flags |= AV_386_MOVBE;
2418a50a8b93SKuriakose Kuruvilla 			if (*ecx & CPUID_INTC_ECX_AES)
2419a50a8b93SKuriakose Kuruvilla 				hwcap_flags |= AV_386_AES;
2420a50a8b93SKuriakose Kuruvilla 			if (*ecx & CPUID_INTC_ECX_PCLMULQDQ)
2421a50a8b93SKuriakose Kuruvilla 				hwcap_flags |= AV_386_PCLMULQDQ;
2422d0f8ff6eSkk208521 		}
2423f8801251Skk208521 		if (*ecx & CPUID_INTC_ECX_POPCNT)
2424f8801251Skk208521 			hwcap_flags |= AV_386_POPCNT;
24257c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_FPU)
24267c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FPU;
24277c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_MMX)
24287c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_MMX;
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_TSC)
24317c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_TSC;
24327c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CX8)
24337c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX8;
24347c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CMOV)
24357c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CMOV;
24367c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_CX16)
24377c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX16;
24387c478bd9Sstevel@tonic-gate 	}
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000001)
24417c478bd9Sstevel@tonic-gate 		goto pass4_done;
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
24448949bcd6Sandrei 		struct cpuid_regs cp;
2445ae115bc7Smrj 		uint32_t *edx, *ecx;
24467c478bd9Sstevel@tonic-gate 
2447ae115bc7Smrj 	case X86_VENDOR_Intel:
2448ae115bc7Smrj 		/*
2449ae115bc7Smrj 		 * Seems like Intel duplicated what we necessary
2450ae115bc7Smrj 		 * here to make the initial crop of 64-bit OS's work.
2451ae115bc7Smrj 		 * Hopefully, those are the only "extended" bits
2452ae115bc7Smrj 		 * they'll add.
2453ae115bc7Smrj 		 */
2454ae115bc7Smrj 		/*FALLTHROUGH*/
2455ae115bc7Smrj 
24567c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
24577c478bd9Sstevel@tonic-gate 		edx = &cpi->cpi_support[AMD_EDX_FEATURES];
2458ae115bc7Smrj 		ecx = &cpi->cpi_support[AMD_ECX_FEATURES];
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_XTD_EDX(cpi);
2461ae115bc7Smrj 		*ecx = CPI_FEATURES_XTD_ECX(cpi);
2462ae115bc7Smrj 
2463ae115bc7Smrj 		/*
2464ae115bc7Smrj 		 * [these features require explicit kernel support]
2465ae115bc7Smrj 		 */
2466ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2467ae115bc7Smrj 		case X86_VENDOR_Intel:
24687417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2469d36ea5d8Ssudheer 				*edx &= ~CPUID_AMD_EDX_TSCP;
2470ae115bc7Smrj 			break;
2471ae115bc7Smrj 
2472ae115bc7Smrj 		case X86_VENDOR_AMD:
24737417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2474ae115bc7Smrj 				*edx &= ~CPUID_AMD_EDX_TSCP;
24757417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4A))
2476f8801251Skk208521 				*ecx &= ~CPUID_AMD_ECX_SSE4A;
2477ae115bc7Smrj 			break;
2478ae115bc7Smrj 
2479ae115bc7Smrj 		default:
2480ae115bc7Smrj 			break;
2481ae115bc7Smrj 		}
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 		/*
24847c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond
24857c478bd9Sstevel@tonic-gate 		 * x87 fp context and exception handlers]
24867c478bd9Sstevel@tonic-gate 		 */
24877c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
24887c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_AMD_EDX_MMXamd |
24897c478bd9Sstevel@tonic-gate 			    CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx);
24907c478bd9Sstevel@tonic-gate 
24917417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_NX))
24927c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_AMD_EDX_NX;
2493ae115bc7Smrj #if !defined(__amd64)
24947c478bd9Sstevel@tonic-gate 		*edx &= ~CPUID_AMD_EDX_LM;
24957c478bd9Sstevel@tonic-gate #endif
24967c478bd9Sstevel@tonic-gate 		/*
24977c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to
24987c478bd9Sstevel@tonic-gate 		 * things that we think userland will care about.
24997c478bd9Sstevel@tonic-gate 		 */
2500ae115bc7Smrj #if defined(__amd64)
25017c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_SYSC)
25027c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_SYSC;
2503ae115bc7Smrj #endif
25047c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_MMXamd)
25057c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_MMX;
25067c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNow)
25077c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNow;
25087c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNowx)
25097c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNowx;
2510ae115bc7Smrj 
2511ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2512ae115bc7Smrj 		case X86_VENDOR_AMD:
2513ae115bc7Smrj 			if (*edx & CPUID_AMD_EDX_TSCP)
2514ae115bc7Smrj 				hwcap_flags |= AV_386_TSCP;
2515ae115bc7Smrj 			if (*ecx & CPUID_AMD_ECX_AHF64)
2516ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2517f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_SSE4A)
2518f8801251Skk208521 				hwcap_flags |= AV_386_AMD_SSE4A;
2519f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_LZCNT)
2520f8801251Skk208521 				hwcap_flags |= AV_386_AMD_LZCNT;
2521ae115bc7Smrj 			break;
2522ae115bc7Smrj 
2523ae115bc7Smrj 		case X86_VENDOR_Intel:
2524d36ea5d8Ssudheer 			if (*edx & CPUID_AMD_EDX_TSCP)
2525d36ea5d8Ssudheer 				hwcap_flags |= AV_386_TSCP;
2526ae115bc7Smrj 			/*
2527ae115bc7Smrj 			 * Aarrgh.
2528ae115bc7Smrj 			 * Intel uses a different bit in the same word.
2529ae115bc7Smrj 			 */
2530ae115bc7Smrj 			if (*ecx & CPUID_INTC_ECX_AHF64)
2531ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2532ae115bc7Smrj 			break;
2533ae115bc7Smrj 
2534ae115bc7Smrj 		default:
2535ae115bc7Smrj 			break;
2536ae115bc7Smrj 		}
25377c478bd9Sstevel@tonic-gate 		break;
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
25408949bcd6Sandrei 		cp.cp_eax = 0x80860001;
25418949bcd6Sandrei 		(void) __cpuid_insn(&cp);
25428949bcd6Sandrei 		cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx;
25437c478bd9Sstevel@tonic-gate 		break;
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 	default:
25467c478bd9Sstevel@tonic-gate 		break;
25477c478bd9Sstevel@tonic-gate 	}
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate pass4_done:
25507c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 4;
25517c478bd9Sstevel@tonic-gate 	return (hwcap_flags);
25527c478bd9Sstevel@tonic-gate }
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate /*
25567c478bd9Sstevel@tonic-gate  * Simulate the cpuid instruction using the data we previously
25577c478bd9Sstevel@tonic-gate  * captured about this CPU.  We try our best to return the truth
25587c478bd9Sstevel@tonic-gate  * about the hardware, independently of kernel support.
25597c478bd9Sstevel@tonic-gate  */
25607c478bd9Sstevel@tonic-gate uint32_t
25618949bcd6Sandrei cpuid_insn(cpu_t *cpu, struct cpuid_regs *cp)
25627c478bd9Sstevel@tonic-gate {
25637c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
25648949bcd6Sandrei 	struct cpuid_regs *xcp;
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
25677c478bd9Sstevel@tonic-gate 		cpu = CPU;
25687c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	/*
25737c478bd9Sstevel@tonic-gate 	 * CPUID data is cached in two separate places: cpi_std for standard
25747c478bd9Sstevel@tonic-gate 	 * CPUID functions, and cpi_extd for extended CPUID functions.
25757c478bd9Sstevel@tonic-gate 	 */
25768949bcd6Sandrei 	if (cp->cp_eax <= cpi->cpi_maxeax && cp->cp_eax < NMAX_CPI_STD)
25778949bcd6Sandrei 		xcp = &cpi->cpi_std[cp->cp_eax];
25788949bcd6Sandrei 	else if (cp->cp_eax >= 0x80000000 && cp->cp_eax <= cpi->cpi_xmaxeax &&
25798949bcd6Sandrei 	    cp->cp_eax < 0x80000000 + NMAX_CPI_EXTD)
25808949bcd6Sandrei 		xcp = &cpi->cpi_extd[cp->cp_eax - 0x80000000];
25817c478bd9Sstevel@tonic-gate 	else
25827c478bd9Sstevel@tonic-gate 		/*
25837c478bd9Sstevel@tonic-gate 		 * The caller is asking for data from an input parameter which
25847c478bd9Sstevel@tonic-gate 		 * the kernel has not cached.  In this case we go fetch from
25857c478bd9Sstevel@tonic-gate 		 * the hardware and return the data directly to the user.
25867c478bd9Sstevel@tonic-gate 		 */
25878949bcd6Sandrei 		return (__cpuid_insn(cp));
25888949bcd6Sandrei 
25898949bcd6Sandrei 	cp->cp_eax = xcp->cp_eax;
25908949bcd6Sandrei 	cp->cp_ebx = xcp->cp_ebx;
25918949bcd6Sandrei 	cp->cp_ecx = xcp->cp_ecx;
25928949bcd6Sandrei 	cp->cp_edx = xcp->cp_edx;
25937c478bd9Sstevel@tonic-gate 	return (cp->cp_eax);
25947c478bd9Sstevel@tonic-gate }
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate int
25977c478bd9Sstevel@tonic-gate cpuid_checkpass(cpu_t *cpu, int pass)
25987c478bd9Sstevel@tonic-gate {
25997c478bd9Sstevel@tonic-gate 	return (cpu != NULL && cpu->cpu_m.mcpu_cpi != NULL &&
26007c478bd9Sstevel@tonic-gate 	    cpu->cpu_m.mcpu_cpi->cpi_pass >= pass);
26017c478bd9Sstevel@tonic-gate }
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate int
26047c478bd9Sstevel@tonic-gate cpuid_getbrandstr(cpu_t *cpu, char *s, size_t n)
26057c478bd9Sstevel@tonic-gate {
26067c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, "%s", cpu->cpu_m.mcpu_cpi->cpi_brandstr));
26097c478bd9Sstevel@tonic-gate }
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate int
26128949bcd6Sandrei cpuid_is_cmt(cpu_t *cpu)
26137c478bd9Sstevel@tonic-gate {
26147c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
26157c478bd9Sstevel@tonic-gate 		cpu = CPU;
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_chipid >= 0);
26207c478bd9Sstevel@tonic-gate }
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate /*
26237c478bd9Sstevel@tonic-gate  * AMD and Intel both implement the 64-bit variant of the syscall
26247c478bd9Sstevel@tonic-gate  * instruction (syscallq), so if there's -any- support for syscall,
26257c478bd9Sstevel@tonic-gate  * cpuid currently says "yes, we support this".
26267c478bd9Sstevel@tonic-gate  *
26277c478bd9Sstevel@tonic-gate  * However, Intel decided to -not- implement the 32-bit variant of the
26287c478bd9Sstevel@tonic-gate  * syscall instruction, so we provide a predicate to allow our caller
26297c478bd9Sstevel@tonic-gate  * to test that subtlety here.
2630843e1988Sjohnlev  *
2631843e1988Sjohnlev  * XXPV	Currently, 32-bit syscall instructions don't work via the hypervisor,
2632843e1988Sjohnlev  *	even in the case where the hardware would in fact support it.
26337c478bd9Sstevel@tonic-gate  */
26347c478bd9Sstevel@tonic-gate /*ARGSUSED*/
26357c478bd9Sstevel@tonic-gate int
26367c478bd9Sstevel@tonic-gate cpuid_syscall32_insn(cpu_t *cpu)
26377c478bd9Sstevel@tonic-gate {
26387c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass((cpu == NULL ? CPU : cpu), 1));
26397c478bd9Sstevel@tonic-gate 
2640843e1988Sjohnlev #if !defined(__xpv)
2641ae115bc7Smrj 	if (cpu == NULL)
2642ae115bc7Smrj 		cpu = CPU;
2643ae115bc7Smrj 
2644ae115bc7Smrj 	/*CSTYLED*/
2645ae115bc7Smrj 	{
2646ae115bc7Smrj 		struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
2647ae115bc7Smrj 
2648ae115bc7Smrj 		if (cpi->cpi_vendor == X86_VENDOR_AMD &&
2649ae115bc7Smrj 		    cpi->cpi_xmaxeax >= 0x80000001 &&
2650ae115bc7Smrj 		    (CPI_FEATURES_XTD_EDX(cpi) & CPUID_AMD_EDX_SYSC))
2651ae115bc7Smrj 			return (1);
2652ae115bc7Smrj 	}
2653843e1988Sjohnlev #endif
26547c478bd9Sstevel@tonic-gate 	return (0);
26557c478bd9Sstevel@tonic-gate }
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate int
26587c478bd9Sstevel@tonic-gate cpuid_getidstr(cpu_t *cpu, char *s, size_t n)
26597c478bd9Sstevel@tonic-gate {
26607c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate 	static const char fmt[] =
2663ecfa43a5Sdmick 	    "x86 (%s %X family %d model %d step %d clock %d MHz)";
26647c478bd9Sstevel@tonic-gate 	static const char fmt_ht[] =
2665ecfa43a5Sdmick 	    "x86 (chipid 0x%x %s %X family %d model %d step %d clock %d MHz)";
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
26687c478bd9Sstevel@tonic-gate 
26698949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
26707c478bd9Sstevel@tonic-gate 		return (snprintf(s, n, fmt_ht, cpi->cpi_chipid,
2671ecfa43a5Sdmick 		    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
2672ecfa43a5Sdmick 		    cpi->cpi_family, cpi->cpi_model,
26737c478bd9Sstevel@tonic-gate 		    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
26747c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, fmt,
2675ecfa43a5Sdmick 	    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
2676ecfa43a5Sdmick 	    cpi->cpi_family, cpi->cpi_model,
26777c478bd9Sstevel@tonic-gate 	    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
26787c478bd9Sstevel@tonic-gate }
26797c478bd9Sstevel@tonic-gate 
26807c478bd9Sstevel@tonic-gate const char *
26817c478bd9Sstevel@tonic-gate cpuid_getvendorstr(cpu_t *cpu)
26827c478bd9Sstevel@tonic-gate {
26837c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
26847c478bd9Sstevel@tonic-gate 	return ((const char *)cpu->cpu_m.mcpu_cpi->cpi_vendorstr);
26857c478bd9Sstevel@tonic-gate }
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate uint_t
26887c478bd9Sstevel@tonic-gate cpuid_getvendor(cpu_t *cpu)
26897c478bd9Sstevel@tonic-gate {
26907c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
26917c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_vendor);
26927c478bd9Sstevel@tonic-gate }
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate uint_t
26957c478bd9Sstevel@tonic-gate cpuid_getfamily(cpu_t *cpu)
26967c478bd9Sstevel@tonic-gate {
26977c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
26987c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_family);
26997c478bd9Sstevel@tonic-gate }
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate uint_t
27027c478bd9Sstevel@tonic-gate cpuid_getmodel(cpu_t *cpu)
27037c478bd9Sstevel@tonic-gate {
27047c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
27057c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_model);
27067c478bd9Sstevel@tonic-gate }
27077c478bd9Sstevel@tonic-gate 
27087c478bd9Sstevel@tonic-gate uint_t
27097c478bd9Sstevel@tonic-gate cpuid_get_ncpu_per_chip(cpu_t *cpu)
27107c478bd9Sstevel@tonic-gate {
27117c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
27127c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_per_chip);
27137c478bd9Sstevel@tonic-gate }
27147c478bd9Sstevel@tonic-gate 
27157c478bd9Sstevel@tonic-gate uint_t
27168949bcd6Sandrei cpuid_get_ncore_per_chip(cpu_t *cpu)
27178949bcd6Sandrei {
27188949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
27198949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_ncore_per_chip);
27208949bcd6Sandrei }
27218949bcd6Sandrei 
27228949bcd6Sandrei uint_t
2723d129bde2Sesaxe cpuid_get_ncpu_sharing_last_cache(cpu_t *cpu)
2724d129bde2Sesaxe {
2725d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
2726d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_shr_last_cache);
2727d129bde2Sesaxe }
2728d129bde2Sesaxe 
2729d129bde2Sesaxe id_t
2730d129bde2Sesaxe cpuid_get_last_lvl_cacheid(cpu_t *cpu)
2731d129bde2Sesaxe {
2732d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
2733d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
2734d129bde2Sesaxe }
2735d129bde2Sesaxe 
2736d129bde2Sesaxe uint_t
27377c478bd9Sstevel@tonic-gate cpuid_getstep(cpu_t *cpu)
27387c478bd9Sstevel@tonic-gate {
27397c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
27407c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_step);
27417c478bd9Sstevel@tonic-gate }
27427c478bd9Sstevel@tonic-gate 
27432449e17fSsherrym uint_t
27442449e17fSsherrym cpuid_getsig(struct cpu *cpu)
27452449e17fSsherrym {
27462449e17fSsherrym 	ASSERT(cpuid_checkpass(cpu, 1));
27472449e17fSsherrym 	return (cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_eax);
27482449e17fSsherrym }
27492449e17fSsherrym 
27508a40a695Sgavinm uint32_t
27518a40a695Sgavinm cpuid_getchiprev(struct cpu *cpu)
27528a40a695Sgavinm {
27538a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
27548a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprev);
27558a40a695Sgavinm }
27568a40a695Sgavinm 
27578a40a695Sgavinm const char *
27588a40a695Sgavinm cpuid_getchiprevstr(struct cpu *cpu)
27598a40a695Sgavinm {
27608a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
27618a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprevstr);
27628a40a695Sgavinm }
27638a40a695Sgavinm 
27648a40a695Sgavinm uint32_t
27658a40a695Sgavinm cpuid_getsockettype(struct cpu *cpu)
27668a40a695Sgavinm {
27678a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
27688a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_socket);
27698a40a695Sgavinm }
27708a40a695Sgavinm 
277189e921d5SKuriakose Kuruvilla const char *
277289e921d5SKuriakose Kuruvilla cpuid_getsocketstr(cpu_t *cpu)
277389e921d5SKuriakose Kuruvilla {
277489e921d5SKuriakose Kuruvilla 	static const char *socketstr = NULL;
277589e921d5SKuriakose Kuruvilla 	struct cpuid_info *cpi;
277689e921d5SKuriakose Kuruvilla 
277789e921d5SKuriakose Kuruvilla 	ASSERT(cpuid_checkpass(cpu, 1));
277889e921d5SKuriakose Kuruvilla 	cpi = cpu->cpu_m.mcpu_cpi;
277989e921d5SKuriakose Kuruvilla 
278089e921d5SKuriakose Kuruvilla 	/* Assume that socket types are the same across the system */
278189e921d5SKuriakose Kuruvilla 	if (socketstr == NULL)
278289e921d5SKuriakose Kuruvilla 		socketstr = _cpuid_sktstr(cpi->cpi_vendor, cpi->cpi_family,
278389e921d5SKuriakose Kuruvilla 		    cpi->cpi_model, cpi->cpi_step);
278489e921d5SKuriakose Kuruvilla 
278589e921d5SKuriakose Kuruvilla 
278689e921d5SKuriakose Kuruvilla 	return (socketstr);
278789e921d5SKuriakose Kuruvilla }
278889e921d5SKuriakose Kuruvilla 
2789fb2f18f8Sesaxe int
2790fb2f18f8Sesaxe cpuid_get_chipid(cpu_t *cpu)
27917c478bd9Sstevel@tonic-gate {
27927c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
27937c478bd9Sstevel@tonic-gate 
27948949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
27957c478bd9Sstevel@tonic-gate 		return (cpu->cpu_m.mcpu_cpi->cpi_chipid);
27967c478bd9Sstevel@tonic-gate 	return (cpu->cpu_id);
27977c478bd9Sstevel@tonic-gate }
27987c478bd9Sstevel@tonic-gate 
27998949bcd6Sandrei id_t
2800fb2f18f8Sesaxe cpuid_get_coreid(cpu_t *cpu)
28018949bcd6Sandrei {
28028949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
28038949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_coreid);
28048949bcd6Sandrei }
28058949bcd6Sandrei 
28067c478bd9Sstevel@tonic-gate int
280710569901Sgavinm cpuid_get_pkgcoreid(cpu_t *cpu)
280810569901Sgavinm {
280910569901Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
281010569901Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_pkgcoreid);
281110569901Sgavinm }
281210569901Sgavinm 
281310569901Sgavinm int
2814fb2f18f8Sesaxe cpuid_get_clogid(cpu_t *cpu)
28157c478bd9Sstevel@tonic-gate {
28167c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28177c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_clogid);
28187c478bd9Sstevel@tonic-gate }
28197c478bd9Sstevel@tonic-gate 
2820b885580bSAlexander Kolbasov int
2821b885580bSAlexander Kolbasov cpuid_get_cacheid(cpu_t *cpu)
2822b885580bSAlexander Kolbasov {
2823b885580bSAlexander Kolbasov 	ASSERT(cpuid_checkpass(cpu, 1));
2824b885580bSAlexander Kolbasov 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
2825b885580bSAlexander Kolbasov }
2826b885580bSAlexander Kolbasov 
28278031591dSSrihari Venkatesan uint_t
28288031591dSSrihari Venkatesan cpuid_get_procnodeid(cpu_t *cpu)
28298031591dSSrihari Venkatesan {
28308031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
28318031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodeid);
28328031591dSSrihari Venkatesan }
28338031591dSSrihari Venkatesan 
28348031591dSSrihari Venkatesan uint_t
28358031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg(cpu_t *cpu)
28368031591dSSrihari Venkatesan {
28378031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
28388031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg);
28398031591dSSrihari Venkatesan }
28408031591dSSrihari Venkatesan 
28412ef50f01SJoe Bonasera /*ARGSUSED*/
28422ef50f01SJoe Bonasera int
28432ef50f01SJoe Bonasera cpuid_have_cr8access(cpu_t *cpu)
28442ef50f01SJoe Bonasera {
28452ef50f01SJoe Bonasera #if defined(__amd64)
28462ef50f01SJoe Bonasera 	return (1);
28472ef50f01SJoe Bonasera #else
28482ef50f01SJoe Bonasera 	struct cpuid_info *cpi;
28492ef50f01SJoe Bonasera 
28502ef50f01SJoe Bonasera 	ASSERT(cpu != NULL);
28512ef50f01SJoe Bonasera 	cpi = cpu->cpu_m.mcpu_cpi;
28522ef50f01SJoe Bonasera 	if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 &&
28532ef50f01SJoe Bonasera 	    (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0)
28542ef50f01SJoe Bonasera 		return (1);
28552ef50f01SJoe Bonasera 	return (0);
28562ef50f01SJoe Bonasera #endif
28572ef50f01SJoe Bonasera }
28582ef50f01SJoe Bonasera 
2859fa96bd91SMichael Corcoran uint32_t
2860fa96bd91SMichael Corcoran cpuid_get_apicid(cpu_t *cpu)
2861fa96bd91SMichael Corcoran {
2862fa96bd91SMichael Corcoran 	ASSERT(cpuid_checkpass(cpu, 1));
2863fa96bd91SMichael Corcoran 	if (cpu->cpu_m.mcpu_cpi->cpi_maxeax < 1) {
2864fa96bd91SMichael Corcoran 		return (UINT32_MAX);
2865fa96bd91SMichael Corcoran 	} else {
2866fa96bd91SMichael Corcoran 		return (cpu->cpu_m.mcpu_cpi->cpi_apicid);
2867fa96bd91SMichael Corcoran 	}
2868fa96bd91SMichael Corcoran }
2869fa96bd91SMichael Corcoran 
28707c478bd9Sstevel@tonic-gate void
28717c478bd9Sstevel@tonic-gate cpuid_get_addrsize(cpu_t *cpu, uint_t *pabits, uint_t *vabits)
28727c478bd9Sstevel@tonic-gate {
28737c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
28747c478bd9Sstevel@tonic-gate 
28757c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
28767c478bd9Sstevel@tonic-gate 		cpu = CPU;
28777c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
28787c478bd9Sstevel@tonic-gate 
28797c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28807c478bd9Sstevel@tonic-gate 
28817c478bd9Sstevel@tonic-gate 	if (pabits)
28827c478bd9Sstevel@tonic-gate 		*pabits = cpi->cpi_pabits;
28837c478bd9Sstevel@tonic-gate 	if (vabits)
28847c478bd9Sstevel@tonic-gate 		*vabits = cpi->cpi_vabits;
28857c478bd9Sstevel@tonic-gate }
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate /*
28887c478bd9Sstevel@tonic-gate  * Returns the number of data TLB entries for a corresponding
28897c478bd9Sstevel@tonic-gate  * pagesize.  If it can't be computed, or isn't known, the
28907c478bd9Sstevel@tonic-gate  * routine returns zero.  If you ask about an architecturally
28917c478bd9Sstevel@tonic-gate  * impossible pagesize, the routine will panic (so that the
28927c478bd9Sstevel@tonic-gate  * hat implementor knows that things are inconsistent.)
28937c478bd9Sstevel@tonic-gate  */
28947c478bd9Sstevel@tonic-gate uint_t
28957c478bd9Sstevel@tonic-gate cpuid_get_dtlb_nent(cpu_t *cpu, size_t pagesize)
28967c478bd9Sstevel@tonic-gate {
28977c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
28987c478bd9Sstevel@tonic-gate 	uint_t dtlb_nent = 0;
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
29017c478bd9Sstevel@tonic-gate 		cpu = CPU;
29027c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
29037c478bd9Sstevel@tonic-gate 
29047c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29057c478bd9Sstevel@tonic-gate 
29067c478bd9Sstevel@tonic-gate 	/*
29077c478bd9Sstevel@tonic-gate 	 * Check the L2 TLB info
29087c478bd9Sstevel@tonic-gate 	 */
29097c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000006) {
29108949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[6];
29117c478bd9Sstevel@tonic-gate 
29127c478bd9Sstevel@tonic-gate 		switch (pagesize) {
29137c478bd9Sstevel@tonic-gate 
29147c478bd9Sstevel@tonic-gate 		case 4 * 1024:
29157c478bd9Sstevel@tonic-gate 			/*
29167c478bd9Sstevel@tonic-gate 			 * All zero in the top 16 bits of the register
29177c478bd9Sstevel@tonic-gate 			 * indicates a unified TLB. Size is in low 16 bits.
29187c478bd9Sstevel@tonic-gate 			 */
29197c478bd9Sstevel@tonic-gate 			if ((cp->cp_ebx & 0xffff0000) == 0)
29207c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_ebx & 0x0000ffff;
29217c478bd9Sstevel@tonic-gate 			else
29227c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_ebx, 27, 16);
29237c478bd9Sstevel@tonic-gate 			break;
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
29267c478bd9Sstevel@tonic-gate 			if ((cp->cp_eax & 0xffff0000) == 0)
29277c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_eax & 0x0000ffff;
29287c478bd9Sstevel@tonic-gate 			else
29297c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_eax, 27, 16);
29307c478bd9Sstevel@tonic-gate 			break;
29317c478bd9Sstevel@tonic-gate 
29327c478bd9Sstevel@tonic-gate 		default:
29337c478bd9Sstevel@tonic-gate 			panic("unknown L2 pagesize");
29347c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
29357c478bd9Sstevel@tonic-gate 		}
29367c478bd9Sstevel@tonic-gate 	}
29377c478bd9Sstevel@tonic-gate 
29387c478bd9Sstevel@tonic-gate 	if (dtlb_nent != 0)
29397c478bd9Sstevel@tonic-gate 		return (dtlb_nent);
29407c478bd9Sstevel@tonic-gate 
29417c478bd9Sstevel@tonic-gate 	/*
29427c478bd9Sstevel@tonic-gate 	 * No L2 TLB support for this size, try L1.
29437c478bd9Sstevel@tonic-gate 	 */
29447c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000005) {
29458949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[5];
29467c478bd9Sstevel@tonic-gate 
29477c478bd9Sstevel@tonic-gate 		switch (pagesize) {
29487c478bd9Sstevel@tonic-gate 		case 4 * 1024:
29497c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_ebx, 23, 16);
29507c478bd9Sstevel@tonic-gate 			break;
29517c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
29527c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_eax, 23, 16);
29537c478bd9Sstevel@tonic-gate 			break;
29547c478bd9Sstevel@tonic-gate 		default:
29557c478bd9Sstevel@tonic-gate 			panic("unknown L1 d-TLB pagesize");
29567c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
29577c478bd9Sstevel@tonic-gate 		}
29587c478bd9Sstevel@tonic-gate 	}
29597c478bd9Sstevel@tonic-gate 
29607c478bd9Sstevel@tonic-gate 	return (dtlb_nent);
29617c478bd9Sstevel@tonic-gate }
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate /*
29647c478bd9Sstevel@tonic-gate  * Return 0 if the erratum is not present or not applicable, positive
29657c478bd9Sstevel@tonic-gate  * if it is, and negative if the status of the erratum is unknown.
29667c478bd9Sstevel@tonic-gate  *
29677c478bd9Sstevel@tonic-gate  * See "Revision Guide for AMD Athlon(tm) 64 and AMD Opteron(tm)
29682201b277Skucharsk  * Processors" #25759, Rev 3.57, August 2005
29697c478bd9Sstevel@tonic-gate  */
29707c478bd9Sstevel@tonic-gate int
29717c478bd9Sstevel@tonic-gate cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum)
29727c478bd9Sstevel@tonic-gate {
29737c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
29748949bcd6Sandrei 	uint_t eax;
29757c478bd9Sstevel@tonic-gate 
2976ea99987eSsethg 	/*
2977ea99987eSsethg 	 * Bail out if this CPU isn't an AMD CPU, or if it's
2978ea99987eSsethg 	 * a legacy (32-bit) AMD CPU.
2979ea99987eSsethg 	 */
2980ea99987eSsethg 	if (cpi->cpi_vendor != X86_VENDOR_AMD ||
2981875b116eSkchow 	    cpi->cpi_family == 4 || cpi->cpi_family == 5 ||
2982875b116eSkchow 	    cpi->cpi_family == 6)
29838a40a695Sgavinm 
29847c478bd9Sstevel@tonic-gate 		return (0);
29857c478bd9Sstevel@tonic-gate 
29867c478bd9Sstevel@tonic-gate 	eax = cpi->cpi_std[1].cp_eax;
29877c478bd9Sstevel@tonic-gate 
29887c478bd9Sstevel@tonic-gate #define	SH_B0(eax)	(eax == 0xf40 || eax == 0xf50)
29897c478bd9Sstevel@tonic-gate #define	SH_B3(eax) 	(eax == 0xf51)
2990ee88d2b9Skchow #define	B(eax)		(SH_B0(eax) || SH_B3(eax))
29917c478bd9Sstevel@tonic-gate 
29927c478bd9Sstevel@tonic-gate #define	SH_C0(eax)	(eax == 0xf48 || eax == 0xf58)
29937c478bd9Sstevel@tonic-gate 
29947c478bd9Sstevel@tonic-gate #define	SH_CG(eax)	(eax == 0xf4a || eax == 0xf5a || eax == 0xf7a)
29957c478bd9Sstevel@tonic-gate #define	DH_CG(eax)	(eax == 0xfc0 || eax == 0xfe0 || eax == 0xff0)
29967c478bd9Sstevel@tonic-gate #define	CH_CG(eax)	(eax == 0xf82 || eax == 0xfb2)
2997ee88d2b9Skchow #define	CG(eax)		(SH_CG(eax) || DH_CG(eax) || CH_CG(eax))
29987c478bd9Sstevel@tonic-gate 
29997c478bd9Sstevel@tonic-gate #define	SH_D0(eax)	(eax == 0x10f40 || eax == 0x10f50 || eax == 0x10f70)
30007c478bd9Sstevel@tonic-gate #define	DH_D0(eax)	(eax == 0x10fc0 || eax == 0x10ff0)
30017c478bd9Sstevel@tonic-gate #define	CH_D0(eax)	(eax == 0x10f80 || eax == 0x10fb0)
3002ee88d2b9Skchow #define	D0(eax)		(SH_D0(eax) || DH_D0(eax) || CH_D0(eax))
30037c478bd9Sstevel@tonic-gate 
30047c478bd9Sstevel@tonic-gate #define	SH_E0(eax)	(eax == 0x20f50 || eax == 0x20f40 || eax == 0x20f70)
30057c478bd9Sstevel@tonic-gate #define	JH_E1(eax)	(eax == 0x20f10)	/* JH8_E0 had 0x20f30 */
30067c478bd9Sstevel@tonic-gate #define	DH_E3(eax)	(eax == 0x20fc0 || eax == 0x20ff0)
30077c478bd9Sstevel@tonic-gate #define	SH_E4(eax)	(eax == 0x20f51 || eax == 0x20f71)
30087c478bd9Sstevel@tonic-gate #define	BH_E4(eax)	(eax == 0x20fb1)
30097c478bd9Sstevel@tonic-gate #define	SH_E5(eax)	(eax == 0x20f42)
30107c478bd9Sstevel@tonic-gate #define	DH_E6(eax)	(eax == 0x20ff2 || eax == 0x20fc2)
30117c478bd9Sstevel@tonic-gate #define	JH_E6(eax)	(eax == 0x20f12 || eax == 0x20f32)
3012ee88d2b9Skchow #define	EX(eax)		(SH_E0(eax) || JH_E1(eax) || DH_E3(eax) || \
3013ee88d2b9Skchow 			    SH_E4(eax) || BH_E4(eax) || SH_E5(eax) || \
3014ee88d2b9Skchow 			    DH_E6(eax) || JH_E6(eax))
30157c478bd9Sstevel@tonic-gate 
3016512cf780Skchow #define	DR_AX(eax)	(eax == 0x100f00 || eax == 0x100f01 || eax == 0x100f02)
3017512cf780Skchow #define	DR_B0(eax)	(eax == 0x100f20)
3018512cf780Skchow #define	DR_B1(eax)	(eax == 0x100f21)
3019512cf780Skchow #define	DR_BA(eax)	(eax == 0x100f2a)
3020512cf780Skchow #define	DR_B2(eax)	(eax == 0x100f22)
3021512cf780Skchow #define	DR_B3(eax)	(eax == 0x100f23)
3022512cf780Skchow #define	RB_C0(eax)	(eax == 0x100f40)
3023512cf780Skchow 
30247c478bd9Sstevel@tonic-gate 	switch (erratum) {
30257c478bd9Sstevel@tonic-gate 	case 1:
3026875b116eSkchow 		return (cpi->cpi_family < 0x10);
30277c478bd9Sstevel@tonic-gate 	case 51:	/* what does the asterisk mean? */
30287c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
30297c478bd9Sstevel@tonic-gate 	case 52:
30307c478bd9Sstevel@tonic-gate 		return (B(eax));
30317c478bd9Sstevel@tonic-gate 	case 57:
3032512cf780Skchow 		return (cpi->cpi_family <= 0x11);
30337c478bd9Sstevel@tonic-gate 	case 58:
30347c478bd9Sstevel@tonic-gate 		return (B(eax));
30357c478bd9Sstevel@tonic-gate 	case 60:
3036512cf780Skchow 		return (cpi->cpi_family <= 0x11);
30377c478bd9Sstevel@tonic-gate 	case 61:
30387c478bd9Sstevel@tonic-gate 	case 62:
30397c478bd9Sstevel@tonic-gate 	case 63:
30407c478bd9Sstevel@tonic-gate 	case 64:
30417c478bd9Sstevel@tonic-gate 	case 65:
30427c478bd9Sstevel@tonic-gate 	case 66:
30437c478bd9Sstevel@tonic-gate 	case 68:
30447c478bd9Sstevel@tonic-gate 	case 69:
30457c478bd9Sstevel@tonic-gate 	case 70:
30467c478bd9Sstevel@tonic-gate 	case 71:
30477c478bd9Sstevel@tonic-gate 		return (B(eax));
30487c478bd9Sstevel@tonic-gate 	case 72:
30497c478bd9Sstevel@tonic-gate 		return (SH_B0(eax));
30507c478bd9Sstevel@tonic-gate 	case 74:
30517c478bd9Sstevel@tonic-gate 		return (B(eax));
30527c478bd9Sstevel@tonic-gate 	case 75:
3053875b116eSkchow 		return (cpi->cpi_family < 0x10);
30547c478bd9Sstevel@tonic-gate 	case 76:
30557c478bd9Sstevel@tonic-gate 		return (B(eax));
30567c478bd9Sstevel@tonic-gate 	case 77:
3057512cf780Skchow 		return (cpi->cpi_family <= 0x11);
30587c478bd9Sstevel@tonic-gate 	case 78:
30597c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
30607c478bd9Sstevel@tonic-gate 	case 79:
30617c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
30627c478bd9Sstevel@tonic-gate 	case 80:
30637c478bd9Sstevel@tonic-gate 	case 81:
30647c478bd9Sstevel@tonic-gate 	case 82:
30657c478bd9Sstevel@tonic-gate 		return (B(eax));
30667c478bd9Sstevel@tonic-gate 	case 83:
30677c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
30687c478bd9Sstevel@tonic-gate 	case 85:
3069875b116eSkchow 		return (cpi->cpi_family < 0x10);
30707c478bd9Sstevel@tonic-gate 	case 86:
30717c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
30727c478bd9Sstevel@tonic-gate 	case 88:
30737c478bd9Sstevel@tonic-gate #if !defined(__amd64)
30747c478bd9Sstevel@tonic-gate 		return (0);
30757c478bd9Sstevel@tonic-gate #else
30767c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
30777c478bd9Sstevel@tonic-gate #endif
30787c478bd9Sstevel@tonic-gate 	case 89:
3079875b116eSkchow 		return (cpi->cpi_family < 0x10);
30807c478bd9Sstevel@tonic-gate 	case 90:
30817c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
30827c478bd9Sstevel@tonic-gate 	case 91:
30837c478bd9Sstevel@tonic-gate 	case 92:
30847c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
30857c478bd9Sstevel@tonic-gate 	case 93:
30867c478bd9Sstevel@tonic-gate 		return (SH_C0(eax));
30877c478bd9Sstevel@tonic-gate 	case 94:
30887c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
30897c478bd9Sstevel@tonic-gate 	case 95:
30907c478bd9Sstevel@tonic-gate #if !defined(__amd64)
30917c478bd9Sstevel@tonic-gate 		return (0);
30927c478bd9Sstevel@tonic-gate #else
30937c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
30947c478bd9Sstevel@tonic-gate #endif
30957c478bd9Sstevel@tonic-gate 	case 96:
30967c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
30977c478bd9Sstevel@tonic-gate 	case 97:
30987c478bd9Sstevel@tonic-gate 	case 98:
30997c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
31007c478bd9Sstevel@tonic-gate 	case 99:
31017c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
31027c478bd9Sstevel@tonic-gate 	case 100:
31037c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
31047c478bd9Sstevel@tonic-gate 	case 101:
31057c478bd9Sstevel@tonic-gate 	case 103:
31067c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
31077c478bd9Sstevel@tonic-gate 	case 104:
31087c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
31097c478bd9Sstevel@tonic-gate 	case 105:
31107c478bd9Sstevel@tonic-gate 	case 106:
31117c478bd9Sstevel@tonic-gate 	case 107:
31127c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
31137c478bd9Sstevel@tonic-gate 	case 108:
31147c478bd9Sstevel@tonic-gate 		return (DH_CG(eax));
31157c478bd9Sstevel@tonic-gate 	case 109:
31167c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
31177c478bd9Sstevel@tonic-gate 	case 110:
31187c478bd9Sstevel@tonic-gate 		return (D0(eax) || EX(eax));
31197c478bd9Sstevel@tonic-gate 	case 111:
31207c478bd9Sstevel@tonic-gate 		return (CG(eax));
31217c478bd9Sstevel@tonic-gate 	case 112:
31227c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
31237c478bd9Sstevel@tonic-gate 	case 113:
31247c478bd9Sstevel@tonic-gate 		return (eax == 0x20fc0);
31257c478bd9Sstevel@tonic-gate 	case 114:
31267c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
31277c478bd9Sstevel@tonic-gate 	case 115:
31287c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax));
31297c478bd9Sstevel@tonic-gate 	case 116:
31307c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
31317c478bd9Sstevel@tonic-gate 	case 117:
31327c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
31337c478bd9Sstevel@tonic-gate 	case 118:
31347c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || SH_E4(eax) || BH_E4(eax) ||
31357c478bd9Sstevel@tonic-gate 		    JH_E6(eax));
31367c478bd9Sstevel@tonic-gate 	case 121:
31377c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
31387c478bd9Sstevel@tonic-gate 	case 122:
3139512cf780Skchow 		return (cpi->cpi_family < 0x10 || cpi->cpi_family == 0x11);
31407c478bd9Sstevel@tonic-gate 	case 123:
31417c478bd9Sstevel@tonic-gate 		return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax));
31422201b277Skucharsk 	case 131:
3143875b116eSkchow 		return (cpi->cpi_family < 0x10);
3144ef50d8c0Sesaxe 	case 6336786:
3145ef50d8c0Sesaxe 		/*
3146ef50d8c0Sesaxe 		 * Test for AdvPowerMgmtInfo.TscPStateInvariant
3147875b116eSkchow 		 * if this is a K8 family or newer processor
3148ef50d8c0Sesaxe 		 */
3149ef50d8c0Sesaxe 		if (CPI_FAMILY(cpi) == 0xf) {
31508949bcd6Sandrei 			struct cpuid_regs regs;
31518949bcd6Sandrei 			regs.cp_eax = 0x80000007;
31528949bcd6Sandrei 			(void) __cpuid_insn(&regs);
31538949bcd6Sandrei 			return (!(regs.cp_edx & 0x100));
3154ef50d8c0Sesaxe 		}
3155ef50d8c0Sesaxe 		return (0);
3156ee88d2b9Skchow 	case 6323525:
3157ee88d2b9Skchow 		return (((((eax >> 12) & 0xff00) + (eax & 0xf00)) |
3158ee88d2b9Skchow 		    (((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0))) < 0xf40);
3159ee88d2b9Skchow 
3160512cf780Skchow 	case 6671130:
3161512cf780Skchow 		/*
3162512cf780Skchow 		 * check for processors (pre-Shanghai) that do not provide
3163512cf780Skchow 		 * optimal management of 1gb ptes in its tlb.
3164512cf780Skchow 		 */
3165512cf780Skchow 		return (cpi->cpi_family == 0x10 && cpi->cpi_model < 4);
3166512cf780Skchow 
3167512cf780Skchow 	case 298:
3168512cf780Skchow 		return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) ||
3169512cf780Skchow 		    DR_B2(eax) || RB_C0(eax));
3170512cf780Skchow 
3171512cf780Skchow 	default:
3172512cf780Skchow 		return (-1);
3173512cf780Skchow 
3174512cf780Skchow 	}
3175512cf780Skchow }
3176512cf780Skchow 
3177512cf780Skchow /*
3178512cf780Skchow  * Determine if specified erratum is present via OSVW (OS Visible Workaround).
3179512cf780Skchow  * Return 1 if erratum is present, 0 if not present and -1 if indeterminate.
3180512cf780Skchow  */
3181512cf780Skchow int
3182512cf780Skchow osvw_opteron_erratum(cpu_t *cpu, uint_t erratum)
3183512cf780Skchow {
3184512cf780Skchow 	struct cpuid_info	*cpi;
3185512cf780Skchow 	uint_t			osvwid;
3186512cf780Skchow 	static int		osvwfeature = -1;
3187512cf780Skchow 	uint64_t		osvwlength;
3188512cf780Skchow 
3189512cf780Skchow 
3190512cf780Skchow 	cpi = cpu->cpu_m.mcpu_cpi;
3191512cf780Skchow 
3192512cf780Skchow 	/* confirm OSVW supported */
3193512cf780Skchow 	if (osvwfeature == -1) {
3194512cf780Skchow 		osvwfeature = cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW;
3195512cf780Skchow 	} else {
3196512cf780Skchow 		/* assert that osvw feature setting is consistent on all cpus */
3197512cf780Skchow 		ASSERT(osvwfeature ==
3198512cf780Skchow 		    (cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW));
3199512cf780Skchow 	}
3200512cf780Skchow 	if (!osvwfeature)
3201512cf780Skchow 		return (-1);
3202512cf780Skchow 
3203512cf780Skchow 	osvwlength = rdmsr(MSR_AMD_OSVW_ID_LEN) & OSVW_ID_LEN_MASK;
3204512cf780Skchow 
3205512cf780Skchow 	switch (erratum) {
3206512cf780Skchow 	case 298:	/* osvwid is 0 */
3207512cf780Skchow 		osvwid = 0;
3208512cf780Skchow 		if (osvwlength <= (uint64_t)osvwid) {
3209512cf780Skchow 			/* osvwid 0 is unknown */
3210512cf780Skchow 			return (-1);
3211512cf780Skchow 		}
3212512cf780Skchow 
3213512cf780Skchow 		/*
3214512cf780Skchow 		 * Check the OSVW STATUS MSR to determine the state
3215512cf780Skchow 		 * of the erratum where:
3216512cf780Skchow 		 *   0 - fixed by HW
3217512cf780Skchow 		 *   1 - BIOS has applied the workaround when BIOS
3218512cf780Skchow 		 *   workaround is available. (Or for other errata,
3219512cf780Skchow 		 *   OS workaround is required.)
3220512cf780Skchow 		 * For a value of 1, caller will confirm that the
3221512cf780Skchow 		 * erratum 298 workaround has indeed been applied by BIOS.
3222512cf780Skchow 		 *
3223512cf780Skchow 		 * A 1 may be set in cpus that have a HW fix
3224512cf780Skchow 		 * in a mixed cpu system. Regarding erratum 298:
3225512cf780Skchow 		 *   In a multiprocessor platform, the workaround above
3226512cf780Skchow 		 *   should be applied to all processors regardless of
3227512cf780Skchow 		 *   silicon revision when an affected processor is
3228512cf780Skchow 		 *   present.
3229512cf780Skchow 		 */
3230512cf780Skchow 
3231512cf780Skchow 		return (rdmsr(MSR_AMD_OSVW_STATUS +
3232512cf780Skchow 		    (osvwid / OSVW_ID_CNT_PER_MSR)) &
3233512cf780Skchow 		    (1ULL << (osvwid % OSVW_ID_CNT_PER_MSR)));
3234512cf780Skchow 
32357c478bd9Sstevel@tonic-gate 	default:
32367c478bd9Sstevel@tonic-gate 		return (-1);
32377c478bd9Sstevel@tonic-gate 	}
32387c478bd9Sstevel@tonic-gate }
32397c478bd9Sstevel@tonic-gate 
32407c478bd9Sstevel@tonic-gate static const char assoc_str[] = "associativity";
32417c478bd9Sstevel@tonic-gate static const char line_str[] = "line-size";
32427c478bd9Sstevel@tonic-gate static const char size_str[] = "size";
32437c478bd9Sstevel@tonic-gate 
32447c478bd9Sstevel@tonic-gate static void
32457c478bd9Sstevel@tonic-gate add_cache_prop(dev_info_t *devi, const char *label, const char *type,
32467c478bd9Sstevel@tonic-gate     uint32_t val)
32477c478bd9Sstevel@tonic-gate {
32487c478bd9Sstevel@tonic-gate 	char buf[128];
32497c478bd9Sstevel@tonic-gate 
32507c478bd9Sstevel@tonic-gate 	/*
32517c478bd9Sstevel@tonic-gate 	 * ndi_prop_update_int() is used because it is desirable for
32527c478bd9Sstevel@tonic-gate 	 * DDI_PROP_HW_DEF and DDI_PROP_DONTSLEEP to be set.
32537c478bd9Sstevel@tonic-gate 	 */
32547c478bd9Sstevel@tonic-gate 	if (snprintf(buf, sizeof (buf), "%s-%s", label, type) < sizeof (buf))
32557c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, buf, val);
32567c478bd9Sstevel@tonic-gate }
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate /*
32597c478bd9Sstevel@tonic-gate  * Intel-style cache/tlb description
32607c478bd9Sstevel@tonic-gate  *
32617c478bd9Sstevel@tonic-gate  * Standard cpuid level 2 gives a randomly ordered
32627c478bd9Sstevel@tonic-gate  * selection of tags that index into a table that describes
32637c478bd9Sstevel@tonic-gate  * cache and tlb properties.
32647c478bd9Sstevel@tonic-gate  */
32657c478bd9Sstevel@tonic-gate 
32667c478bd9Sstevel@tonic-gate static const char l1_icache_str[] = "l1-icache";
32677c478bd9Sstevel@tonic-gate static const char l1_dcache_str[] = "l1-dcache";
32687c478bd9Sstevel@tonic-gate static const char l2_cache_str[] = "l2-cache";
3269ae115bc7Smrj static const char l3_cache_str[] = "l3-cache";
32707c478bd9Sstevel@tonic-gate static const char itlb4k_str[] = "itlb-4K";
32717c478bd9Sstevel@tonic-gate static const char dtlb4k_str[] = "dtlb-4K";
3272824e4fecSvd224797 static const char itlb2M_str[] = "itlb-2M";
32737c478bd9Sstevel@tonic-gate static const char itlb4M_str[] = "itlb-4M";
32747c478bd9Sstevel@tonic-gate static const char dtlb4M_str[] = "dtlb-4M";
327525dfb062Sksadhukh static const char dtlb24_str[] = "dtlb0-2M-4M";
32767c478bd9Sstevel@tonic-gate static const char itlb424_str[] = "itlb-4K-2M-4M";
327725dfb062Sksadhukh static const char itlb24_str[] = "itlb-2M-4M";
32787c478bd9Sstevel@tonic-gate static const char dtlb44_str[] = "dtlb-4K-4M";
32797c478bd9Sstevel@tonic-gate static const char sl1_dcache_str[] = "sectored-l1-dcache";
32807c478bd9Sstevel@tonic-gate static const char sl2_cache_str[] = "sectored-l2-cache";
32817c478bd9Sstevel@tonic-gate static const char itrace_str[] = "itrace-cache";
32827c478bd9Sstevel@tonic-gate static const char sl3_cache_str[] = "sectored-l3-cache";
328325dfb062Sksadhukh static const char sh_l2_tlb4k_str[] = "shared-l2-tlb-4k";
32847c478bd9Sstevel@tonic-gate 
32857c478bd9Sstevel@tonic-gate static const struct cachetab {
32867c478bd9Sstevel@tonic-gate 	uint8_t 	ct_code;
32877c478bd9Sstevel@tonic-gate 	uint8_t		ct_assoc;
32887c478bd9Sstevel@tonic-gate 	uint16_t 	ct_line_size;
32897c478bd9Sstevel@tonic-gate 	size_t		ct_size;
32907c478bd9Sstevel@tonic-gate 	const char	*ct_label;
32917c478bd9Sstevel@tonic-gate } intel_ctab[] = {
3292824e4fecSvd224797 	/*
3293824e4fecSvd224797 	 * maintain descending order!
3294824e4fecSvd224797 	 *
3295824e4fecSvd224797 	 * Codes ignored - Reason
3296824e4fecSvd224797 	 * ----------------------
3297824e4fecSvd224797 	 * 40H - intel_cpuid_4_cache_info() disambiguates l2/l3 cache
3298824e4fecSvd224797 	 * f0H/f1H - Currently we do not interpret prefetch size by design
3299824e4fecSvd224797 	 */
330025dfb062Sksadhukh 	{ 0xe4, 16, 64, 8*1024*1024, l3_cache_str},
330125dfb062Sksadhukh 	{ 0xe3, 16, 64, 4*1024*1024, l3_cache_str},
330225dfb062Sksadhukh 	{ 0xe2, 16, 64, 2*1024*1024, l3_cache_str},
330325dfb062Sksadhukh 	{ 0xde, 12, 64, 6*1024*1024, l3_cache_str},
330425dfb062Sksadhukh 	{ 0xdd, 12, 64, 3*1024*1024, l3_cache_str},
330525dfb062Sksadhukh 	{ 0xdc, 12, 64, ((1*1024*1024)+(512*1024)), l3_cache_str},
330625dfb062Sksadhukh 	{ 0xd8, 8, 64, 4*1024*1024, l3_cache_str},
330725dfb062Sksadhukh 	{ 0xd7, 8, 64, 2*1024*1024, l3_cache_str},
330825dfb062Sksadhukh 	{ 0xd6, 8, 64, 1*1024*1024, l3_cache_str},
330925dfb062Sksadhukh 	{ 0xd2, 4, 64, 2*1024*1024, l3_cache_str},
331025dfb062Sksadhukh 	{ 0xd1, 4, 64, 1*1024*1024, l3_cache_str},
331125dfb062Sksadhukh 	{ 0xd0, 4, 64, 512*1024, l3_cache_str},
331225dfb062Sksadhukh 	{ 0xca, 4, 0, 512, sh_l2_tlb4k_str},
3313824e4fecSvd224797 	{ 0xc0, 4, 0, 8, dtlb44_str },
3314824e4fecSvd224797 	{ 0xba, 4, 0, 64, dtlb4k_str },
3315ae115bc7Smrj 	{ 0xb4, 4, 0, 256, dtlb4k_str },
33167c478bd9Sstevel@tonic-gate 	{ 0xb3, 4, 0, 128, dtlb4k_str },
331725dfb062Sksadhukh 	{ 0xb2, 4, 0, 64, itlb4k_str },
33187c478bd9Sstevel@tonic-gate 	{ 0xb0, 4, 0, 128, itlb4k_str },
33197c478bd9Sstevel@tonic-gate 	{ 0x87, 8, 64, 1024*1024, l2_cache_str},
33207c478bd9Sstevel@tonic-gate 	{ 0x86, 4, 64, 512*1024, l2_cache_str},
33217c478bd9Sstevel@tonic-gate 	{ 0x85, 8, 32, 2*1024*1024, l2_cache_str},
33227c478bd9Sstevel@tonic-gate 	{ 0x84, 8, 32, 1024*1024, l2_cache_str},
33237c478bd9Sstevel@tonic-gate 	{ 0x83, 8, 32, 512*1024, l2_cache_str},
33247c478bd9Sstevel@tonic-gate 	{ 0x82, 8, 32, 256*1024, l2_cache_str},
3325824e4fecSvd224797 	{ 0x80, 8, 64, 512*1024, l2_cache_str},
33267c478bd9Sstevel@tonic-gate 	{ 0x7f, 2, 64, 512*1024, l2_cache_str},
33277c478bd9Sstevel@tonic-gate 	{ 0x7d, 8, 64, 2*1024*1024, sl2_cache_str},
33287c478bd9Sstevel@tonic-gate 	{ 0x7c, 8, 64, 1024*1024, sl2_cache_str},
33297c478bd9Sstevel@tonic-gate 	{ 0x7b, 8, 64, 512*1024, sl2_cache_str},
33307c478bd9Sstevel@tonic-gate 	{ 0x7a, 8, 64, 256*1024, sl2_cache_str},
33317c478bd9Sstevel@tonic-gate 	{ 0x79, 8, 64, 128*1024, sl2_cache_str},
33327c478bd9Sstevel@tonic-gate 	{ 0x78, 8, 64, 1024*1024, l2_cache_str},
3333ae115bc7Smrj 	{ 0x73, 8, 0, 64*1024, itrace_str},
33347c478bd9Sstevel@tonic-gate 	{ 0x72, 8, 0, 32*1024, itrace_str},
33357c478bd9Sstevel@tonic-gate 	{ 0x71, 8, 0, 16*1024, itrace_str},
33367c478bd9Sstevel@tonic-gate 	{ 0x70, 8, 0, 12*1024, itrace_str},
33377c478bd9Sstevel@tonic-gate 	{ 0x68, 4, 64, 32*1024, sl1_dcache_str},
33387c478bd9Sstevel@tonic-gate 	{ 0x67, 4, 64, 16*1024, sl1_dcache_str},
33397c478bd9Sstevel@tonic-gate 	{ 0x66, 4, 64, 8*1024, sl1_dcache_str},
33407c478bd9Sstevel@tonic-gate 	{ 0x60, 8, 64, 16*1024, sl1_dcache_str},
33417c478bd9Sstevel@tonic-gate 	{ 0x5d, 0, 0, 256, dtlb44_str},
33427c478bd9Sstevel@tonic-gate 	{ 0x5c, 0, 0, 128, dtlb44_str},
33437c478bd9Sstevel@tonic-gate 	{ 0x5b, 0, 0, 64, dtlb44_str},
334425dfb062Sksadhukh 	{ 0x5a, 4, 0, 32, dtlb24_str},
3345824e4fecSvd224797 	{ 0x59, 0, 0, 16, dtlb4k_str},
3346824e4fecSvd224797 	{ 0x57, 4, 0, 16, dtlb4k_str},
3347824e4fecSvd224797 	{ 0x56, 4, 0, 16, dtlb4M_str},
334825dfb062Sksadhukh 	{ 0x55, 0, 0, 7, itlb24_str},
33497c478bd9Sstevel@tonic-gate 	{ 0x52, 0, 0, 256, itlb424_str},
33507c478bd9Sstevel@tonic-gate 	{ 0x51, 0, 0, 128, itlb424_str},
33517c478bd9Sstevel@tonic-gate 	{ 0x50, 0, 0, 64, itlb424_str},
3352824e4fecSvd224797 	{ 0x4f, 0, 0, 32, itlb4k_str},
3353824e4fecSvd224797 	{ 0x4e, 24, 64, 6*1024*1024, l2_cache_str},
3354ae115bc7Smrj 	{ 0x4d, 16, 64, 16*1024*1024, l3_cache_str},
3355ae115bc7Smrj 	{ 0x4c, 12, 64, 12*1024*1024, l3_cache_str},
3356ae115bc7Smrj 	{ 0x4b, 16, 64, 8*1024*1024, l3_cache_str},
3357ae115bc7Smrj 	{ 0x4a, 12, 64, 6*1024*1024, l3_cache_str},
3358ae115bc7Smrj 	{ 0x49, 16, 64, 4*1024*1024, l3_cache_str},
3359824e4fecSvd224797 	{ 0x48, 12, 64, 3*1024*1024, l2_cache_str},
3360ae115bc7Smrj 	{ 0x47, 8, 64, 8*1024*1024, l3_cache_str},
3361ae115bc7Smrj 	{ 0x46, 4, 64, 4*1024*1024, l3_cache_str},
33627c478bd9Sstevel@tonic-gate 	{ 0x45, 4, 32, 2*1024*1024, l2_cache_str},
33637c478bd9Sstevel@tonic-gate 	{ 0x44, 4, 32, 1024*1024, l2_cache_str},
33647c478bd9Sstevel@tonic-gate 	{ 0x43, 4, 32, 512*1024, l2_cache_str},
33657c478bd9Sstevel@tonic-gate 	{ 0x42, 4, 32, 256*1024, l2_cache_str},
33667c478bd9Sstevel@tonic-gate 	{ 0x41, 4, 32, 128*1024, l2_cache_str},
3367ae115bc7Smrj 	{ 0x3e, 4, 64, 512*1024, sl2_cache_str},
3368ae115bc7Smrj 	{ 0x3d, 6, 64, 384*1024, sl2_cache_str},
33697c478bd9Sstevel@tonic-gate 	{ 0x3c, 4, 64, 256*1024, sl2_cache_str},
33707c478bd9Sstevel@tonic-gate 	{ 0x3b, 2, 64, 128*1024, sl2_cache_str},
3371ae115bc7Smrj 	{ 0x3a, 6, 64, 192*1024, sl2_cache_str},
33727c478bd9Sstevel@tonic-gate 	{ 0x39, 4, 64, 128*1024, sl2_cache_str},
33737c478bd9Sstevel@tonic-gate 	{ 0x30, 8, 64, 32*1024, l1_icache_str},
33747c478bd9Sstevel@tonic-gate 	{ 0x2c, 8, 64, 32*1024, l1_dcache_str},
33757c478bd9Sstevel@tonic-gate 	{ 0x29, 8, 64, 4096*1024, sl3_cache_str},
33767c478bd9Sstevel@tonic-gate 	{ 0x25, 8, 64, 2048*1024, sl3_cache_str},
33777c478bd9Sstevel@tonic-gate 	{ 0x23, 8, 64, 1024*1024, sl3_cache_str},
33787c478bd9Sstevel@tonic-gate 	{ 0x22, 4, 64, 512*1024, sl3_cache_str},
3379824e4fecSvd224797 	{ 0x0e, 6, 64, 24*1024, l1_dcache_str},
338025dfb062Sksadhukh 	{ 0x0d, 4, 32, 16*1024, l1_dcache_str},
33817c478bd9Sstevel@tonic-gate 	{ 0x0c, 4, 32, 16*1024, l1_dcache_str},
3382ae115bc7Smrj 	{ 0x0b, 4, 0, 4, itlb4M_str},
33837c478bd9Sstevel@tonic-gate 	{ 0x0a, 2, 32, 8*1024, l1_dcache_str},
33847c478bd9Sstevel@tonic-gate 	{ 0x08, 4, 32, 16*1024, l1_icache_str},
33857c478bd9Sstevel@tonic-gate 	{ 0x06, 4, 32, 8*1024, l1_icache_str},
3386824e4fecSvd224797 	{ 0x05, 4, 0, 32, dtlb4M_str},
33877c478bd9Sstevel@tonic-gate 	{ 0x04, 4, 0, 8, dtlb4M_str},
33887c478bd9Sstevel@tonic-gate 	{ 0x03, 4, 0, 64, dtlb4k_str},
33897c478bd9Sstevel@tonic-gate 	{ 0x02, 4, 0, 2, itlb4M_str},
33907c478bd9Sstevel@tonic-gate 	{ 0x01, 4, 0, 32, itlb4k_str},
33917c478bd9Sstevel@tonic-gate 	{ 0 }
33927c478bd9Sstevel@tonic-gate };
33937c478bd9Sstevel@tonic-gate 
33947c478bd9Sstevel@tonic-gate static const struct cachetab cyrix_ctab[] = {
33957c478bd9Sstevel@tonic-gate 	{ 0x70, 4, 0, 32, "tlb-4K" },
33967c478bd9Sstevel@tonic-gate 	{ 0x80, 4, 16, 16*1024, "l1-cache" },
33977c478bd9Sstevel@tonic-gate 	{ 0 }
33987c478bd9Sstevel@tonic-gate };
33997c478bd9Sstevel@tonic-gate 
34007c478bd9Sstevel@tonic-gate /*
34017c478bd9Sstevel@tonic-gate  * Search a cache table for a matching entry
34027c478bd9Sstevel@tonic-gate  */
34037c478bd9Sstevel@tonic-gate static const struct cachetab *
34047c478bd9Sstevel@tonic-gate find_cacheent(const struct cachetab *ct, uint_t code)
34057c478bd9Sstevel@tonic-gate {
34067c478bd9Sstevel@tonic-gate 	if (code != 0) {
34077c478bd9Sstevel@tonic-gate 		for (; ct->ct_code != 0; ct++)
34087c478bd9Sstevel@tonic-gate 			if (ct->ct_code <= code)
34097c478bd9Sstevel@tonic-gate 				break;
34107c478bd9Sstevel@tonic-gate 		if (ct->ct_code == code)
34117c478bd9Sstevel@tonic-gate 			return (ct);
34127c478bd9Sstevel@tonic-gate 	}
34137c478bd9Sstevel@tonic-gate 	return (NULL);
34147c478bd9Sstevel@tonic-gate }
34157c478bd9Sstevel@tonic-gate 
34167c478bd9Sstevel@tonic-gate /*
34177dee861bSksadhukh  * Populate cachetab entry with L2 or L3 cache-information using
34187dee861bSksadhukh  * cpuid function 4. This function is called from intel_walk_cacheinfo()
34197dee861bSksadhukh  * when descriptor 0x49 is encountered. It returns 0 if no such cache
34207dee861bSksadhukh  * information is found.
34217dee861bSksadhukh  */
34227dee861bSksadhukh static int
34237dee861bSksadhukh intel_cpuid_4_cache_info(struct cachetab *ct, struct cpuid_info *cpi)
34247dee861bSksadhukh {
34257dee861bSksadhukh 	uint32_t level, i;
34267dee861bSksadhukh 	int ret = 0;
34277dee861bSksadhukh 
34287dee861bSksadhukh 	for (i = 0; i < cpi->cpi_std_4_size; i++) {
34297dee861bSksadhukh 		level = CPI_CACHE_LVL(cpi->cpi_std_4[i]);
34307dee861bSksadhukh 
34317dee861bSksadhukh 		if (level == 2 || level == 3) {
34327dee861bSksadhukh 			ct->ct_assoc = CPI_CACHE_WAYS(cpi->cpi_std_4[i]) + 1;
34337dee861bSksadhukh 			ct->ct_line_size =
34347dee861bSksadhukh 			    CPI_CACHE_COH_LN_SZ(cpi->cpi_std_4[i]) + 1;
34357dee861bSksadhukh 			ct->ct_size = ct->ct_assoc *
34367dee861bSksadhukh 			    (CPI_CACHE_PARTS(cpi->cpi_std_4[i]) + 1) *
34377dee861bSksadhukh 			    ct->ct_line_size *
34387dee861bSksadhukh 			    (cpi->cpi_std_4[i]->cp_ecx + 1);
34397dee861bSksadhukh 
34407dee861bSksadhukh 			if (level == 2) {
34417dee861bSksadhukh 				ct->ct_label = l2_cache_str;
34427dee861bSksadhukh 			} else if (level == 3) {
34437dee861bSksadhukh 				ct->ct_label = l3_cache_str;
34447dee861bSksadhukh 			}
34457dee861bSksadhukh 			ret = 1;
34467dee861bSksadhukh 		}
34477dee861bSksadhukh 	}
34487dee861bSksadhukh 
34497dee861bSksadhukh 	return (ret);
34507dee861bSksadhukh }
34517dee861bSksadhukh 
34527dee861bSksadhukh /*
34537c478bd9Sstevel@tonic-gate  * Walk the cacheinfo descriptor, applying 'func' to every valid element
34547c478bd9Sstevel@tonic-gate  * The walk is terminated if the walker returns non-zero.
34557c478bd9Sstevel@tonic-gate  */
34567c478bd9Sstevel@tonic-gate static void
34577c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(struct cpuid_info *cpi,
34587c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
34597c478bd9Sstevel@tonic-gate {
34607c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
3461824e4fecSvd224797 	struct cachetab des_49_ct, des_b1_ct;
34627c478bd9Sstevel@tonic-gate 	uint8_t *dp;
34637c478bd9Sstevel@tonic-gate 	int i;
34647c478bd9Sstevel@tonic-gate 
34657c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
34667c478bd9Sstevel@tonic-gate 		return;
3467f1d742a9Sksadhukh 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
3468f1d742a9Sksadhukh 		/*
3469f1d742a9Sksadhukh 		 * For overloaded descriptor 0x49 we use cpuid function 4
34707dee861bSksadhukh 		 * if supported by the current processor, to create
3471f1d742a9Sksadhukh 		 * cache information.
3472824e4fecSvd224797 		 * For overloaded descriptor 0xb1 we use X86_PAE flag
3473824e4fecSvd224797 		 * to disambiguate the cache information.
3474f1d742a9Sksadhukh 		 */
34757dee861bSksadhukh 		if (*dp == 0x49 && cpi->cpi_maxeax >= 0x4 &&
34767dee861bSksadhukh 		    intel_cpuid_4_cache_info(&des_49_ct, cpi) == 1) {
34777dee861bSksadhukh 				ct = &des_49_ct;
3478824e4fecSvd224797 		} else if (*dp == 0xb1) {
3479824e4fecSvd224797 			des_b1_ct.ct_code = 0xb1;
3480824e4fecSvd224797 			des_b1_ct.ct_assoc = 4;
3481824e4fecSvd224797 			des_b1_ct.ct_line_size = 0;
34827417cfdeSKuriakose Kuruvilla 			if (is_x86_feature(x86_featureset, X86FSET_PAE)) {
3483824e4fecSvd224797 				des_b1_ct.ct_size = 8;
3484824e4fecSvd224797 				des_b1_ct.ct_label = itlb2M_str;
3485824e4fecSvd224797 			} else {
3486824e4fecSvd224797 				des_b1_ct.ct_size = 4;
3487824e4fecSvd224797 				des_b1_ct.ct_label = itlb4M_str;
3488824e4fecSvd224797 			}
3489824e4fecSvd224797 			ct = &des_b1_ct;
34907dee861bSksadhukh 		} else {
34917dee861bSksadhukh 			if ((ct = find_cacheent(intel_ctab, *dp)) == NULL) {
3492f1d742a9Sksadhukh 				continue;
3493f1d742a9Sksadhukh 			}
34947dee861bSksadhukh 		}
3495f1d742a9Sksadhukh 
34967dee861bSksadhukh 		if (func(arg, ct) != 0) {
34977c478bd9Sstevel@tonic-gate 			break;
34987c478bd9Sstevel@tonic-gate 		}
34997c478bd9Sstevel@tonic-gate 	}
3500f1d742a9Sksadhukh }
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate /*
35037c478bd9Sstevel@tonic-gate  * (Like the Intel one, except for Cyrix CPUs)
35047c478bd9Sstevel@tonic-gate  */
35057c478bd9Sstevel@tonic-gate static void
35067c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(struct cpuid_info *cpi,
35077c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
35087c478bd9Sstevel@tonic-gate {
35097c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
35107c478bd9Sstevel@tonic-gate 	uint8_t *dp;
35117c478bd9Sstevel@tonic-gate 	int i;
35127c478bd9Sstevel@tonic-gate 
35137c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
35147c478bd9Sstevel@tonic-gate 		return;
35157c478bd9Sstevel@tonic-gate 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
35167c478bd9Sstevel@tonic-gate 		/*
35177c478bd9Sstevel@tonic-gate 		 * Search Cyrix-specific descriptor table first ..
35187c478bd9Sstevel@tonic-gate 		 */
35197c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(cyrix_ctab, *dp)) != NULL) {
35207c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
35217c478bd9Sstevel@tonic-gate 				break;
35227c478bd9Sstevel@tonic-gate 			continue;
35237c478bd9Sstevel@tonic-gate 		}
35247c478bd9Sstevel@tonic-gate 		/*
35257c478bd9Sstevel@tonic-gate 		 * .. else fall back to the Intel one
35267c478bd9Sstevel@tonic-gate 		 */
35277c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(intel_ctab, *dp)) != NULL) {
35287c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
35297c478bd9Sstevel@tonic-gate 				break;
35307c478bd9Sstevel@tonic-gate 			continue;
35317c478bd9Sstevel@tonic-gate 		}
35327c478bd9Sstevel@tonic-gate 	}
35337c478bd9Sstevel@tonic-gate }
35347c478bd9Sstevel@tonic-gate 
35357c478bd9Sstevel@tonic-gate /*
35367c478bd9Sstevel@tonic-gate  * A cacheinfo walker that adds associativity, line-size, and size properties
35377c478bd9Sstevel@tonic-gate  * to the devinfo node it is passed as an argument.
35387c478bd9Sstevel@tonic-gate  */
35397c478bd9Sstevel@tonic-gate static int
35407c478bd9Sstevel@tonic-gate add_cacheent_props(void *arg, const struct cachetab *ct)
35417c478bd9Sstevel@tonic-gate {
35427c478bd9Sstevel@tonic-gate 	dev_info_t *devi = arg;
35437c478bd9Sstevel@tonic-gate 
35447c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, assoc_str, ct->ct_assoc);
35457c478bd9Sstevel@tonic-gate 	if (ct->ct_line_size != 0)
35467c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, ct->ct_label, line_str,
35477c478bd9Sstevel@tonic-gate 		    ct->ct_line_size);
35487c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, size_str, ct->ct_size);
35497c478bd9Sstevel@tonic-gate 	return (0);
35507c478bd9Sstevel@tonic-gate }
35517c478bd9Sstevel@tonic-gate 
3552f1d742a9Sksadhukh 
35537c478bd9Sstevel@tonic-gate static const char fully_assoc[] = "fully-associative?";
35547c478bd9Sstevel@tonic-gate 
35557c478bd9Sstevel@tonic-gate /*
35567c478bd9Sstevel@tonic-gate  * AMD style cache/tlb description
35577c478bd9Sstevel@tonic-gate  *
35587c478bd9Sstevel@tonic-gate  * Extended functions 5 and 6 directly describe properties of
35597c478bd9Sstevel@tonic-gate  * tlbs and various cache levels.
35607c478bd9Sstevel@tonic-gate  */
35617c478bd9Sstevel@tonic-gate static void
35627c478bd9Sstevel@tonic-gate add_amd_assoc(dev_info_t *devi, const char *label, uint_t assoc)
35637c478bd9Sstevel@tonic-gate {
35647c478bd9Sstevel@tonic-gate 	switch (assoc) {
35657c478bd9Sstevel@tonic-gate 	case 0:	/* reserved; ignore */
35667c478bd9Sstevel@tonic-gate 		break;
35677c478bd9Sstevel@tonic-gate 	default:
35687c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
35697c478bd9Sstevel@tonic-gate 		break;
35707c478bd9Sstevel@tonic-gate 	case 0xff:
35717c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
35727c478bd9Sstevel@tonic-gate 		break;
35737c478bd9Sstevel@tonic-gate 	}
35747c478bd9Sstevel@tonic-gate }
35757c478bd9Sstevel@tonic-gate 
35767c478bd9Sstevel@tonic-gate static void
35777c478bd9Sstevel@tonic-gate add_amd_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
35787c478bd9Sstevel@tonic-gate {
35797c478bd9Sstevel@tonic-gate 	if (size == 0)
35807c478bd9Sstevel@tonic-gate 		return;
35817c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
35827c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
35837c478bd9Sstevel@tonic-gate }
35847c478bd9Sstevel@tonic-gate 
35857c478bd9Sstevel@tonic-gate static void
35867c478bd9Sstevel@tonic-gate add_amd_cache(dev_info_t *devi, const char *label,
35877c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
35887c478bd9Sstevel@tonic-gate {
35897c478bd9Sstevel@tonic-gate 	if (size == 0 || line_size == 0)
35907c478bd9Sstevel@tonic-gate 		return;
35917c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
35927c478bd9Sstevel@tonic-gate 	/*
35937c478bd9Sstevel@tonic-gate 	 * Most AMD parts have a sectored cache. Multiple cache lines are
35947c478bd9Sstevel@tonic-gate 	 * associated with each tag. A sector consists of all cache lines
35957c478bd9Sstevel@tonic-gate 	 * associated with a tag. For example, the AMD K6-III has a sector
35967c478bd9Sstevel@tonic-gate 	 * size of 2 cache lines per tag.
35977c478bd9Sstevel@tonic-gate 	 */
35987c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
35997c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
36007c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
36017c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
36027c478bd9Sstevel@tonic-gate }
36037c478bd9Sstevel@tonic-gate 
36047c478bd9Sstevel@tonic-gate static void
36057c478bd9Sstevel@tonic-gate add_amd_l2_assoc(dev_info_t *devi, const char *label, uint_t assoc)
36067c478bd9Sstevel@tonic-gate {
36077c478bd9Sstevel@tonic-gate 	switch (assoc) {
36087c478bd9Sstevel@tonic-gate 	case 0:	/* off */
36097c478bd9Sstevel@tonic-gate 		break;
36107c478bd9Sstevel@tonic-gate 	case 1:
36117c478bd9Sstevel@tonic-gate 	case 2:
36127c478bd9Sstevel@tonic-gate 	case 4:
36137c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
36147c478bd9Sstevel@tonic-gate 		break;
36157c478bd9Sstevel@tonic-gate 	case 6:
36167c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 8);
36177c478bd9Sstevel@tonic-gate 		break;
36187c478bd9Sstevel@tonic-gate 	case 8:
36197c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 16);
36207c478bd9Sstevel@tonic-gate 		break;
36217c478bd9Sstevel@tonic-gate 	case 0xf:
36227c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
36237c478bd9Sstevel@tonic-gate 		break;
36247c478bd9Sstevel@tonic-gate 	default: /* reserved; ignore */
36257c478bd9Sstevel@tonic-gate 		break;
36267c478bd9Sstevel@tonic-gate 	}
36277c478bd9Sstevel@tonic-gate }
36287c478bd9Sstevel@tonic-gate 
36297c478bd9Sstevel@tonic-gate static void
36307c478bd9Sstevel@tonic-gate add_amd_l2_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
36317c478bd9Sstevel@tonic-gate {
36327c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0)
36337c478bd9Sstevel@tonic-gate 		return;
36347c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
36357c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
36367c478bd9Sstevel@tonic-gate }
36377c478bd9Sstevel@tonic-gate 
36387c478bd9Sstevel@tonic-gate static void
36397c478bd9Sstevel@tonic-gate add_amd_l2_cache(dev_info_t *devi, const char *label,
36407c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
36417c478bd9Sstevel@tonic-gate {
36427c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0 || line_size == 0)
36437c478bd9Sstevel@tonic-gate 		return;
36447c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
36457c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
36467c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
36477c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
36487c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
36497c478bd9Sstevel@tonic-gate }
36507c478bd9Sstevel@tonic-gate 
36517c478bd9Sstevel@tonic-gate static void
36527c478bd9Sstevel@tonic-gate amd_cache_info(struct cpuid_info *cpi, dev_info_t *devi)
36537c478bd9Sstevel@tonic-gate {
36548949bcd6Sandrei 	struct cpuid_regs *cp;
36557c478bd9Sstevel@tonic-gate 
36567c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000005)
36577c478bd9Sstevel@tonic-gate 		return;
36587c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[5];
36597c478bd9Sstevel@tonic-gate 
36607c478bd9Sstevel@tonic-gate 	/*
36617c478bd9Sstevel@tonic-gate 	 * 4M/2M L1 TLB configuration
36627c478bd9Sstevel@tonic-gate 	 *
36637c478bd9Sstevel@tonic-gate 	 * We report the size for 2M pages because AMD uses two
36647c478bd9Sstevel@tonic-gate 	 * TLB entries for one 4M page.
36657c478bd9Sstevel@tonic-gate 	 */
36667c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "dtlb-2M",
36677c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 31, 24), BITX(cp->cp_eax, 23, 16));
36687c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "itlb-2M",
36697c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 15, 8), BITX(cp->cp_eax, 7, 0));
36707c478bd9Sstevel@tonic-gate 
36717c478bd9Sstevel@tonic-gate 	/*
36727c478bd9Sstevel@tonic-gate 	 * 4K L1 TLB configuration
36737c478bd9Sstevel@tonic-gate 	 */
36747c478bd9Sstevel@tonic-gate 
36757c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
36767c478bd9Sstevel@tonic-gate 		uint_t nentries;
36777c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
36787c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5) {
36797c478bd9Sstevel@tonic-gate 			/*
36807c478bd9Sstevel@tonic-gate 			 * Crusoe processors have 256 TLB entries, but
36817c478bd9Sstevel@tonic-gate 			 * cpuid data format constrains them to only
36827c478bd9Sstevel@tonic-gate 			 * reporting 255 of them.
36837c478bd9Sstevel@tonic-gate 			 */
36847c478bd9Sstevel@tonic-gate 			if ((nentries = BITX(cp->cp_ebx, 23, 16)) == 255)
36857c478bd9Sstevel@tonic-gate 				nentries = 256;
36867c478bd9Sstevel@tonic-gate 			/*
36877c478bd9Sstevel@tonic-gate 			 * Crusoe processors also have a unified TLB
36887c478bd9Sstevel@tonic-gate 			 */
36897c478bd9Sstevel@tonic-gate 			add_amd_tlb(devi, "tlb-4K", BITX(cp->cp_ebx, 31, 24),
36907c478bd9Sstevel@tonic-gate 			    nentries);
36917c478bd9Sstevel@tonic-gate 			break;
36927c478bd9Sstevel@tonic-gate 		}
36937c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
36947c478bd9Sstevel@tonic-gate 	default:
36957c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, itlb4k_str,
36967c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 31, 24), BITX(cp->cp_ebx, 23, 16));
36977c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, dtlb4k_str,
36987c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 15, 8), BITX(cp->cp_ebx, 7, 0));
36997c478bd9Sstevel@tonic-gate 		break;
37007c478bd9Sstevel@tonic-gate 	}
37017c478bd9Sstevel@tonic-gate 
37027c478bd9Sstevel@tonic-gate 	/*
37037c478bd9Sstevel@tonic-gate 	 * data L1 cache configuration
37047c478bd9Sstevel@tonic-gate 	 */
37057c478bd9Sstevel@tonic-gate 
37067c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_dcache_str,
37077c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 24), BITX(cp->cp_ecx, 23, 16),
37087c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 15, 8), BITX(cp->cp_ecx, 7, 0));
37097c478bd9Sstevel@tonic-gate 
37107c478bd9Sstevel@tonic-gate 	/*
37117c478bd9Sstevel@tonic-gate 	 * code L1 cache configuration
37127c478bd9Sstevel@tonic-gate 	 */
37137c478bd9Sstevel@tonic-gate 
37147c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_icache_str,
37157c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 31, 24), BITX(cp->cp_edx, 23, 16),
37167c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 15, 8), BITX(cp->cp_edx, 7, 0));
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
37197c478bd9Sstevel@tonic-gate 		return;
37207c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for large pages */
37237c478bd9Sstevel@tonic-gate 
37247c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_eax, 31, 16) == 0)
37257c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-2M",
37267c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
37277c478bd9Sstevel@tonic-gate 	else {
37287c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-2M",
37297c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
37307c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-2M",
37317c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
37327c478bd9Sstevel@tonic-gate 	}
37337c478bd9Sstevel@tonic-gate 
37347c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for 4K pages */
37357c478bd9Sstevel@tonic-gate 
37367c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_ebx, 31, 16) == 0) {
37377c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-4K",
37387c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
37397c478bd9Sstevel@tonic-gate 	} else {
37407c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-4K",
37417c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
37427c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-4K",
37437c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
37447c478bd9Sstevel@tonic-gate 	}
37457c478bd9Sstevel@tonic-gate 
37467c478bd9Sstevel@tonic-gate 	add_amd_l2_cache(devi, l2_cache_str,
37477c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 16), BITX(cp->cp_ecx, 15, 12),
37487c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 11, 8), BITX(cp->cp_ecx, 7, 0));
37497c478bd9Sstevel@tonic-gate }
37507c478bd9Sstevel@tonic-gate 
37517c478bd9Sstevel@tonic-gate /*
37527c478bd9Sstevel@tonic-gate  * There are two basic ways that the x86 world describes it cache
37537c478bd9Sstevel@tonic-gate  * and tlb architecture - Intel's way and AMD's way.
37547c478bd9Sstevel@tonic-gate  *
37557c478bd9Sstevel@tonic-gate  * Return which flavor of cache architecture we should use
37567c478bd9Sstevel@tonic-gate  */
37577c478bd9Sstevel@tonic-gate static int
37587c478bd9Sstevel@tonic-gate x86_which_cacheinfo(struct cpuid_info *cpi)
37597c478bd9Sstevel@tonic-gate {
37607c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
37617c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
37627c478bd9Sstevel@tonic-gate 		if (cpi->cpi_maxeax >= 2)
37637c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
37647c478bd9Sstevel@tonic-gate 		break;
37657c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
37667c478bd9Sstevel@tonic-gate 		/*
37677c478bd9Sstevel@tonic-gate 		 * The K5 model 1 was the first part from AMD that reported
37687c478bd9Sstevel@tonic-gate 		 * cache sizes via extended cpuid functions.
37697c478bd9Sstevel@tonic-gate 		 */
37707c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
37717c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
37727c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
37737c478bd9Sstevel@tonic-gate 		break;
37747c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
37757c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5)
37767c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
37777c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
37787c478bd9Sstevel@tonic-gate 	default:
37797c478bd9Sstevel@tonic-gate 		/*
37807c478bd9Sstevel@tonic-gate 		 * If they have extended CPU data for 0x80000005
37817c478bd9Sstevel@tonic-gate 		 * then we assume they have AMD-format cache
37827c478bd9Sstevel@tonic-gate 		 * information.
37837c478bd9Sstevel@tonic-gate 		 *
37847c478bd9Sstevel@tonic-gate 		 * If not, and the vendor happens to be Cyrix,
37857c478bd9Sstevel@tonic-gate 		 * then try our-Cyrix specific handler.
37867c478bd9Sstevel@tonic-gate 		 *
37877c478bd9Sstevel@tonic-gate 		 * If we're not Cyrix, then assume we're using Intel's
37887c478bd9Sstevel@tonic-gate 		 * table-driven format instead.
37897c478bd9Sstevel@tonic-gate 		 */
37907c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax >= 0x80000005)
37917c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
37927c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_vendor == X86_VENDOR_Cyrix)
37937c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Cyrix);
37947c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_maxeax >= 2)
37957c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
37967c478bd9Sstevel@tonic-gate 		break;
37977c478bd9Sstevel@tonic-gate 	}
37987c478bd9Sstevel@tonic-gate 	return (-1);
37997c478bd9Sstevel@tonic-gate }
38007c478bd9Sstevel@tonic-gate 
38017c478bd9Sstevel@tonic-gate void
3802fa96bd91SMichael Corcoran cpuid_set_cpu_properties(void *dip, processorid_t cpu_id,
3803fa96bd91SMichael Corcoran     struct cpuid_info *cpi)
38047c478bd9Sstevel@tonic-gate {
38057c478bd9Sstevel@tonic-gate 	dev_info_t *cpu_devi;
38067c478bd9Sstevel@tonic-gate 	int create;
38077c478bd9Sstevel@tonic-gate 
3808fa96bd91SMichael Corcoran 	cpu_devi = (dev_info_t *)dip;
38097c478bd9Sstevel@tonic-gate 
38107c478bd9Sstevel@tonic-gate 	/* device_type */
38117c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
38127c478bd9Sstevel@tonic-gate 	    "device_type", "cpu");
38137c478bd9Sstevel@tonic-gate 
38147c478bd9Sstevel@tonic-gate 	/* reg */
38157c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38167c478bd9Sstevel@tonic-gate 	    "reg", cpu_id);
38177c478bd9Sstevel@tonic-gate 
38187c478bd9Sstevel@tonic-gate 	/* cpu-mhz, and clock-frequency */
38197c478bd9Sstevel@tonic-gate 	if (cpu_freq > 0) {
38207c478bd9Sstevel@tonic-gate 		long long mul;
38217c478bd9Sstevel@tonic-gate 
38227c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38237c478bd9Sstevel@tonic-gate 		    "cpu-mhz", cpu_freq);
38247c478bd9Sstevel@tonic-gate 		if ((mul = cpu_freq * 1000000LL) <= INT_MAX)
38257c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38267c478bd9Sstevel@tonic-gate 			    "clock-frequency", (int)mul);
38277c478bd9Sstevel@tonic-gate 	}
38287c478bd9Sstevel@tonic-gate 
38297417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) {
38307c478bd9Sstevel@tonic-gate 		return;
38317c478bd9Sstevel@tonic-gate 	}
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate 	/* vendor-id */
38347c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
38357c478bd9Sstevel@tonic-gate 	    "vendor-id", cpi->cpi_vendorstr);
38367c478bd9Sstevel@tonic-gate 
38377c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax == 0) {
38387c478bd9Sstevel@tonic-gate 		return;
38397c478bd9Sstevel@tonic-gate 	}
38407c478bd9Sstevel@tonic-gate 
38417c478bd9Sstevel@tonic-gate 	/*
38427c478bd9Sstevel@tonic-gate 	 * family, model, and step
38437c478bd9Sstevel@tonic-gate 	 */
38447c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38457c478bd9Sstevel@tonic-gate 	    "family", CPI_FAMILY(cpi));
38467c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38477c478bd9Sstevel@tonic-gate 	    "cpu-model", CPI_MODEL(cpi));
38487c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38497c478bd9Sstevel@tonic-gate 	    "stepping-id", CPI_STEP(cpi));
38507c478bd9Sstevel@tonic-gate 
38517c478bd9Sstevel@tonic-gate 	/* type */
38527c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
38537c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
38547c478bd9Sstevel@tonic-gate 		create = 1;
38557c478bd9Sstevel@tonic-gate 		break;
38567c478bd9Sstevel@tonic-gate 	default:
38577c478bd9Sstevel@tonic-gate 		create = 0;
38587c478bd9Sstevel@tonic-gate 		break;
38597c478bd9Sstevel@tonic-gate 	}
38607c478bd9Sstevel@tonic-gate 	if (create)
38617c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38627c478bd9Sstevel@tonic-gate 		    "type", CPI_TYPE(cpi));
38637c478bd9Sstevel@tonic-gate 
38647c478bd9Sstevel@tonic-gate 	/* ext-family */
38657c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
38667c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
38677c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
38687c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
38697c478bd9Sstevel@tonic-gate 		break;
38707c478bd9Sstevel@tonic-gate 	default:
38717c478bd9Sstevel@tonic-gate 		create = 0;
38727c478bd9Sstevel@tonic-gate 		break;
38737c478bd9Sstevel@tonic-gate 	}
38747c478bd9Sstevel@tonic-gate 	if (create)
38757c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38767c478bd9Sstevel@tonic-gate 		    "ext-family", CPI_FAMILY_XTD(cpi));
38777c478bd9Sstevel@tonic-gate 
38787c478bd9Sstevel@tonic-gate 	/* ext-model */
38797c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
38807c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
388163d3f7dfSkk208521 		create = IS_EXTENDED_MODEL_INTEL(cpi);
388268c91426Sdmick 		break;
38837c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
3884ee88d2b9Skchow 		create = CPI_FAMILY(cpi) == 0xf;
38857c478bd9Sstevel@tonic-gate 		break;
38867c478bd9Sstevel@tonic-gate 	default:
38877c478bd9Sstevel@tonic-gate 		create = 0;
38887c478bd9Sstevel@tonic-gate 		break;
38897c478bd9Sstevel@tonic-gate 	}
38907c478bd9Sstevel@tonic-gate 	if (create)
38917c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
38927c478bd9Sstevel@tonic-gate 		    "ext-model", CPI_MODEL_XTD(cpi));
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate 	/* generation */
38957c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
38967c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
38977c478bd9Sstevel@tonic-gate 		/*
38987c478bd9Sstevel@tonic-gate 		 * AMD K5 model 1 was the first part to support this
38997c478bd9Sstevel@tonic-gate 		 */
39007c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
39017c478bd9Sstevel@tonic-gate 		break;
39027c478bd9Sstevel@tonic-gate 	default:
39037c478bd9Sstevel@tonic-gate 		create = 0;
39047c478bd9Sstevel@tonic-gate 		break;
39057c478bd9Sstevel@tonic-gate 	}
39067c478bd9Sstevel@tonic-gate 	if (create)
39077c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39087c478bd9Sstevel@tonic-gate 		    "generation", BITX((cpi)->cpi_extd[1].cp_eax, 11, 8));
39097c478bd9Sstevel@tonic-gate 
39107c478bd9Sstevel@tonic-gate 	/* brand-id */
39117c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
39127c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
39137c478bd9Sstevel@tonic-gate 		/*
39147c478bd9Sstevel@tonic-gate 		 * brand id first appeared on Pentium III Xeon model 8,
39157c478bd9Sstevel@tonic-gate 		 * and Celeron model 8 processors and Opteron
39167c478bd9Sstevel@tonic-gate 		 */
39177c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family > 6 ||
39187c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 6 && cpi->cpi_model >= 8);
39197c478bd9Sstevel@tonic-gate 		break;
39207c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
39217c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
39227c478bd9Sstevel@tonic-gate 		break;
39237c478bd9Sstevel@tonic-gate 	default:
39247c478bd9Sstevel@tonic-gate 		create = 0;
39257c478bd9Sstevel@tonic-gate 		break;
39267c478bd9Sstevel@tonic-gate 	}
39277c478bd9Sstevel@tonic-gate 	if (create && cpi->cpi_brandid != 0) {
39287c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39297c478bd9Sstevel@tonic-gate 		    "brand-id", cpi->cpi_brandid);
39307c478bd9Sstevel@tonic-gate 	}
39317c478bd9Sstevel@tonic-gate 
39327c478bd9Sstevel@tonic-gate 	/* chunks, and apic-id */
39337c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
39347c478bd9Sstevel@tonic-gate 		/*
39357c478bd9Sstevel@tonic-gate 		 * first available on Pentium IV and Opteron (K8)
39367c478bd9Sstevel@tonic-gate 		 */
39375ff02082Sdmick 	case X86_VENDOR_Intel:
39385ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
39395ff02082Sdmick 		break;
39405ff02082Sdmick 	case X86_VENDOR_AMD:
39417c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
39427c478bd9Sstevel@tonic-gate 		break;
39437c478bd9Sstevel@tonic-gate 	default:
39447c478bd9Sstevel@tonic-gate 		create = 0;
39457c478bd9Sstevel@tonic-gate 		break;
39467c478bd9Sstevel@tonic-gate 	}
39477c478bd9Sstevel@tonic-gate 	if (create) {
39487c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39497c478bd9Sstevel@tonic-gate 		    "chunks", CPI_CHUNKS(cpi));
39507c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
3951b6917abeSmishra 		    "apic-id", cpi->cpi_apicid);
39527aec1d6eScindi 		if (cpi->cpi_chipid >= 0) {
39537c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39547c478bd9Sstevel@tonic-gate 			    "chip#", cpi->cpi_chipid);
39557aec1d6eScindi 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39567aec1d6eScindi 			    "clog#", cpi->cpi_clogid);
39577aec1d6eScindi 		}
39587c478bd9Sstevel@tonic-gate 	}
39597c478bd9Sstevel@tonic-gate 
39607c478bd9Sstevel@tonic-gate 	/* cpuid-features */
39617c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39627c478bd9Sstevel@tonic-gate 	    "cpuid-features", CPI_FEATURES_EDX(cpi));
39637c478bd9Sstevel@tonic-gate 
39647c478bd9Sstevel@tonic-gate 
39657c478bd9Sstevel@tonic-gate 	/* cpuid-features-ecx */
39667c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
39677c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
39685ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
39697c478bd9Sstevel@tonic-gate 		break;
39707c478bd9Sstevel@tonic-gate 	default:
39717c478bd9Sstevel@tonic-gate 		create = 0;
39727c478bd9Sstevel@tonic-gate 		break;
39737c478bd9Sstevel@tonic-gate 	}
39747c478bd9Sstevel@tonic-gate 	if (create)
39757c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39767c478bd9Sstevel@tonic-gate 		    "cpuid-features-ecx", CPI_FEATURES_ECX(cpi));
39777c478bd9Sstevel@tonic-gate 
39787c478bd9Sstevel@tonic-gate 	/* ext-cpuid-features */
39797c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
39805ff02082Sdmick 	case X86_VENDOR_Intel:
39817c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
39827c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
39837c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
39847c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
39857c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
39867c478bd9Sstevel@tonic-gate 		break;
39877c478bd9Sstevel@tonic-gate 	default:
39887c478bd9Sstevel@tonic-gate 		create = 0;
39897c478bd9Sstevel@tonic-gate 		break;
39907c478bd9Sstevel@tonic-gate 	}
39915ff02082Sdmick 	if (create) {
39927c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39937c478bd9Sstevel@tonic-gate 		    "ext-cpuid-features", CPI_FEATURES_XTD_EDX(cpi));
39945ff02082Sdmick 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39955ff02082Sdmick 		    "ext-cpuid-features-ecx", CPI_FEATURES_XTD_ECX(cpi));
39965ff02082Sdmick 	}
39977c478bd9Sstevel@tonic-gate 
39987c478bd9Sstevel@tonic-gate 	/*
39997c478bd9Sstevel@tonic-gate 	 * Brand String first appeared in Intel Pentium IV, AMD K5
40007c478bd9Sstevel@tonic-gate 	 * model 1, and Cyrix GXm.  On earlier models we try and
40017c478bd9Sstevel@tonic-gate 	 * simulate something similar .. so this string should always
40027c478bd9Sstevel@tonic-gate 	 * same -something- about the processor, however lame.
40037c478bd9Sstevel@tonic-gate 	 */
40047c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
40057c478bd9Sstevel@tonic-gate 	    "brand-string", cpi->cpi_brandstr);
40067c478bd9Sstevel@tonic-gate 
40077c478bd9Sstevel@tonic-gate 	/*
40087c478bd9Sstevel@tonic-gate 	 * Finally, cache and tlb information
40097c478bd9Sstevel@tonic-gate 	 */
40107c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
40117c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
40127c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
40137c478bd9Sstevel@tonic-gate 		break;
40147c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
40157c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
40167c478bd9Sstevel@tonic-gate 		break;
40177c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
40187c478bd9Sstevel@tonic-gate 		amd_cache_info(cpi, cpu_devi);
40197c478bd9Sstevel@tonic-gate 		break;
40207c478bd9Sstevel@tonic-gate 	default:
40217c478bd9Sstevel@tonic-gate 		break;
40227c478bd9Sstevel@tonic-gate 	}
40237c478bd9Sstevel@tonic-gate }
40247c478bd9Sstevel@tonic-gate 
40257c478bd9Sstevel@tonic-gate struct l2info {
40267c478bd9Sstevel@tonic-gate 	int *l2i_csz;
40277c478bd9Sstevel@tonic-gate 	int *l2i_lsz;
40287c478bd9Sstevel@tonic-gate 	int *l2i_assoc;
40297c478bd9Sstevel@tonic-gate 	int l2i_ret;
40307c478bd9Sstevel@tonic-gate };
40317c478bd9Sstevel@tonic-gate 
40327c478bd9Sstevel@tonic-gate /*
40337c478bd9Sstevel@tonic-gate  * A cacheinfo walker that fetches the size, line-size and associativity
40347c478bd9Sstevel@tonic-gate  * of the L2 cache
40357c478bd9Sstevel@tonic-gate  */
40367c478bd9Sstevel@tonic-gate static int
40377c478bd9Sstevel@tonic-gate intel_l2cinfo(void *arg, const struct cachetab *ct)
40387c478bd9Sstevel@tonic-gate {
40397c478bd9Sstevel@tonic-gate 	struct l2info *l2i = arg;
40407c478bd9Sstevel@tonic-gate 	int *ip;
40417c478bd9Sstevel@tonic-gate 
40427c478bd9Sstevel@tonic-gate 	if (ct->ct_label != l2_cache_str &&
40437c478bd9Sstevel@tonic-gate 	    ct->ct_label != sl2_cache_str)
40447c478bd9Sstevel@tonic-gate 		return (0);	/* not an L2 -- keep walking */
40457c478bd9Sstevel@tonic-gate 
40467c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_csz) != NULL)
40477c478bd9Sstevel@tonic-gate 		*ip = ct->ct_size;
40487c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_lsz) != NULL)
40497c478bd9Sstevel@tonic-gate 		*ip = ct->ct_line_size;
40507c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_assoc) != NULL)
40517c478bd9Sstevel@tonic-gate 		*ip = ct->ct_assoc;
40527c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = ct->ct_size;
40537c478bd9Sstevel@tonic-gate 	return (1);		/* was an L2 -- terminate walk */
40547c478bd9Sstevel@tonic-gate }
40557c478bd9Sstevel@tonic-gate 
4056606303c9Skchow /*
4057606303c9Skchow  * AMD L2/L3 Cache and TLB Associativity Field Definition:
4058606303c9Skchow  *
4059606303c9Skchow  *	Unlike the associativity for the L1 cache and tlb where the 8 bit
4060606303c9Skchow  *	value is the associativity, the associativity for the L2 cache and
4061606303c9Skchow  *	tlb is encoded in the following table. The 4 bit L2 value serves as
4062606303c9Skchow  *	an index into the amd_afd[] array to determine the associativity.
4063606303c9Skchow  *	-1 is undefined. 0 is fully associative.
4064606303c9Skchow  */
4065606303c9Skchow 
4066606303c9Skchow static int amd_afd[] =
4067606303c9Skchow 	{-1, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, 0};
4068606303c9Skchow 
40697c478bd9Sstevel@tonic-gate static void
40707c478bd9Sstevel@tonic-gate amd_l2cacheinfo(struct cpuid_info *cpi, struct l2info *l2i)
40717c478bd9Sstevel@tonic-gate {
40728949bcd6Sandrei 	struct cpuid_regs *cp;
40737c478bd9Sstevel@tonic-gate 	uint_t size, assoc;
4074606303c9Skchow 	int i;
40757c478bd9Sstevel@tonic-gate 	int *ip;
40767c478bd9Sstevel@tonic-gate 
40777c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
40787c478bd9Sstevel@tonic-gate 		return;
40797c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
40807c478bd9Sstevel@tonic-gate 
4081606303c9Skchow 	if ((i = BITX(cp->cp_ecx, 15, 12)) != 0 &&
40827c478bd9Sstevel@tonic-gate 	    (size = BITX(cp->cp_ecx, 31, 16)) != 0) {
40837c478bd9Sstevel@tonic-gate 		uint_t cachesz = size * 1024;
4084606303c9Skchow 		assoc = amd_afd[i];
40857c478bd9Sstevel@tonic-gate 
4086606303c9Skchow 		ASSERT(assoc != -1);
40877c478bd9Sstevel@tonic-gate 
40887c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_csz) != NULL)
40897c478bd9Sstevel@tonic-gate 			*ip = cachesz;
40907c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_lsz) != NULL)
40917c478bd9Sstevel@tonic-gate 			*ip = BITX(cp->cp_ecx, 7, 0);
40927c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_assoc) != NULL)
40937c478bd9Sstevel@tonic-gate 			*ip = assoc;
40947c478bd9Sstevel@tonic-gate 		l2i->l2i_ret = cachesz;
40957c478bd9Sstevel@tonic-gate 	}
40967c478bd9Sstevel@tonic-gate }
40977c478bd9Sstevel@tonic-gate 
40987c478bd9Sstevel@tonic-gate int
40997c478bd9Sstevel@tonic-gate getl2cacheinfo(cpu_t *cpu, int *csz, int *lsz, int *assoc)
41007c478bd9Sstevel@tonic-gate {
41017c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
41027c478bd9Sstevel@tonic-gate 	struct l2info __l2info, *l2i = &__l2info;
41037c478bd9Sstevel@tonic-gate 
41047c478bd9Sstevel@tonic-gate 	l2i->l2i_csz = csz;
41057c478bd9Sstevel@tonic-gate 	l2i->l2i_lsz = lsz;
41067c478bd9Sstevel@tonic-gate 	l2i->l2i_assoc = assoc;
41077c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = -1;
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
41107c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41117c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
41127c478bd9Sstevel@tonic-gate 		break;
41137c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
41147c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
41157c478bd9Sstevel@tonic-gate 		break;
41167c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41177c478bd9Sstevel@tonic-gate 		amd_l2cacheinfo(cpi, l2i);
41187c478bd9Sstevel@tonic-gate 		break;
41197c478bd9Sstevel@tonic-gate 	default:
41207c478bd9Sstevel@tonic-gate 		break;
41217c478bd9Sstevel@tonic-gate 	}
41227c478bd9Sstevel@tonic-gate 	return (l2i->l2i_ret);
41237c478bd9Sstevel@tonic-gate }
4124f98fbcecSbholler 
4125843e1988Sjohnlev #if !defined(__xpv)
4126843e1988Sjohnlev 
41275b8a6efeSbholler uint32_t *
41285b8a6efeSbholler cpuid_mwait_alloc(cpu_t *cpu)
41295b8a6efeSbholler {
41305b8a6efeSbholler 	uint32_t	*ret;
41315b8a6efeSbholler 	size_t		mwait_size;
41325b8a6efeSbholler 
4133a3114836SGerry Liu 	ASSERT(cpuid_checkpass(CPU, 2));
41345b8a6efeSbholler 
4135a3114836SGerry Liu 	mwait_size = CPU->cpu_m.mcpu_cpi->cpi_mwait.mon_max;
41365b8a6efeSbholler 	if (mwait_size == 0)
41375b8a6efeSbholler 		return (NULL);
41385b8a6efeSbholler 
41395b8a6efeSbholler 	/*
41405b8a6efeSbholler 	 * kmem_alloc() returns cache line size aligned data for mwait_size
41415b8a6efeSbholler 	 * allocations.  mwait_size is currently cache line sized.  Neither
41425b8a6efeSbholler 	 * of these implementation details are guarantied to be true in the
41435b8a6efeSbholler 	 * future.
41445b8a6efeSbholler 	 *
41455b8a6efeSbholler 	 * First try allocating mwait_size as kmem_alloc() currently returns
41465b8a6efeSbholler 	 * correctly aligned memory.  If kmem_alloc() does not return
41475b8a6efeSbholler 	 * mwait_size aligned memory, then use mwait_size ROUNDUP.
41485b8a6efeSbholler 	 *
41495b8a6efeSbholler 	 * Set cpi_mwait.buf_actual and cpi_mwait.size_actual in case we
41505b8a6efeSbholler 	 * decide to free this memory.
41515b8a6efeSbholler 	 */
41525b8a6efeSbholler 	ret = kmem_zalloc(mwait_size, KM_SLEEP);
41535b8a6efeSbholler 	if (ret == (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size)) {
41545b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
41555b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size;
41565b8a6efeSbholler 		*ret = MWAIT_RUNNING;
41575b8a6efeSbholler 		return (ret);
41585b8a6efeSbholler 	} else {
41595b8a6efeSbholler 		kmem_free(ret, mwait_size);
41605b8a6efeSbholler 		ret = kmem_zalloc(mwait_size * 2, KM_SLEEP);
41615b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
41625b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size * 2;
41635b8a6efeSbholler 		ret = (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size);
41645b8a6efeSbholler 		*ret = MWAIT_RUNNING;
41655b8a6efeSbholler 		return (ret);
41665b8a6efeSbholler 	}
41675b8a6efeSbholler }
41685b8a6efeSbholler 
41695b8a6efeSbholler void
41705b8a6efeSbholler cpuid_mwait_free(cpu_t *cpu)
4171f98fbcecSbholler {
4172a3114836SGerry Liu 	if (cpu->cpu_m.mcpu_cpi == NULL) {
4173a3114836SGerry Liu 		return;
4174a3114836SGerry Liu 	}
41755b8a6efeSbholler 
41765b8a6efeSbholler 	if (cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual != NULL &&
41775b8a6efeSbholler 	    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual > 0) {
41785b8a6efeSbholler 		kmem_free(cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual,
41795b8a6efeSbholler 		    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual);
41805b8a6efeSbholler 	}
41815b8a6efeSbholler 
41825b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = NULL;
41835b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = 0;
4184f98fbcecSbholler }
4185843e1988Sjohnlev 
4186247dbb3dSsudheer void
4187247dbb3dSsudheer patch_tsc_read(int flag)
4188247dbb3dSsudheer {
4189247dbb3dSsudheer 	size_t cnt;
4190e4b86885SCheng Sean Ye 
4191247dbb3dSsudheer 	switch (flag) {
4192247dbb3dSsudheer 	case X86_NO_TSC:
4193247dbb3dSsudheer 		cnt = &_no_rdtsc_end - &_no_rdtsc_start;
41942b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt);
4195247dbb3dSsudheer 		break;
4196247dbb3dSsudheer 	case X86_HAVE_TSCP:
4197247dbb3dSsudheer 		cnt = &_tscp_end - &_tscp_start;
41982b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt);
4199247dbb3dSsudheer 		break;
4200247dbb3dSsudheer 	case X86_TSC_MFENCE:
4201247dbb3dSsudheer 		cnt = &_tsc_mfence_end - &_tsc_mfence_start;
42022b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read,
42032b0bcb26Ssudheer 		    (void *)&_tsc_mfence_start, cnt);
4204247dbb3dSsudheer 		break;
420515363b27Ssudheer 	case X86_TSC_LFENCE:
420615363b27Ssudheer 		cnt = &_tsc_lfence_end - &_tsc_lfence_start;
420715363b27Ssudheer 		(void) memcpy((void *)tsc_read,
420815363b27Ssudheer 		    (void *)&_tsc_lfence_start, cnt);
420915363b27Ssudheer 		break;
4210247dbb3dSsudheer 	default:
4211247dbb3dSsudheer 		break;
4212247dbb3dSsudheer 	}
4213247dbb3dSsudheer }
4214247dbb3dSsudheer 
42150e751525SEric Saxe int
42160e751525SEric Saxe cpuid_deep_cstates_supported(void)
42170e751525SEric Saxe {
42180e751525SEric Saxe 	struct cpuid_info *cpi;
42190e751525SEric Saxe 	struct cpuid_regs regs;
42200e751525SEric Saxe 
42210e751525SEric Saxe 	ASSERT(cpuid_checkpass(CPU, 1));
42220e751525SEric Saxe 
42230e751525SEric Saxe 	cpi = CPU->cpu_m.mcpu_cpi;
42240e751525SEric Saxe 
42257417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID))
42260e751525SEric Saxe 		return (0);
42270e751525SEric Saxe 
42280e751525SEric Saxe 	switch (cpi->cpi_vendor) {
42290e751525SEric Saxe 	case X86_VENDOR_Intel:
42300e751525SEric Saxe 		if (cpi->cpi_xmaxeax < 0x80000007)
42310e751525SEric Saxe 			return (0);
42320e751525SEric Saxe 
42330e751525SEric Saxe 		/*
42340e751525SEric Saxe 		 * TSC run at a constant rate in all ACPI C-states?
42350e751525SEric Saxe 		 */
42360e751525SEric Saxe 		regs.cp_eax = 0x80000007;
42370e751525SEric Saxe 		(void) __cpuid_insn(&regs);
42380e751525SEric Saxe 		return (regs.cp_edx & CPUID_TSC_CSTATE_INVARIANCE);
42390e751525SEric Saxe 
42400e751525SEric Saxe 	default:
42410e751525SEric Saxe 		return (0);
42420e751525SEric Saxe 	}
42430e751525SEric Saxe }
42440e751525SEric Saxe 
4245e774b42bSBill Holler #endif	/* !__xpv */
4246e774b42bSBill Holler 
4247e774b42bSBill Holler void
4248e774b42bSBill Holler post_startup_cpu_fixups(void)
4249e774b42bSBill Holler {
4250e774b42bSBill Holler #ifndef __xpv
4251e774b42bSBill Holler 	/*
4252e774b42bSBill Holler 	 * Some AMD processors support C1E state. Entering this state will
4253e774b42bSBill Holler 	 * cause the local APIC timer to stop, which we can't deal with at
4254e774b42bSBill Holler 	 * this time.
4255e774b42bSBill Holler 	 */
4256e774b42bSBill Holler 	if (cpuid_getvendor(CPU) == X86_VENDOR_AMD) {
4257e774b42bSBill Holler 		on_trap_data_t otd;
4258e774b42bSBill Holler 		uint64_t reg;
4259e774b42bSBill Holler 
4260e774b42bSBill Holler 		if (!on_trap(&otd, OT_DATA_ACCESS)) {
4261e774b42bSBill Holler 			reg = rdmsr(MSR_AMD_INT_PENDING_CMP_HALT);
4262e774b42bSBill Holler 			/* Disable C1E state if it is enabled by BIOS */
4263e774b42bSBill Holler 			if ((reg >> AMD_ACTONCMPHALT_SHIFT) &
4264e774b42bSBill Holler 			    AMD_ACTONCMPHALT_MASK) {
4265e774b42bSBill Holler 				reg &= ~(AMD_ACTONCMPHALT_MASK <<
4266e774b42bSBill Holler 				    AMD_ACTONCMPHALT_SHIFT);
4267e774b42bSBill Holler 				wrmsr(MSR_AMD_INT_PENDING_CMP_HALT, reg);
4268e774b42bSBill Holler 			}
4269e774b42bSBill Holler 		}
4270e774b42bSBill Holler 		no_trap();
4271e774b42bSBill Holler 	}
4272e774b42bSBill Holler #endif	/* !__xpv */
4273e774b42bSBill Holler }
4274e774b42bSBill Holler 
4275cef70d2cSBill Holler /*
4276cef70d2cSBill Holler  * Starting with the Westmere processor the local
4277cef70d2cSBill Holler  * APIC timer will continue running in all C-states,
4278cef70d2cSBill Holler  * including the deepest C-states.
4279cef70d2cSBill Holler  */
4280cef70d2cSBill Holler int
4281cef70d2cSBill Holler cpuid_arat_supported(void)
4282cef70d2cSBill Holler {
4283cef70d2cSBill Holler 	struct cpuid_info *cpi;
4284cef70d2cSBill Holler 	struct cpuid_regs regs;
4285cef70d2cSBill Holler 
4286cef70d2cSBill Holler 	ASSERT(cpuid_checkpass(CPU, 1));
42877417cfdeSKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
4288cef70d2cSBill Holler 
4289cef70d2cSBill Holler 	cpi = CPU->cpu_m.mcpu_cpi;
4290cef70d2cSBill Holler 
4291cef70d2cSBill Holler 	switch (cpi->cpi_vendor) {
4292cef70d2cSBill Holler 	case X86_VENDOR_Intel:
4293cef70d2cSBill Holler 		/*
4294cef70d2cSBill Holler 		 * Always-running Local APIC Timer is
4295cef70d2cSBill Holler 		 * indicated by CPUID.6.EAX[2].
4296cef70d2cSBill Holler 		 */
4297cef70d2cSBill Holler 		if (cpi->cpi_maxeax >= 6) {
4298cef70d2cSBill Holler 			regs.cp_eax = 6;
4299cef70d2cSBill Holler 			(void) cpuid_insn(NULL, &regs);
4300cef70d2cSBill Holler 			return (regs.cp_eax & CPUID_CSTATE_ARAT);
4301cef70d2cSBill Holler 		} else {
4302cef70d2cSBill Holler 			return (0);
4303cef70d2cSBill Holler 		}
4304cef70d2cSBill Holler 	default:
4305cef70d2cSBill Holler 		return (0);
4306cef70d2cSBill Holler 	}
4307cef70d2cSBill Holler }
4308cef70d2cSBill Holler 
4309f21ed392Saubrey.li@intel.com /*
4310f21ed392Saubrey.li@intel.com  * Check support for Intel ENERGY_PERF_BIAS feature
4311f21ed392Saubrey.li@intel.com  */
4312f21ed392Saubrey.li@intel.com int
4313f21ed392Saubrey.li@intel.com cpuid_iepb_supported(struct cpu *cp)
4314f21ed392Saubrey.li@intel.com {
4315f21ed392Saubrey.li@intel.com 	struct cpuid_info *cpi = cp->cpu_m.mcpu_cpi;
4316f21ed392Saubrey.li@intel.com 	struct cpuid_regs regs;
4317f21ed392Saubrey.li@intel.com 
4318f21ed392Saubrey.li@intel.com 	ASSERT(cpuid_checkpass(cp, 1));
4319f21ed392Saubrey.li@intel.com 
43207417cfdeSKuriakose Kuruvilla 	if (!(is_x86_feature(x86_featureset, X86FSET_CPUID)) ||
43217417cfdeSKuriakose Kuruvilla 	    !(is_x86_feature(x86_featureset, X86FSET_MSR))) {
4322f21ed392Saubrey.li@intel.com 		return (0);
4323f21ed392Saubrey.li@intel.com 	}
4324f21ed392Saubrey.li@intel.com 
4325f21ed392Saubrey.li@intel.com 	/*
4326f21ed392Saubrey.li@intel.com 	 * Intel ENERGY_PERF_BIAS MSR is indicated by
4327f21ed392Saubrey.li@intel.com 	 * capability bit CPUID.6.ECX.3
4328f21ed392Saubrey.li@intel.com 	 */
4329f21ed392Saubrey.li@intel.com 	if ((cpi->cpi_vendor != X86_VENDOR_Intel) || (cpi->cpi_maxeax < 6))
4330f21ed392Saubrey.li@intel.com 		return (0);
4331f21ed392Saubrey.li@intel.com 
4332f21ed392Saubrey.li@intel.com 	regs.cp_eax = 0x6;
4333f21ed392Saubrey.li@intel.com 	(void) cpuid_insn(NULL, &regs);
4334f21ed392Saubrey.li@intel.com 	return (regs.cp_ecx & CPUID_EPB_SUPPORT);
4335f21ed392Saubrey.li@intel.com }
4336f21ed392Saubrey.li@intel.com 
433722cc0e45SBill Holler #if defined(__amd64) && !defined(__xpv)
433822cc0e45SBill Holler /*
433922cc0e45SBill Holler  * Patch in versions of bcopy for high performance Intel Nhm processors
434022cc0e45SBill Holler  * and later...
434122cc0e45SBill Holler  */
434222cc0e45SBill Holler void
434322cc0e45SBill Holler patch_memops(uint_t vendor)
434422cc0e45SBill Holler {
434522cc0e45SBill Holler 	size_t cnt, i;
434622cc0e45SBill Holler 	caddr_t to, from;
434722cc0e45SBill Holler 
43487417cfdeSKuriakose Kuruvilla 	if ((vendor == X86_VENDOR_Intel) &&
43497417cfdeSKuriakose Kuruvilla 	    is_x86_feature(x86_featureset, X86FSET_SSE4_2)) {
435022cc0e45SBill Holler 		cnt = &bcopy_patch_end - &bcopy_patch_start;
435122cc0e45SBill Holler 		to = &bcopy_ck_size;
435222cc0e45SBill Holler 		from = &bcopy_patch_start;
435322cc0e45SBill Holler 		for (i = 0; i < cnt; i++) {
435422cc0e45SBill Holler 			*to++ = *from++;
435522cc0e45SBill Holler 		}
435622cc0e45SBill Holler 	}
435722cc0e45SBill Holler }
435822cc0e45SBill Holler #endif  /* __amd64 && !__xpv */
43592d2efdc6SVuong Nguyen 
43602d2efdc6SVuong Nguyen /*
43612d2efdc6SVuong Nguyen  * This function finds the number of bits to represent the number of cores per
43622d2efdc6SVuong Nguyen  * chip and the number of strands per core for the Intel platforms.
43632d2efdc6SVuong Nguyen  * It re-uses the x2APIC cpuid code of the cpuid_pass2().
43642d2efdc6SVuong Nguyen  */
43652d2efdc6SVuong Nguyen void
43662d2efdc6SVuong Nguyen cpuid_get_ext_topo(uint_t vendor, uint_t *core_nbits, uint_t *strand_nbits)
43672d2efdc6SVuong Nguyen {
43682d2efdc6SVuong Nguyen 	struct cpuid_regs regs;
43692d2efdc6SVuong Nguyen 	struct cpuid_regs *cp = &regs;
43702d2efdc6SVuong Nguyen 
43712d2efdc6SVuong Nguyen 	if (vendor != X86_VENDOR_Intel) {
43722d2efdc6SVuong Nguyen 		return;
43732d2efdc6SVuong Nguyen 	}
43742d2efdc6SVuong Nguyen 
43752d2efdc6SVuong Nguyen 	/* if the cpuid level is 0xB, extended topo is available. */
43762d2efdc6SVuong Nguyen 	cp->cp_eax = 0;
43772d2efdc6SVuong Nguyen 	if (__cpuid_insn(cp) >= 0xB) {
43782d2efdc6SVuong Nguyen 
43792d2efdc6SVuong Nguyen 		cp->cp_eax = 0xB;
43802d2efdc6SVuong Nguyen 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
43812d2efdc6SVuong Nguyen 		(void) __cpuid_insn(cp);
43822d2efdc6SVuong Nguyen 
43832d2efdc6SVuong Nguyen 		/*
43842d2efdc6SVuong Nguyen 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
43852d2efdc6SVuong Nguyen 		 * indicates that the extended topology enumeration leaf is
43862d2efdc6SVuong Nguyen 		 * available.
43872d2efdc6SVuong Nguyen 		 */
43882d2efdc6SVuong Nguyen 		if (cp->cp_ebx) {
43892d2efdc6SVuong Nguyen 			uint_t coreid_shift = 0;
43902d2efdc6SVuong Nguyen 			uint_t chipid_shift = 0;
43912d2efdc6SVuong Nguyen 			uint_t i;
43922d2efdc6SVuong Nguyen 			uint_t level;
43932d2efdc6SVuong Nguyen 
43942d2efdc6SVuong Nguyen 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
43952d2efdc6SVuong Nguyen 				cp->cp_eax = 0xB;
43962d2efdc6SVuong Nguyen 				cp->cp_ecx = i;
43972d2efdc6SVuong Nguyen 
43982d2efdc6SVuong Nguyen 				(void) __cpuid_insn(cp);
43992d2efdc6SVuong Nguyen 				level = CPI_CPU_LEVEL_TYPE(cp);
44002d2efdc6SVuong Nguyen 
44012d2efdc6SVuong Nguyen 				if (level == 1) {
44022d2efdc6SVuong Nguyen 					/*
44032d2efdc6SVuong Nguyen 					 * Thread level processor topology
44042d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
44052d2efdc6SVuong Nguyen 					 * to get the coreid.
44062d2efdc6SVuong Nguyen 					 */
44072d2efdc6SVuong Nguyen 					coreid_shift = BITX(cp->cp_eax, 4, 0);
44082d2efdc6SVuong Nguyen 				} else if (level == 2) {
44092d2efdc6SVuong Nguyen 					/*
44102d2efdc6SVuong Nguyen 					 * Core level processor topology
44112d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
44122d2efdc6SVuong Nguyen 					 * to get the chipid.
44132d2efdc6SVuong Nguyen 					 */
44142d2efdc6SVuong Nguyen 					chipid_shift = BITX(cp->cp_eax, 4, 0);
44152d2efdc6SVuong Nguyen 				}
44162d2efdc6SVuong Nguyen 			}
44172d2efdc6SVuong Nguyen 
44182d2efdc6SVuong Nguyen 			if (coreid_shift > 0 && chipid_shift > coreid_shift) {
44192d2efdc6SVuong Nguyen 				*strand_nbits = coreid_shift;
44202d2efdc6SVuong Nguyen 				*core_nbits = chipid_shift - coreid_shift;
44212d2efdc6SVuong Nguyen 			}
44222d2efdc6SVuong Nguyen 		}
44232d2efdc6SVuong Nguyen 	}
44242d2efdc6SVuong Nguyen }
4425