xref: /titanic_53/usr/src/uts/i86pc/os/cpuid.c (revision 7660e73f5b1e781050d87237f1123324e01f467b)
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.
23cfe84b82SMatt Amdur  * Copyright (c) 2011 by Delphix. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
25cef70d2cSBill Holler /*
2641afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Copyright (c) 2010, Intel Corporation.
27cef70d2cSBill Holler  * All rights reserved.
28cef70d2cSBill Holler  */
298031591dSSrihari Venkatesan /*
308031591dSSrihari Venkatesan  * Portions Copyright 2009 Advanced Micro Devices, Inc.
318031591dSSrihari Venkatesan  */
32faa20166SBryan Cantrill /*
33f3390f39SRobert Mustacchi  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
34faa20166SBryan Cantrill  */
357c478bd9Sstevel@tonic-gate /*
367c478bd9Sstevel@tonic-gate  * Various routines to handle identification
377c478bd9Sstevel@tonic-gate  * and classification of x86 processors.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
417c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
427c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/systm.h>
457c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
487c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
497c478bd9Sstevel@tonic-gate #include <sys/processor.h>
505b8a6efeSbholler #include <sys/sysmacros.h>
51fb2f18f8Sesaxe #include <sys/pg.h>
527c478bd9Sstevel@tonic-gate #include <sys/fp.h>
537c478bd9Sstevel@tonic-gate #include <sys/controlregs.h>
547c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
55dfea898aSKuriakose Kuruvilla #include <sys/auxv_386.h>
567c478bd9Sstevel@tonic-gate #include <sys/memnode.h>
578031591dSSrihari Venkatesan #include <sys/pci_cfgspace.h>
587c478bd9Sstevel@tonic-gate 
59e4b86885SCheng Sean Ye #ifdef __xpv
60e4b86885SCheng Sean Ye #include <sys/hypervisor.h>
61e774b42bSBill Holler #else
62e774b42bSBill Holler #include <sys/ontrap.h>
63e4b86885SCheng Sean Ye #endif
64e4b86885SCheng Sean Ye 
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate  * Pass 0 of cpuid feature analysis happens in locore. It contains special code
677c478bd9Sstevel@tonic-gate  * to recognize Cyrix processors that are not cpuid-compliant, and to deal with
687c478bd9Sstevel@tonic-gate  * them accordingly. For most modern processors, feature detection occurs here
697c478bd9Sstevel@tonic-gate  * in pass 1.
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  * Pass 1 of cpuid feature analysis happens just at the beginning of mlsetup()
727c478bd9Sstevel@tonic-gate  * for the boot CPU and does the basic analysis that the early kernel needs.
737417cfdeSKuriakose Kuruvilla  * x86_featureset is set based on the return value of cpuid_pass1() of the boot
747c478bd9Sstevel@tonic-gate  * CPU.
757c478bd9Sstevel@tonic-gate  *
767c478bd9Sstevel@tonic-gate  * Pass 1 includes:
777c478bd9Sstevel@tonic-gate  *
787c478bd9Sstevel@tonic-gate  *	o Determining vendor/model/family/stepping and setting x86_type and
797c478bd9Sstevel@tonic-gate  *	  x86_vendor accordingly.
807c478bd9Sstevel@tonic-gate  *	o Processing the feature flags returned by the cpuid instruction while
817c478bd9Sstevel@tonic-gate  *	  applying any workarounds or tricks for the specific processor.
827c478bd9Sstevel@tonic-gate  *	o Mapping the feature flags into Solaris feature bits (X86_*).
837c478bd9Sstevel@tonic-gate  *	o Processing extended feature flags if supported by the processor,
847c478bd9Sstevel@tonic-gate  *	  again while applying specific processor knowledge.
857c478bd9Sstevel@tonic-gate  *	o Determining the CMT characteristics of the system.
867c478bd9Sstevel@tonic-gate  *
877c478bd9Sstevel@tonic-gate  * Pass 1 is done on non-boot CPUs during their initialization and the results
887c478bd9Sstevel@tonic-gate  * are used only as a meager attempt at ensuring that all processors within the
897c478bd9Sstevel@tonic-gate  * system support the same features.
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * Pass 2 of cpuid feature analysis happens just at the beginning
927c478bd9Sstevel@tonic-gate  * of startup().  It just copies in and corrects the remainder
937c478bd9Sstevel@tonic-gate  * of the cpuid data we depend on: standard cpuid functions that we didn't
947c478bd9Sstevel@tonic-gate  * need for pass1 feature analysis, and extended cpuid functions beyond the
957c478bd9Sstevel@tonic-gate  * simple feature processing done in pass1.
967c478bd9Sstevel@tonic-gate  *
977c478bd9Sstevel@tonic-gate  * Pass 3 of cpuid analysis is invoked after basic kernel services; in
987c478bd9Sstevel@tonic-gate  * particular kernel memory allocation has been made available. It creates a
997c478bd9Sstevel@tonic-gate  * readable brand string based on the data collected in the first two passes.
1007c478bd9Sstevel@tonic-gate  *
1017c478bd9Sstevel@tonic-gate  * Pass 4 of cpuid analysis is invoked after post_startup() when all
1027c478bd9Sstevel@tonic-gate  * the support infrastructure for various hardware features has been
1037c478bd9Sstevel@tonic-gate  * initialized. It determines which processor features will be reported
1047c478bd9Sstevel@tonic-gate  * to userland via the aux vector.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * All passes are executed on all CPUs, but only the boot CPU determines what
1077c478bd9Sstevel@tonic-gate  * features the kernel will use.
1087c478bd9Sstevel@tonic-gate  *
1097c478bd9Sstevel@tonic-gate  * Much of the worst junk in this file is for the support of processors
1107c478bd9Sstevel@tonic-gate  * that didn't really implement the cpuid instruction properly.
1117c478bd9Sstevel@tonic-gate  *
1127c478bd9Sstevel@tonic-gate  * NOTE: The accessor functions (cpuid_get*) are aware of, and ASSERT upon,
1137c478bd9Sstevel@tonic-gate  * the pass numbers.  Accordingly, changes to the pass code may require changes
1147c478bd9Sstevel@tonic-gate  * to the accessor code.
1157c478bd9Sstevel@tonic-gate  */
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate uint_t x86_vendor = X86_VENDOR_IntelClone;
1187c478bd9Sstevel@tonic-gate uint_t x86_type = X86_TYPE_OTHER;
11986c1f4dcSVikram Hegde uint_t x86_clflush_size = 0;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4046376;
1227c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4064495;
1237c478bd9Sstevel@tonic-gate 
124dfea898aSKuriakose Kuruvilla uchar_t x86_featureset[BT_SIZEOFMAP(NUM_X86_FEATURES)];
1257417cfdeSKuriakose Kuruvilla 
126dfea898aSKuriakose Kuruvilla static char *x86_feature_names[NUM_X86_FEATURES] = {
1277417cfdeSKuriakose Kuruvilla 	"lgpg",
1287417cfdeSKuriakose Kuruvilla 	"tsc",
1297417cfdeSKuriakose Kuruvilla 	"msr",
1307417cfdeSKuriakose Kuruvilla 	"mtrr",
1317417cfdeSKuriakose Kuruvilla 	"pge",
1327417cfdeSKuriakose Kuruvilla 	"de",
1337417cfdeSKuriakose Kuruvilla 	"cmov",
1347417cfdeSKuriakose Kuruvilla 	"mmx",
1357417cfdeSKuriakose Kuruvilla 	"mca",
1367417cfdeSKuriakose Kuruvilla 	"pae",
1377417cfdeSKuriakose Kuruvilla 	"cv8",
1387417cfdeSKuriakose Kuruvilla 	"pat",
1397417cfdeSKuriakose Kuruvilla 	"sep",
1407417cfdeSKuriakose Kuruvilla 	"sse",
1417417cfdeSKuriakose Kuruvilla 	"sse2",
1427417cfdeSKuriakose Kuruvilla 	"htt",
1437417cfdeSKuriakose Kuruvilla 	"asysc",
1447417cfdeSKuriakose Kuruvilla 	"nx",
1457417cfdeSKuriakose Kuruvilla 	"sse3",
1467417cfdeSKuriakose Kuruvilla 	"cx16",
1477417cfdeSKuriakose Kuruvilla 	"cmp",
1487417cfdeSKuriakose Kuruvilla 	"tscp",
1497417cfdeSKuriakose Kuruvilla 	"mwait",
1507417cfdeSKuriakose Kuruvilla 	"sse4a",
1517417cfdeSKuriakose Kuruvilla 	"cpuid",
1527417cfdeSKuriakose Kuruvilla 	"ssse3",
1537417cfdeSKuriakose Kuruvilla 	"sse4_1",
1547417cfdeSKuriakose Kuruvilla 	"sse4_2",
1557417cfdeSKuriakose Kuruvilla 	"1gpg",
1567417cfdeSKuriakose Kuruvilla 	"clfsh",
1577417cfdeSKuriakose Kuruvilla 	"64",
1587417cfdeSKuriakose Kuruvilla 	"aes",
1597af88ac7SKuriakose Kuruvilla 	"pclmulqdq",
1607af88ac7SKuriakose Kuruvilla 	"xsave",
161faa20166SBryan Cantrill 	"avx",
162faa20166SBryan Cantrill 	"vmx",
163*7660e73fSHans Rosenfeld 	"svm",
164*7660e73fSHans Rosenfeld 	"topoext"
165faa20166SBryan Cantrill };
1667417cfdeSKuriakose Kuruvilla 
1677417cfdeSKuriakose Kuruvilla boolean_t
1687417cfdeSKuriakose Kuruvilla is_x86_feature(void *featureset, uint_t feature)
1697417cfdeSKuriakose Kuruvilla {
1707417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1717417cfdeSKuriakose Kuruvilla 	return (BT_TEST((ulong_t *)featureset, feature));
1727417cfdeSKuriakose Kuruvilla }
1737417cfdeSKuriakose Kuruvilla 
1747417cfdeSKuriakose Kuruvilla void
1757417cfdeSKuriakose Kuruvilla add_x86_feature(void *featureset, uint_t feature)
1767417cfdeSKuriakose Kuruvilla {
1777417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1787417cfdeSKuriakose Kuruvilla 	BT_SET((ulong_t *)featureset, feature);
1797417cfdeSKuriakose Kuruvilla }
1807417cfdeSKuriakose Kuruvilla 
1817417cfdeSKuriakose Kuruvilla void
1827417cfdeSKuriakose Kuruvilla remove_x86_feature(void *featureset, uint_t feature)
1837417cfdeSKuriakose Kuruvilla {
1847417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1857417cfdeSKuriakose Kuruvilla 	BT_CLEAR((ulong_t *)featureset, feature);
1867417cfdeSKuriakose Kuruvilla }
1877417cfdeSKuriakose Kuruvilla 
1887417cfdeSKuriakose Kuruvilla boolean_t
1897417cfdeSKuriakose Kuruvilla compare_x86_featureset(void *setA, void *setB)
1907417cfdeSKuriakose Kuruvilla {
1917417cfdeSKuriakose Kuruvilla 	/*
1927417cfdeSKuriakose Kuruvilla 	 * We assume that the unused bits of the bitmap are always zero.
1937417cfdeSKuriakose Kuruvilla 	 */
1947417cfdeSKuriakose Kuruvilla 	if (memcmp(setA, setB, BT_SIZEOFMAP(NUM_X86_FEATURES)) == 0) {
1957417cfdeSKuriakose Kuruvilla 		return (B_TRUE);
1967417cfdeSKuriakose Kuruvilla 	} else {
1977417cfdeSKuriakose Kuruvilla 		return (B_FALSE);
1987417cfdeSKuriakose Kuruvilla 	}
1997417cfdeSKuriakose Kuruvilla }
2007417cfdeSKuriakose Kuruvilla 
2017417cfdeSKuriakose Kuruvilla void
2027417cfdeSKuriakose Kuruvilla print_x86_featureset(void *featureset)
2037417cfdeSKuriakose Kuruvilla {
2047417cfdeSKuriakose Kuruvilla 	uint_t i;
2057417cfdeSKuriakose Kuruvilla 
2067417cfdeSKuriakose Kuruvilla 	for (i = 0; i < NUM_X86_FEATURES; i++) {
2077417cfdeSKuriakose Kuruvilla 		if (is_x86_feature(featureset, i)) {
2087417cfdeSKuriakose Kuruvilla 			cmn_err(CE_CONT, "?x86_feature: %s\n",
2097417cfdeSKuriakose Kuruvilla 			    x86_feature_names[i]);
2107417cfdeSKuriakose Kuruvilla 		}
2117417cfdeSKuriakose Kuruvilla 	}
2127417cfdeSKuriakose Kuruvilla }
2137417cfdeSKuriakose Kuruvilla 
2147c478bd9Sstevel@tonic-gate uint_t enable486;
2157af88ac7SKuriakose Kuruvilla 
2167af88ac7SKuriakose Kuruvilla static size_t xsave_state_size = 0;
2177af88ac7SKuriakose Kuruvilla uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE);
2187af88ac7SKuriakose Kuruvilla boolean_t xsave_force_disable = B_FALSE;
2197af88ac7SKuriakose Kuruvilla 
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 /*
2507af88ac7SKuriakose Kuruvilla  * xsave/xrestor info.
2517af88ac7SKuriakose Kuruvilla  *
2527af88ac7SKuriakose Kuruvilla  * This structure contains HW feature bits and size of the xsave save area.
2537af88ac7SKuriakose Kuruvilla  * Note: the kernel will use the maximum size required for all hardware
2547af88ac7SKuriakose Kuruvilla  * features. It is not optimize for potential memory savings if features at
2557af88ac7SKuriakose Kuruvilla  * the end of the save area are not enabled.
2567af88ac7SKuriakose Kuruvilla  */
2577af88ac7SKuriakose Kuruvilla struct xsave_info {
2587af88ac7SKuriakose Kuruvilla 	uint32_t	xsav_hw_features_low;   /* Supported HW features */
2597af88ac7SKuriakose Kuruvilla 	uint32_t	xsav_hw_features_high;  /* Supported HW features */
2607af88ac7SKuriakose Kuruvilla 	size_t		xsav_max_size;  /* max size save area for HW features */
2617af88ac7SKuriakose Kuruvilla 	size_t		ymm_size;	/* AVX: size of ymm save area */
2627af88ac7SKuriakose Kuruvilla 	size_t		ymm_offset;	/* AVX: offset for ymm save area */
2637af88ac7SKuriakose Kuruvilla };
2647af88ac7SKuriakose Kuruvilla 
2657af88ac7SKuriakose Kuruvilla 
2667af88ac7SKuriakose Kuruvilla /*
2677c478bd9Sstevel@tonic-gate  * These constants determine how many of the elements of the
2687c478bd9Sstevel@tonic-gate  * cpuid we cache in the cpuid_info data structure; the
2697c478bd9Sstevel@tonic-gate  * remaining elements are accessible via the cpuid instruction.
2707c478bd9Sstevel@tonic-gate  */
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate #define	NMAX_CPI_STD	6		/* eax = 0 .. 5 */
273*7660e73fSHans Rosenfeld #define	NMAX_CPI_EXTD	0x1f		/* eax = 0x80000000 .. 0x8000001e */
2748031591dSSrihari Venkatesan 
2758031591dSSrihari Venkatesan /*
2768031591dSSrihari Venkatesan  * Some terminology needs to be explained:
2778031591dSSrihari Venkatesan  *  - Socket: Something that can be plugged into a motherboard.
2788031591dSSrihari Venkatesan  *  - Package: Same as socket
2798031591dSSrihari Venkatesan  *  - Chip: Same as socket. Note that AMD's documentation uses term "chip"
2808031591dSSrihari Venkatesan  *    differently: there, chip is the same as processor node (below)
2818031591dSSrihari Venkatesan  *  - Processor node: Some AMD processors have more than one
2828031591dSSrihari Venkatesan  *    "subprocessor" embedded in a package. These subprocessors (nodes)
2838031591dSSrihari Venkatesan  *    are fully-functional processors themselves with cores, caches,
2848031591dSSrihari Venkatesan  *    memory controllers, PCI configuration spaces. They are connected
2858031591dSSrihari Venkatesan  *    inside the package with Hypertransport links. On single-node
2868031591dSSrihari Venkatesan  *    processors, processor node is equivalent to chip/socket/package.
287*7660e73fSHans Rosenfeld  *  - Compute Unit: Some AMD processors pair cores in "compute units" that
288*7660e73fSHans Rosenfeld  *    share the FPU and the I$ and L2 caches.
2898031591dSSrihari Venkatesan  */
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate struct cpuid_info {
2927c478bd9Sstevel@tonic-gate 	uint_t cpi_pass;		/* last pass completed */
2937c478bd9Sstevel@tonic-gate 	/*
2947c478bd9Sstevel@tonic-gate 	 * standard function information
2957c478bd9Sstevel@tonic-gate 	 */
2967c478bd9Sstevel@tonic-gate 	uint_t cpi_maxeax;		/* fn 0: %eax */
2977c478bd9Sstevel@tonic-gate 	char cpi_vendorstr[13];		/* fn 0: %ebx:%ecx:%edx */
2987c478bd9Sstevel@tonic-gate 	uint_t cpi_vendor;		/* enum of cpi_vendorstr */
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	uint_t cpi_family;		/* fn 1: extended family */
3017c478bd9Sstevel@tonic-gate 	uint_t cpi_model;		/* fn 1: extended model */
3027c478bd9Sstevel@tonic-gate 	uint_t cpi_step;		/* fn 1: stepping */
3038031591dSSrihari Venkatesan 	chipid_t cpi_chipid;		/* fn 1: %ebx:  Intel: chip # */
3048031591dSSrihari Venkatesan 					/*		AMD: package/socket # */
3057c478bd9Sstevel@tonic-gate 	uint_t cpi_brandid;		/* fn 1: %ebx: brand ID */
3067c478bd9Sstevel@tonic-gate 	int cpi_clogid;			/* fn 1: %ebx: thread # */
3078949bcd6Sandrei 	uint_t cpi_ncpu_per_chip;	/* fn 1: %ebx: logical cpu count */
3087c478bd9Sstevel@tonic-gate 	uint8_t cpi_cacheinfo[16];	/* fn 2: intel-style cache desc */
3097c478bd9Sstevel@tonic-gate 	uint_t cpi_ncache;		/* fn 2: number of elements */
310d129bde2Sesaxe 	uint_t cpi_ncpu_shr_last_cache;	/* fn 4: %eax: ncpus sharing cache */
311d129bde2Sesaxe 	id_t cpi_last_lvl_cacheid;	/* fn 4: %eax: derived cache id */
312d129bde2Sesaxe 	uint_t cpi_std_4_size;		/* fn 4: number of fn 4 elements */
313d129bde2Sesaxe 	struct cpuid_regs **cpi_std_4;	/* fn 4: %ecx == 0 .. fn4_size */
3148949bcd6Sandrei 	struct cpuid_regs cpi_std[NMAX_CPI_STD];	/* 0 .. 5 */
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * extended function information
3177c478bd9Sstevel@tonic-gate 	 */
3187c478bd9Sstevel@tonic-gate 	uint_t cpi_xmaxeax;		/* fn 0x80000000: %eax */
3197c478bd9Sstevel@tonic-gate 	char cpi_brandstr[49];		/* fn 0x8000000[234] */
3207c478bd9Sstevel@tonic-gate 	uint8_t cpi_pabits;		/* fn 0x80000006: %eax */
3217c478bd9Sstevel@tonic-gate 	uint8_t	cpi_vabits;		/* fn 0x80000006: %eax */
3228031591dSSrihari Venkatesan 	struct	cpuid_regs cpi_extd[NMAX_CPI_EXTD];	/* 0x800000XX */
3238031591dSSrihari Venkatesan 
32410569901Sgavinm 	id_t cpi_coreid;		/* same coreid => strands share core */
32510569901Sgavinm 	int cpi_pkgcoreid;		/* core number within single package */
3268949bcd6Sandrei 	uint_t cpi_ncore_per_chip;	/* AMD: fn 0x80000008: %ecx[7-0] */
3278949bcd6Sandrei 					/* Intel: fn 4: %eax[31-26] */
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * supported feature information
3307c478bd9Sstevel@tonic-gate 	 */
331ae115bc7Smrj 	uint32_t cpi_support[5];
3327c478bd9Sstevel@tonic-gate #define	STD_EDX_FEATURES	0
3337c478bd9Sstevel@tonic-gate #define	AMD_EDX_FEATURES	1
3347c478bd9Sstevel@tonic-gate #define	TM_EDX_FEATURES		2
3357c478bd9Sstevel@tonic-gate #define	STD_ECX_FEATURES	3
336ae115bc7Smrj #define	AMD_ECX_FEATURES	4
3378a40a695Sgavinm 	/*
3388a40a695Sgavinm 	 * Synthesized information, where known.
3398a40a695Sgavinm 	 */
3408a40a695Sgavinm 	uint32_t cpi_chiprev;		/* See X86_CHIPREV_* in x86_archext.h */
3418a40a695Sgavinm 	const char *cpi_chiprevstr;	/* May be NULL if chiprev unknown */
3428a40a695Sgavinm 	uint32_t cpi_socket;		/* Chip package/socket type */
343f98fbcecSbholler 
344f98fbcecSbholler 	struct mwait_info cpi_mwait;	/* fn 5: monitor/mwait info */
345b6917abeSmishra 	uint32_t cpi_apicid;
3468031591dSSrihari Venkatesan 	uint_t cpi_procnodeid;		/* AMD: nodeID on HT, Intel: chipid */
3478031591dSSrihari Venkatesan 	uint_t cpi_procnodes_per_pkg;	/* AMD: # of nodes in the package */
3488031591dSSrihari Venkatesan 					/* Intel: 1 */
349*7660e73fSHans Rosenfeld 	uint_t cpi_compunitid;		/* AMD: ComputeUnit ID, Intel: coreid */
350*7660e73fSHans Rosenfeld 	uint_t cpi_cores_per_compunit;	/* AMD: # of cores in the ComputeUnit */
3517af88ac7SKuriakose Kuruvilla 
3527af88ac7SKuriakose Kuruvilla 	struct xsave_info cpi_xsave;	/* fn D: xsave/xrestor info */
3537c478bd9Sstevel@tonic-gate };
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate static struct cpuid_info cpuid_info0;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate /*
3597c478bd9Sstevel@tonic-gate  * These bit fields are defined by the Intel Application Note AP-485
3607c478bd9Sstevel@tonic-gate  * "Intel Processor Identification and the CPUID Instruction"
3617c478bd9Sstevel@tonic-gate  */
3627c478bd9Sstevel@tonic-gate #define	CPI_FAMILY_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 27, 20)
3637c478bd9Sstevel@tonic-gate #define	CPI_MODEL_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 19, 16)
3647c478bd9Sstevel@tonic-gate #define	CPI_TYPE(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 13, 12)
3657c478bd9Sstevel@tonic-gate #define	CPI_FAMILY(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 11, 8)
3667c478bd9Sstevel@tonic-gate #define	CPI_STEP(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 3, 0)
3677c478bd9Sstevel@tonic-gate #define	CPI_MODEL(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 7, 4)
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_EDX(cpi)		((cpi)->cpi_std[1].cp_edx)
3707c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_ECX(cpi)		((cpi)->cpi_std[1].cp_ecx)
3717c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_EDX(cpi)	((cpi)->cpi_extd[1].cp_edx)
3727c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_ECX(cpi)	((cpi)->cpi_extd[1].cp_ecx)
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate #define	CPI_BRANDID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 7, 0)
3757c478bd9Sstevel@tonic-gate #define	CPI_CHUNKS(cpi)		BITX((cpi)->cpi_std[1].cp_ebx, 15, 7)
3767c478bd9Sstevel@tonic-gate #define	CPI_CPU_COUNT(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 23, 16)
3777c478bd9Sstevel@tonic-gate #define	CPI_APIC_ID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 31, 24)
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate #define	CPI_MAXEAX_MAX		0x100		/* sanity control */
3807c478bd9Sstevel@tonic-gate #define	CPI_XMAXEAX_MAX		0x80000100
381d129bde2Sesaxe #define	CPI_FN4_ECX_MAX		0x20		/* sanity: max fn 4 levels */
382b6917abeSmishra #define	CPI_FNB_ECX_MAX		0x20		/* sanity: max fn B levels */
383d129bde2Sesaxe 
384d129bde2Sesaxe /*
385d129bde2Sesaxe  * Function 4 (Deterministic Cache Parameters) macros
386d129bde2Sesaxe  * Defined by Intel Application Note AP-485
387d129bde2Sesaxe  */
388d129bde2Sesaxe #define	CPI_NUM_CORES(regs)		BITX((regs)->cp_eax, 31, 26)
389d129bde2Sesaxe #define	CPI_NTHR_SHR_CACHE(regs)	BITX((regs)->cp_eax, 25, 14)
390d129bde2Sesaxe #define	CPI_FULL_ASSOC_CACHE(regs)	BITX((regs)->cp_eax, 9, 9)
391d129bde2Sesaxe #define	CPI_SELF_INIT_CACHE(regs)	BITX((regs)->cp_eax, 8, 8)
392d129bde2Sesaxe #define	CPI_CACHE_LVL(regs)		BITX((regs)->cp_eax, 7, 5)
393d129bde2Sesaxe #define	CPI_CACHE_TYPE(regs)		BITX((regs)->cp_eax, 4, 0)
394b6917abeSmishra #define	CPI_CPU_LEVEL_TYPE(regs)	BITX((regs)->cp_ecx, 15, 8)
395d129bde2Sesaxe 
396d129bde2Sesaxe #define	CPI_CACHE_WAYS(regs)		BITX((regs)->cp_ebx, 31, 22)
397d129bde2Sesaxe #define	CPI_CACHE_PARTS(regs)		BITX((regs)->cp_ebx, 21, 12)
398d129bde2Sesaxe #define	CPI_CACHE_COH_LN_SZ(regs)	BITX((regs)->cp_ebx, 11, 0)
399d129bde2Sesaxe 
400d129bde2Sesaxe #define	CPI_CACHE_SETS(regs)		BITX((regs)->cp_ecx, 31, 0)
401d129bde2Sesaxe 
402d129bde2Sesaxe #define	CPI_PREFCH_STRIDE(regs)		BITX((regs)->cp_edx, 9, 0)
403d129bde2Sesaxe 
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate /*
4065ff02082Sdmick  * A couple of shorthand macros to identify "later" P6-family chips
4075ff02082Sdmick  * like the Pentium M and Core.  First, the "older" P6-based stuff
4085ff02082Sdmick  * (loosely defined as "pre-Pentium-4"):
4095ff02082Sdmick  * P6, PII, Mobile PII, PII Xeon, PIII, Mobile PIII, PIII Xeon
4105ff02082Sdmick  */
4115ff02082Sdmick 
4125ff02082Sdmick #define	IS_LEGACY_P6(cpi) (			\
4135ff02082Sdmick 	cpi->cpi_family == 6 && 		\
4145ff02082Sdmick 		(cpi->cpi_model == 1 ||		\
4155ff02082Sdmick 		cpi->cpi_model == 3 ||		\
4165ff02082Sdmick 		cpi->cpi_model == 5 ||		\
4175ff02082Sdmick 		cpi->cpi_model == 6 ||		\
4185ff02082Sdmick 		cpi->cpi_model == 7 ||		\
4195ff02082Sdmick 		cpi->cpi_model == 8 ||		\
4205ff02082Sdmick 		cpi->cpi_model == 0xA ||	\
4215ff02082Sdmick 		cpi->cpi_model == 0xB)		\
4225ff02082Sdmick )
4235ff02082Sdmick 
4245ff02082Sdmick /* A "new F6" is everything with family 6 that's not the above */
4255ff02082Sdmick #define	IS_NEW_F6(cpi) ((cpi->cpi_family == 6) && !IS_LEGACY_P6(cpi))
4265ff02082Sdmick 
427bf91205bSksadhukh /* Extended family/model support */
428bf91205bSksadhukh #define	IS_EXTENDED_MODEL_INTEL(cpi) (cpi->cpi_family == 0x6 || \
429bf91205bSksadhukh 	cpi->cpi_family >= 0xf)
430bf91205bSksadhukh 
4315ff02082Sdmick /*
432f98fbcecSbholler  * Info for monitor/mwait idle loop.
433f98fbcecSbholler  *
434f98fbcecSbholler  * See cpuid section of "Intel 64 and IA-32 Architectures Software Developer's
435f98fbcecSbholler  * Manual Volume 2A: Instruction Set Reference, A-M" #25366-022US, November
436f98fbcecSbholler  * 2006.
437f98fbcecSbholler  * See MONITOR/MWAIT section of "AMD64 Architecture Programmer's Manual
438f98fbcecSbholler  * Documentation Updates" #33633, Rev 2.05, December 2006.
439f98fbcecSbholler  */
440f98fbcecSbholler #define	MWAIT_SUPPORT		(0x00000001)	/* mwait supported */
441f98fbcecSbholler #define	MWAIT_EXTENSIONS	(0x00000002)	/* extenstion supported */
442f98fbcecSbholler #define	MWAIT_ECX_INT_ENABLE	(0x00000004)	/* ecx 1 extension supported */
443f98fbcecSbholler #define	MWAIT_SUPPORTED(cpi)	((cpi)->cpi_std[1].cp_ecx & CPUID_INTC_ECX_MON)
444f98fbcecSbholler #define	MWAIT_INT_ENABLE(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x2)
445f98fbcecSbholler #define	MWAIT_EXTENSION(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x1)
446f98fbcecSbholler #define	MWAIT_SIZE_MIN(cpi)	BITX((cpi)->cpi_std[5].cp_eax, 15, 0)
447f98fbcecSbholler #define	MWAIT_SIZE_MAX(cpi)	BITX((cpi)->cpi_std[5].cp_ebx, 15, 0)
448f98fbcecSbholler /*
449f98fbcecSbholler  * Number of sub-cstates for a given c-state.
450f98fbcecSbholler  */
451f98fbcecSbholler #define	MWAIT_NUM_SUBC_STATES(cpi, c_state)			\
452f98fbcecSbholler 	BITX((cpi)->cpi_std[5].cp_edx, c_state + 3, c_state)
453f98fbcecSbholler 
4548a40a695Sgavinm /*
4557af88ac7SKuriakose Kuruvilla  * XSAVE leaf 0xD enumeration
4567af88ac7SKuriakose Kuruvilla  */
4577af88ac7SKuriakose Kuruvilla #define	CPUID_LEAFD_2_YMM_OFFSET	576
4587af88ac7SKuriakose Kuruvilla #define	CPUID_LEAFD_2_YMM_SIZE		256
4597af88ac7SKuriakose Kuruvilla 
4607af88ac7SKuriakose Kuruvilla /*
461e4b86885SCheng Sean Ye  * Functions we consune from cpuid_subr.c;  don't publish these in a header
462e4b86885SCheng Sean Ye  * file to try and keep people using the expected cpuid_* interfaces.
4638a40a695Sgavinm  */
464e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t);
46589e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t);
466e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t);
467e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t);
468e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *);
4698a40a695Sgavinm 
4708a40a695Sgavinm /*
471ae115bc7Smrj  * Apply up various platform-dependent restrictions where the
472ae115bc7Smrj  * underlying platform restrictions mean the CPU can be marked
473ae115bc7Smrj  * as less capable than its cpuid instruction would imply.
474ae115bc7Smrj  */
475843e1988Sjohnlev #if defined(__xpv)
476843e1988Sjohnlev static void
477843e1988Sjohnlev platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp)
478843e1988Sjohnlev {
479843e1988Sjohnlev 	switch (eax) {
480e4b86885SCheng Sean Ye 	case 1: {
481e4b86885SCheng Sean Ye 		uint32_t mcamask = DOMAIN_IS_INITDOMAIN(xen_info) ?
482e4b86885SCheng Sean Ye 		    0 : CPUID_INTC_EDX_MCA;
483843e1988Sjohnlev 		cp->cp_edx &=
484e4b86885SCheng Sean Ye 		    ~(mcamask |
485e4b86885SCheng Sean Ye 		    CPUID_INTC_EDX_PSE |
486843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
487843e1988Sjohnlev 		    CPUID_INTC_EDX_SEP | CPUID_INTC_EDX_MTRR |
488843e1988Sjohnlev 		    CPUID_INTC_EDX_PGE | CPUID_INTC_EDX_PAT |
489843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
490843e1988Sjohnlev 		    CPUID_INTC_EDX_PSE36 | CPUID_INTC_EDX_HTT);
491843e1988Sjohnlev 		break;
492e4b86885SCheng Sean Ye 	}
493ae115bc7Smrj 
494843e1988Sjohnlev 	case 0x80000001:
495843e1988Sjohnlev 		cp->cp_edx &=
496843e1988Sjohnlev 		    ~(CPUID_AMD_EDX_PSE |
497843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
498843e1988Sjohnlev 		    CPUID_AMD_EDX_MTRR | CPUID_AMD_EDX_PGE |
499843e1988Sjohnlev 		    CPUID_AMD_EDX_PAT | CPUID_AMD_EDX_PSE36 |
500843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
501843e1988Sjohnlev 		    CPUID_AMD_EDX_TSCP);
502843e1988Sjohnlev 		cp->cp_ecx &= ~CPUID_AMD_ECX_CMP_LGCY;
503843e1988Sjohnlev 		break;
504843e1988Sjohnlev 	default:
505843e1988Sjohnlev 		break;
506843e1988Sjohnlev 	}
507843e1988Sjohnlev 
508843e1988Sjohnlev 	switch (vendor) {
509843e1988Sjohnlev 	case X86_VENDOR_Intel:
510843e1988Sjohnlev 		switch (eax) {
511843e1988Sjohnlev 		case 4:
512843e1988Sjohnlev 			/*
513843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
514843e1988Sjohnlev 			 */
515843e1988Sjohnlev 			cp->cp_eax &= 0x03fffffff;
516843e1988Sjohnlev 			break;
517843e1988Sjohnlev 		default:
518843e1988Sjohnlev 			break;
519843e1988Sjohnlev 		}
520843e1988Sjohnlev 		break;
521843e1988Sjohnlev 	case X86_VENDOR_AMD:
522843e1988Sjohnlev 		switch (eax) {
5232ef50f01SJoe Bonasera 
5242ef50f01SJoe Bonasera 		case 0x80000001:
5252ef50f01SJoe Bonasera 			cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D;
5262ef50f01SJoe Bonasera 			break;
5272ef50f01SJoe Bonasera 
528843e1988Sjohnlev 		case 0x80000008:
529843e1988Sjohnlev 			/*
530843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
531843e1988Sjohnlev 			 */
532843e1988Sjohnlev 			cp->cp_ecx &= 0xffffff00;
533843e1988Sjohnlev 			break;
534843e1988Sjohnlev 		default:
535843e1988Sjohnlev 			break;
536843e1988Sjohnlev 		}
537843e1988Sjohnlev 		break;
538843e1988Sjohnlev 	default:
539843e1988Sjohnlev 		break;
540843e1988Sjohnlev 	}
541843e1988Sjohnlev }
542843e1988Sjohnlev #else
543ae115bc7Smrj #define	platform_cpuid_mangle(vendor, eax, cp)	/* nothing */
544843e1988Sjohnlev #endif
545ae115bc7Smrj 
546ae115bc7Smrj /*
5477c478bd9Sstevel@tonic-gate  *  Some undocumented ways of patching the results of the cpuid
5487c478bd9Sstevel@tonic-gate  *  instruction to permit running Solaris 10 on future cpus that
5497c478bd9Sstevel@tonic-gate  *  we don't currently support.  Could be set to non-zero values
5507c478bd9Sstevel@tonic-gate  *  via settings in eeprom.
5517c478bd9Sstevel@tonic-gate  */
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_include;
5547c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_exclude;
5557c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_include;
5567c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_exclude;
5577c478bd9Sstevel@tonic-gate 
558a3114836SGerry Liu /*
559a3114836SGerry Liu  * Allocate space for mcpu_cpi in the machcpu structure for all non-boot CPUs.
560a3114836SGerry Liu  */
561ae115bc7Smrj void
562ae115bc7Smrj cpuid_alloc_space(cpu_t *cpu)
563ae115bc7Smrj {
564ae115bc7Smrj 	/*
565ae115bc7Smrj 	 * By convention, cpu0 is the boot cpu, which is set up
566ae115bc7Smrj 	 * before memory allocation is available.  All other cpus get
567ae115bc7Smrj 	 * their cpuid_info struct allocated here.
568ae115bc7Smrj 	 */
569ae115bc7Smrj 	ASSERT(cpu->cpu_id != 0);
570a3114836SGerry Liu 	ASSERT(cpu->cpu_m.mcpu_cpi == NULL);
571ae115bc7Smrj 	cpu->cpu_m.mcpu_cpi =
572ae115bc7Smrj 	    kmem_zalloc(sizeof (*cpu->cpu_m.mcpu_cpi), KM_SLEEP);
573ae115bc7Smrj }
574ae115bc7Smrj 
575ae115bc7Smrj void
576ae115bc7Smrj cpuid_free_space(cpu_t *cpu)
577ae115bc7Smrj {
578d129bde2Sesaxe 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
579d129bde2Sesaxe 	int i;
580d129bde2Sesaxe 
581a3114836SGerry Liu 	ASSERT(cpi != NULL);
582a3114836SGerry Liu 	ASSERT(cpi != &cpuid_info0);
583d129bde2Sesaxe 
584d129bde2Sesaxe 	/*
585d129bde2Sesaxe 	 * Free up any function 4 related dynamic storage
586d129bde2Sesaxe 	 */
587d129bde2Sesaxe 	for (i = 1; i < cpi->cpi_std_4_size; i++)
588d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4[i], sizeof (struct cpuid_regs));
589d129bde2Sesaxe 	if (cpi->cpi_std_4_size > 0)
590d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4,
591d129bde2Sesaxe 		    cpi->cpi_std_4_size * sizeof (struct cpuid_regs *));
592d129bde2Sesaxe 
593a3114836SGerry Liu 	kmem_free(cpi, sizeof (*cpi));
594a3114836SGerry Liu 	cpu->cpu_m.mcpu_cpi = NULL;
595ae115bc7Smrj }
596ae115bc7Smrj 
597551bc2a6Smrj #if !defined(__xpv)
598551bc2a6Smrj 
599cfe84b82SMatt Amdur /*
600cfe84b82SMatt Amdur  * Determine the type of the underlying platform. This is used to customize
601cfe84b82SMatt Amdur  * initialization of various subsystems (e.g. TSC). determine_platform() must
602cfe84b82SMatt Amdur  * only ever be called once to prevent two processors from seeing different
603cfe84b82SMatt Amdur  * values of platform_type, it must be called before cpuid_pass1(), the
604cfe84b82SMatt Amdur  * earliest consumer to execute.
605cfe84b82SMatt Amdur  */
606cfe84b82SMatt Amdur void
607cfe84b82SMatt Amdur determine_platform(void)
608551bc2a6Smrj {
609551bc2a6Smrj 	struct cpuid_regs cp;
610551bc2a6Smrj 	char *xen_str;
6116e5580c9SFrank Van Der Linden 	uint32_t xen_signature[4], base;
612551bc2a6Smrj 
613cfe84b82SMatt Amdur 	ASSERT(platform_type == -1);
614cfe84b82SMatt Amdur 
615349b53ddSStuart Maybee 	platform_type = HW_NATIVE;
616349b53ddSStuart Maybee 
617349b53ddSStuart Maybee 	if (!enable_platform_detection)
618349b53ddSStuart Maybee 		return;
619349b53ddSStuart Maybee 
620551bc2a6Smrj 	/*
621551bc2a6Smrj 	 * In a fully virtualized domain, Xen's pseudo-cpuid function
6226e5580c9SFrank Van Der Linden 	 * returns a string representing the Xen signature in %ebx, %ecx,
6236e5580c9SFrank Van Der Linden 	 * and %edx. %eax contains the maximum supported cpuid function.
6246e5580c9SFrank Van Der Linden 	 * We need at least a (base + 2) leaf value to do what we want
6256e5580c9SFrank Van Der Linden 	 * to do. Try different base values, since the hypervisor might
6266e5580c9SFrank Van Der Linden 	 * use a different one depending on whether hyper-v emulation
6276e5580c9SFrank Van Der Linden 	 * is switched on by default or not.
628551bc2a6Smrj 	 */
6296e5580c9SFrank Van Der Linden 	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
6306e5580c9SFrank Van Der Linden 		cp.cp_eax = base;
631551bc2a6Smrj 		(void) __cpuid_insn(&cp);
632551bc2a6Smrj 		xen_signature[0] = cp.cp_ebx;
633551bc2a6Smrj 		xen_signature[1] = cp.cp_ecx;
634551bc2a6Smrj 		xen_signature[2] = cp.cp_edx;
635551bc2a6Smrj 		xen_signature[3] = 0;
636551bc2a6Smrj 		xen_str = (char *)xen_signature;
6376e5580c9SFrank Van Der Linden 		if (strcmp("XenVMMXenVMM", xen_str) == 0 &&
6386e5580c9SFrank Van Der Linden 		    cp.cp_eax >= (base + 2)) {
639b9bfdccdSStuart Maybee 			platform_type = HW_XEN_HVM;
6406e5580c9SFrank Van Der Linden 			return;
641551bc2a6Smrj 		}
642b9bfdccdSStuart Maybee 	}
643b9bfdccdSStuart Maybee 
6446e5580c9SFrank Van Der Linden 	if (vmware_platform()) /* running under vmware hypervisor? */
6456e5580c9SFrank Van Der Linden 		platform_type = HW_VMWARE;
6466e5580c9SFrank Van Der Linden }
6476e5580c9SFrank Van Der Linden 
648b9bfdccdSStuart Maybee int
649b9bfdccdSStuart Maybee get_hwenv(void)
650b9bfdccdSStuart Maybee {
651cfe84b82SMatt Amdur 	ASSERT(platform_type != -1);
652b9bfdccdSStuart Maybee 	return (platform_type);
653b9bfdccdSStuart Maybee }
654b9bfdccdSStuart Maybee 
655b9bfdccdSStuart Maybee int
656b9bfdccdSStuart Maybee is_controldom(void)
657b9bfdccdSStuart Maybee {
658b9bfdccdSStuart Maybee 	return (0);
659b9bfdccdSStuart Maybee }
660b9bfdccdSStuart Maybee 
661b9bfdccdSStuart Maybee #else
662b9bfdccdSStuart Maybee 
663b9bfdccdSStuart Maybee int
664b9bfdccdSStuart Maybee get_hwenv(void)
665b9bfdccdSStuart Maybee {
666b9bfdccdSStuart Maybee 	return (HW_XEN_PV);
667b9bfdccdSStuart Maybee }
668b9bfdccdSStuart Maybee 
669b9bfdccdSStuart Maybee int
670b9bfdccdSStuart Maybee is_controldom(void)
671b9bfdccdSStuart Maybee {
672b9bfdccdSStuart Maybee 	return (DOMAIN_IS_INITDOMAIN(xen_info));
673b9bfdccdSStuart Maybee }
674b9bfdccdSStuart Maybee 
675551bc2a6Smrj #endif	/* __xpv */
676551bc2a6Smrj 
6778031591dSSrihari Venkatesan static void
6787417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu_t *cpu, void *feature)
6798031591dSSrihari Venkatesan {
6808031591dSSrihari Venkatesan 	uint_t i;
6818031591dSSrihari Venkatesan 	uint_t chipid_shift = 0;
6828031591dSSrihari Venkatesan 	uint_t coreid_shift = 0;
6838031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
6848031591dSSrihari Venkatesan 
6858031591dSSrihari Venkatesan 	for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1)
6868031591dSSrihari Venkatesan 		chipid_shift++;
6878031591dSSrihari Venkatesan 
6888031591dSSrihari Venkatesan 	cpi->cpi_chipid = cpi->cpi_apicid >> chipid_shift;
6898031591dSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_apicid & ((1 << chipid_shift) - 1);
6908031591dSSrihari Venkatesan 
6917417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(feature, X86FSET_CMP)) {
6928031591dSSrihari Venkatesan 		/*
6938031591dSSrihari Venkatesan 		 * Multi-core (and possibly multi-threaded)
6948031591dSSrihari Venkatesan 		 * processors.
6958031591dSSrihari Venkatesan 		 */
6968031591dSSrihari Venkatesan 		uint_t ncpu_per_core;
6978031591dSSrihari Venkatesan 		if (cpi->cpi_ncore_per_chip == 1)
6988031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip;
6998031591dSSrihari Venkatesan 		else if (cpi->cpi_ncore_per_chip > 1)
7008031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip /
7018031591dSSrihari Venkatesan 			    cpi->cpi_ncore_per_chip;
7028031591dSSrihari Venkatesan 		/*
7038031591dSSrihari Venkatesan 		 * 8bit APIC IDs on dual core Pentiums
7048031591dSSrihari Venkatesan 		 * look like this:
7058031591dSSrihari Venkatesan 		 *
7068031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
7078031591dSSrihari Venkatesan 		 * | Physical Package ID   |  MC  |  HT  |
7088031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
7098031591dSSrihari Venkatesan 		 * <------- chipid -------->
7108031591dSSrihari Venkatesan 		 * <------- coreid --------------->
7118031591dSSrihari Venkatesan 		 *			   <--- clogid -->
7128031591dSSrihari Venkatesan 		 *			   <------>
7138031591dSSrihari Venkatesan 		 *			   pkgcoreid
7148031591dSSrihari Venkatesan 		 *
7158031591dSSrihari Venkatesan 		 * Where the number of bits necessary to
7168031591dSSrihari Venkatesan 		 * represent MC and HT fields together equals
7178031591dSSrihari Venkatesan 		 * to the minimum number of bits necessary to
7188031591dSSrihari Venkatesan 		 * store the value of cpi->cpi_ncpu_per_chip.
7198031591dSSrihari Venkatesan 		 * Of those bits, the MC part uses the number
7208031591dSSrihari Venkatesan 		 * of bits necessary to store the value of
7218031591dSSrihari Venkatesan 		 * cpi->cpi_ncore_per_chip.
7228031591dSSrihari Venkatesan 		 */
7238031591dSSrihari Venkatesan 		for (i = 1; i < ncpu_per_core; i <<= 1)
7248031591dSSrihari Venkatesan 			coreid_shift++;
7258031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_apicid >> coreid_shift;
7268031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
7277417cfdeSKuriakose Kuruvilla 	} else if (is_x86_feature(feature, X86FSET_HTT)) {
7288031591dSSrihari Venkatesan 		/*
7298031591dSSrihari Venkatesan 		 * Single-core multi-threaded processors.
7308031591dSSrihari Venkatesan 		 */
7318031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_chipid;
7328031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = 0;
7338031591dSSrihari Venkatesan 	}
7348031591dSSrihari Venkatesan 	cpi->cpi_procnodeid = cpi->cpi_chipid;
735*7660e73fSHans Rosenfeld 	cpi->cpi_compunitid = cpi->cpi_coreid;
7368031591dSSrihari Venkatesan }
7378031591dSSrihari Venkatesan 
7388031591dSSrihari Venkatesan static void
7398031591dSSrihari Venkatesan cpuid_amd_getids(cpu_t *cpu)
7408031591dSSrihari Venkatesan {
7411fbe4a4fSSrihari Venkatesan 	int i, first_half, coreidsz;
7428031591dSSrihari Venkatesan 	uint32_t nb_caps_reg;
7438031591dSSrihari Venkatesan 	uint_t node2_1;
7448031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
745*7660e73fSHans Rosenfeld 	struct cpuid_regs *cp;
7468031591dSSrihari Venkatesan 
7478031591dSSrihari Venkatesan 	/*
7488031591dSSrihari Venkatesan 	 * AMD CMP chips currently have a single thread per core.
7498031591dSSrihari Venkatesan 	 *
7508031591dSSrihari Venkatesan 	 * Since no two cpus share a core we must assign a distinct coreid
7518031591dSSrihari Venkatesan 	 * per cpu, and we do this by using the cpu_id.  This scheme does not,
7528031591dSSrihari Venkatesan 	 * however, guarantee that sibling cores of a chip will have sequential
7538031591dSSrihari Venkatesan 	 * coreids starting at a multiple of the number of cores per chip -
7548031591dSSrihari Venkatesan 	 * that is usually the case, but if the ACPI MADT table is presented
7558031591dSSrihari Venkatesan 	 * in a different order then we need to perform a few more gymnastics
7568031591dSSrihari Venkatesan 	 * for the pkgcoreid.
7578031591dSSrihari Venkatesan 	 *
7588031591dSSrihari Venkatesan 	 * All processors in the system have the same number of enabled
7598031591dSSrihari Venkatesan 	 * cores. Cores within a processor are always numbered sequentially
7608031591dSSrihari Venkatesan 	 * from 0 regardless of how many or which are disabled, and there
7618031591dSSrihari Venkatesan 	 * is no way for operating system to discover the real core id when some
7628031591dSSrihari Venkatesan 	 * are disabled.
763*7660e73fSHans Rosenfeld 	 *
764*7660e73fSHans Rosenfeld 	 * In family 0x15, the cores come in pairs called compute units. They
765*7660e73fSHans Rosenfeld 	 * share I$ and L2 caches and the FPU. Enumeration of this feature is
766*7660e73fSHans Rosenfeld 	 * simplified by the new topology extensions CPUID leaf, indicated by
767*7660e73fSHans Rosenfeld 	 * the X86 feature X86FSET_TOPOEXT.
7688031591dSSrihari Venkatesan 	 */
7698031591dSSrihari Venkatesan 
7708031591dSSrihari Venkatesan 	cpi->cpi_coreid = cpu->cpu_id;
771*7660e73fSHans Rosenfeld 	cpi->cpi_compunitid = cpu->cpu_id;
7728031591dSSrihari Venkatesan 
7738031591dSSrihari Venkatesan 	if (cpi->cpi_xmaxeax >= 0x80000008) {
7748031591dSSrihari Venkatesan 
7758031591dSSrihari Venkatesan 		coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12);
7768031591dSSrihari Venkatesan 
7778031591dSSrihari Venkatesan 		/*
7788031591dSSrihari Venkatesan 		 * In AMD parlance chip is really a node while Solaris
7798031591dSSrihari Venkatesan 		 * sees chip as equivalent to socket/package.
7808031591dSSrihari Venkatesan 		 */
7818031591dSSrihari Venkatesan 		cpi->cpi_ncore_per_chip =
7828031591dSSrihari Venkatesan 		    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
7831fbe4a4fSSrihari Venkatesan 		if (coreidsz == 0) {
7848031591dSSrihari Venkatesan 			/* Use legacy method */
7851fbe4a4fSSrihari Venkatesan 			for (i = 1; i < cpi->cpi_ncore_per_chip; i <<= 1)
7861fbe4a4fSSrihari Venkatesan 				coreidsz++;
7871fbe4a4fSSrihari Venkatesan 			if (coreidsz == 0)
7881fbe4a4fSSrihari Venkatesan 				coreidsz = 1;
7891fbe4a4fSSrihari Venkatesan 		}
7908031591dSSrihari Venkatesan 	} else {
7918031591dSSrihari Venkatesan 		/* Assume single-core part */
7921fbe4a4fSSrihari Venkatesan 		cpi->cpi_ncore_per_chip = 1;
79372b70389SJakub Jermar 		coreidsz = 1;
7948031591dSSrihari Venkatesan 	}
7958031591dSSrihari Venkatesan 
7961fbe4a4fSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_pkgcoreid =
7971fbe4a4fSSrihari Venkatesan 	    cpi->cpi_apicid & ((1<<coreidsz) - 1);
7988031591dSSrihari Venkatesan 	cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip;
7998031591dSSrihari Venkatesan 
800*7660e73fSHans Rosenfeld 	/* Get node ID, compute unit ID */
801*7660e73fSHans Rosenfeld 	if (is_x86_feature(x86_featureset, X86FSET_TOPOEXT) &&
802*7660e73fSHans Rosenfeld 	    cpi->cpi_xmaxeax >= 0x8000001e) {
803*7660e73fSHans Rosenfeld 		cp = &cpi->cpi_extd[0x1e];
804*7660e73fSHans Rosenfeld 		cp->cp_eax = 0x8000001e;
805*7660e73fSHans Rosenfeld 		(void) __cpuid_insn(cp);
806*7660e73fSHans Rosenfeld 
807*7660e73fSHans Rosenfeld 		cpi->cpi_procnodes_per_pkg = BITX(cp->cp_ecx, 10, 8) + 1;
808*7660e73fSHans Rosenfeld 		cpi->cpi_procnodeid = BITX(cp->cp_ecx, 7, 0);
809*7660e73fSHans Rosenfeld 		cpi->cpi_cores_per_compunit = BITX(cp->cp_ebx, 15, 8) + 1;
810*7660e73fSHans Rosenfeld 		cpi->cpi_compunitid = BITX(cp->cp_ebx, 7, 0)
811*7660e73fSHans Rosenfeld 		    + (cpi->cpi_ncore_per_chip / cpi->cpi_cores_per_compunit)
812*7660e73fSHans Rosenfeld 		    * (cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg);
813*7660e73fSHans Rosenfeld 	} else if (cpi->cpi_family == 0xf || cpi->cpi_family >= 0x11) {
8141fbe4a4fSSrihari Venkatesan 		cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
8158031591dSSrihari Venkatesan 	} else if (cpi->cpi_family == 0x10) {
8168031591dSSrihari Venkatesan 		/*
8178031591dSSrihari Venkatesan 		 * See if we are a multi-node processor.
8188031591dSSrihari Venkatesan 		 * All processors in the system have the same number of nodes
8198031591dSSrihari Venkatesan 		 */
8208031591dSSrihari Venkatesan 		nb_caps_reg =  pci_getl_func(0, 24, 3, 0xe8);
8218031591dSSrihari Venkatesan 		if ((cpi->cpi_model < 8) || BITX(nb_caps_reg, 29, 29) == 0) {
8228031591dSSrihari Venkatesan 			/* Single-node */
8231fbe4a4fSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5,
8241fbe4a4fSSrihari Venkatesan 			    coreidsz);
8258031591dSSrihari Venkatesan 		} else {
8268031591dSSrihari Venkatesan 
8278031591dSSrihari Venkatesan 			/*
8288031591dSSrihari Venkatesan 			 * Multi-node revision D (2 nodes per package
8298031591dSSrihari Venkatesan 			 * are supported)
8308031591dSSrihari Venkatesan 			 */
8318031591dSSrihari Venkatesan 			cpi->cpi_procnodes_per_pkg = 2;
8328031591dSSrihari Venkatesan 
8338031591dSSrihari Venkatesan 			first_half = (cpi->cpi_pkgcoreid <=
8348031591dSSrihari Venkatesan 			    (cpi->cpi_ncore_per_chip/2 - 1));
8358031591dSSrihari Venkatesan 
8368031591dSSrihari Venkatesan 			if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) {
8378031591dSSrihari Venkatesan 				/* We are BSP */
8388031591dSSrihari Venkatesan 				cpi->cpi_procnodeid = (first_half ? 0 : 1);
8398031591dSSrihari Venkatesan 			} else {
8408031591dSSrihari Venkatesan 
8418031591dSSrihari Venkatesan 				/* We are AP */
8428031591dSSrihari Venkatesan 				/* NodeId[2:1] bits to use for reading F3xe8 */
8438031591dSSrihari Venkatesan 				node2_1 = BITX(cpi->cpi_apicid, 5, 4) << 1;
8448031591dSSrihari Venkatesan 
8458031591dSSrihari Venkatesan 				nb_caps_reg =
8468031591dSSrihari Venkatesan 				    pci_getl_func(0, 24 + node2_1, 3, 0xe8);
8478031591dSSrihari Venkatesan 
8488031591dSSrihari Venkatesan 				/*
8498031591dSSrihari Venkatesan 				 * Check IntNodeNum bit (31:30, but bit 31 is
8508031591dSSrihari Venkatesan 				 * always 0 on dual-node processors)
8518031591dSSrihari Venkatesan 				 */
8528031591dSSrihari Venkatesan 				if (BITX(nb_caps_reg, 30, 30) == 0)
8538031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
8548031591dSSrihari Venkatesan 					    !first_half;
8558031591dSSrihari Venkatesan 				else
8568031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
8578031591dSSrihari Venkatesan 					    first_half;
8588031591dSSrihari Venkatesan 			}
8598031591dSSrihari Venkatesan 		}
8608031591dSSrihari Venkatesan 	} else {
8618031591dSSrihari Venkatesan 		cpi->cpi_procnodeid = 0;
8628031591dSSrihari Venkatesan 	}
863*7660e73fSHans Rosenfeld 
864*7660e73fSHans Rosenfeld 	cpi->cpi_chipid =
865*7660e73fSHans Rosenfeld 	    cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg;
8668031591dSSrihari Venkatesan }
8678031591dSSrihari Venkatesan 
8687af88ac7SKuriakose Kuruvilla /*
8697af88ac7SKuriakose Kuruvilla  * Setup XFeature_Enabled_Mask register. Required by xsave feature.
8707af88ac7SKuriakose Kuruvilla  */
8717af88ac7SKuriakose Kuruvilla void
8727af88ac7SKuriakose Kuruvilla setup_xfem(void)
8737af88ac7SKuriakose Kuruvilla {
8747af88ac7SKuriakose Kuruvilla 	uint64_t flags = XFEATURE_LEGACY_FP;
8757af88ac7SKuriakose Kuruvilla 
8767af88ac7SKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
8777af88ac7SKuriakose Kuruvilla 
8787af88ac7SKuriakose Kuruvilla 	if (is_x86_feature(x86_featureset, X86FSET_SSE))
8797af88ac7SKuriakose Kuruvilla 		flags |= XFEATURE_SSE;
8807af88ac7SKuriakose Kuruvilla 
8817af88ac7SKuriakose Kuruvilla 	if (is_x86_feature(x86_featureset, X86FSET_AVX))
8827af88ac7SKuriakose Kuruvilla 		flags |= XFEATURE_AVX;
8837af88ac7SKuriakose Kuruvilla 
8847af88ac7SKuriakose Kuruvilla 	set_xcr(XFEATURE_ENABLED_MASK, flags);
8857af88ac7SKuriakose Kuruvilla 
8867af88ac7SKuriakose Kuruvilla 	xsave_bv_all = flags;
8877af88ac7SKuriakose Kuruvilla }
8887af88ac7SKuriakose Kuruvilla 
889dfea898aSKuriakose Kuruvilla void
890dfea898aSKuriakose Kuruvilla cpuid_pass1(cpu_t *cpu, uchar_t *featureset)
8917c478bd9Sstevel@tonic-gate {
8927c478bd9Sstevel@tonic-gate 	uint32_t mask_ecx, mask_edx;
8937c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
8948949bcd6Sandrei 	struct cpuid_regs *cp;
8957c478bd9Sstevel@tonic-gate 	int xcpuid;
896843e1988Sjohnlev #if !defined(__xpv)
8975b8a6efeSbholler 	extern int idle_cpu_prefer_mwait;
898843e1988Sjohnlev #endif
899ae115bc7Smrj 
9007c478bd9Sstevel@tonic-gate 	/*
901a3114836SGerry Liu 	 * Space statically allocated for BSP, ensure pointer is set
9027c478bd9Sstevel@tonic-gate 	 */
9037417cfdeSKuriakose Kuruvilla 	if (cpu->cpu_id == 0) {
9047417cfdeSKuriakose Kuruvilla 		if (cpu->cpu_m.mcpu_cpi == NULL)
905ae115bc7Smrj 			cpu->cpu_m.mcpu_cpi = &cpuid_info0;
9067417cfdeSKuriakose Kuruvilla 	}
9077417cfdeSKuriakose Kuruvilla 
9087417cfdeSKuriakose Kuruvilla 	add_x86_feature(featureset, X86FSET_CPUID);
9097417cfdeSKuriakose Kuruvilla 
910ae115bc7Smrj 	cpi = cpu->cpu_m.mcpu_cpi;
911ae115bc7Smrj 	ASSERT(cpi != NULL);
9127c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[0];
9138949bcd6Sandrei 	cp->cp_eax = 0;
9148949bcd6Sandrei 	cpi->cpi_maxeax = __cpuid_insn(cp);
9157c478bd9Sstevel@tonic-gate 	{
9167c478bd9Sstevel@tonic-gate 		uint32_t *iptr = (uint32_t *)cpi->cpi_vendorstr;
9177c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ebx;
9187c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_edx;
9197c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ecx;
9207c478bd9Sstevel@tonic-gate 		*(char *)&cpi->cpi_vendorstr[12] = '\0';
9217c478bd9Sstevel@tonic-gate 	}
9227c478bd9Sstevel@tonic-gate 
923e4b86885SCheng Sean Ye 	cpi->cpi_vendor = _cpuid_vendorstr_to_vendorcode(cpi->cpi_vendorstr);
9247c478bd9Sstevel@tonic-gate 	x86_vendor = cpi->cpi_vendor; /* for compatibility */
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	/*
9277c478bd9Sstevel@tonic-gate 	 * Limit the range in case of weird hardware
9287c478bd9Sstevel@tonic-gate 	 */
9297c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax > CPI_MAXEAX_MAX)
9307c478bd9Sstevel@tonic-gate 		cpi->cpi_maxeax = CPI_MAXEAX_MAX;
9317c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
9327c478bd9Sstevel@tonic-gate 		goto pass1_done;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[1];
9358949bcd6Sandrei 	cp->cp_eax = 1;
9368949bcd6Sandrei 	(void) __cpuid_insn(cp);
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	/*
9397c478bd9Sstevel@tonic-gate 	 * Extract identifying constants for easy access.
9407c478bd9Sstevel@tonic-gate 	 */
9417c478bd9Sstevel@tonic-gate 	cpi->cpi_model = CPI_MODEL(cpi);
9427c478bd9Sstevel@tonic-gate 	cpi->cpi_family = CPI_FAMILY(cpi);
9437c478bd9Sstevel@tonic-gate 
9445ff02082Sdmick 	if (cpi->cpi_family == 0xf)
9457c478bd9Sstevel@tonic-gate 		cpi->cpi_family += CPI_FAMILY_XTD(cpi);
9465ff02082Sdmick 
94768c91426Sdmick 	/*
948875b116eSkchow 	 * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
94968c91426Sdmick 	 * Intel, and presumably everyone else, uses model == 0xf, as
95068c91426Sdmick 	 * one would expect (max value means possible overflow).  Sigh.
95168c91426Sdmick 	 */
95268c91426Sdmick 
95368c91426Sdmick 	switch (cpi->cpi_vendor) {
954bf91205bSksadhukh 	case X86_VENDOR_Intel:
955bf91205bSksadhukh 		if (IS_EXTENDED_MODEL_INTEL(cpi))
956bf91205bSksadhukh 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
957447af253Sksadhukh 		break;
95868c91426Sdmick 	case X86_VENDOR_AMD:
959875b116eSkchow 		if (CPI_FAMILY(cpi) == 0xf)
96068c91426Sdmick 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
96168c91426Sdmick 		break;
96268c91426Sdmick 	default:
9635ff02082Sdmick 		if (cpi->cpi_model == 0xf)
9647c478bd9Sstevel@tonic-gate 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
96568c91426Sdmick 		break;
96668c91426Sdmick 	}
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	cpi->cpi_step = CPI_STEP(cpi);
9697c478bd9Sstevel@tonic-gate 	cpi->cpi_brandid = CPI_BRANDID(cpi);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	/*
9727c478bd9Sstevel@tonic-gate 	 * *default* assumptions:
9737c478bd9Sstevel@tonic-gate 	 * - believe %edx feature word
9747c478bd9Sstevel@tonic-gate 	 * - ignore %ecx feature word
9757c478bd9Sstevel@tonic-gate 	 * - 32-bit virtual and physical addressing
9767c478bd9Sstevel@tonic-gate 	 */
9777c478bd9Sstevel@tonic-gate 	mask_edx = 0xffffffff;
9787c478bd9Sstevel@tonic-gate 	mask_ecx = 0;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	cpi->cpi_pabits = cpi->cpi_vabits = 32;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
9837c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
9847c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
9857c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P5;
9865ff02082Sdmick 		else if (IS_LEGACY_P6(cpi)) {
9877c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P6;
9887c478bd9Sstevel@tonic-gate 			pentiumpro_bug4046376 = 1;
9897c478bd9Sstevel@tonic-gate 			pentiumpro_bug4064495 = 1;
9907c478bd9Sstevel@tonic-gate 			/*
9917c478bd9Sstevel@tonic-gate 			 * Clear the SEP bit when it was set erroneously
9927c478bd9Sstevel@tonic-gate 			 */
9937c478bd9Sstevel@tonic-gate 			if (cpi->cpi_model < 3 && cpi->cpi_step < 3)
9947c478bd9Sstevel@tonic-gate 				cp->cp_edx &= ~CPUID_INTC_EDX_SEP;
9955ff02082Sdmick 		} else if (IS_NEW_F6(cpi) || cpi->cpi_family == 0xf) {
9967c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P4;
9977c478bd9Sstevel@tonic-gate 			/*
9987c478bd9Sstevel@tonic-gate 			 * We don't currently depend on any of the %ecx
9997c478bd9Sstevel@tonic-gate 			 * features until Prescott, so we'll only check
10007c478bd9Sstevel@tonic-gate 			 * this from P4 onwards.  We might want to revisit
10017c478bd9Sstevel@tonic-gate 			 * that idea later.
10027c478bd9Sstevel@tonic-gate 			 */
10037c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
10047c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family > 0xf)
10057c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
10067c622d23Sbholler 		/*
10077c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
10087c622d23Sbholler 		 * to obtain the monitor linesize.
10097c622d23Sbholler 		 */
10107c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
10117c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
10127c478bd9Sstevel@tonic-gate 		break;
10137c478bd9Sstevel@tonic-gate 	case X86_VENDOR_IntelClone:
10147c478bd9Sstevel@tonic-gate 	default:
10157c478bd9Sstevel@tonic-gate 		break;
10167c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
10177c478bd9Sstevel@tonic-gate #if defined(OPTERON_ERRATUM_108)
10187c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 0xf && cpi->cpi_model == 0xe) {
10197c478bd9Sstevel@tonic-gate 			cp->cp_eax = (0xf0f & cp->cp_eax) | 0xc0;
10207c478bd9Sstevel@tonic-gate 			cpi->cpi_model = 0xc;
10217c478bd9Sstevel@tonic-gate 		} else
10227c478bd9Sstevel@tonic-gate #endif
10237c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5) {
10247c478bd9Sstevel@tonic-gate 			/*
10257c478bd9Sstevel@tonic-gate 			 * AMD K5 and K6
10267c478bd9Sstevel@tonic-gate 			 *
10277c478bd9Sstevel@tonic-gate 			 * These CPUs have an incomplete implementation
10287c478bd9Sstevel@tonic-gate 			 * of MCA/MCE which we mask away.
10297c478bd9Sstevel@tonic-gate 			 */
10308949bcd6Sandrei 			mask_edx &= ~(CPUID_INTC_EDX_MCE | CPUID_INTC_EDX_MCA);
10318949bcd6Sandrei 
10327c478bd9Sstevel@tonic-gate 			/*
10337c478bd9Sstevel@tonic-gate 			 * Model 0 uses the wrong (APIC) bit
10347c478bd9Sstevel@tonic-gate 			 * to indicate PGE.  Fix it here.
10357c478bd9Sstevel@tonic-gate 			 */
10368949bcd6Sandrei 			if (cpi->cpi_model == 0) {
10377c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x200) {
10387c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x200;
10397c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_INTC_EDX_PGE;
10407c478bd9Sstevel@tonic-gate 				}
10417c478bd9Sstevel@tonic-gate 			}
10428949bcd6Sandrei 
10438949bcd6Sandrei 			/*
10448949bcd6Sandrei 			 * Early models had problems w/ MMX; disable.
10458949bcd6Sandrei 			 */
10468949bcd6Sandrei 			if (cpi->cpi_model < 6)
10478949bcd6Sandrei 				mask_edx &= ~CPUID_INTC_EDX_MMX;
10488949bcd6Sandrei 		}
10498949bcd6Sandrei 
10508949bcd6Sandrei 		/*
10518949bcd6Sandrei 		 * For newer families, SSE3 and CX16, at least, are valid;
10528949bcd6Sandrei 		 * enable all
10538949bcd6Sandrei 		 */
10548949bcd6Sandrei 		if (cpi->cpi_family >= 0xf)
10558949bcd6Sandrei 			mask_ecx = 0xffffffff;
10567c622d23Sbholler 		/*
10577c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
10587c622d23Sbholler 		 * to obtain the monitor linesize.
10597c622d23Sbholler 		 */
10607c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
10617c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
10625b8a6efeSbholler 
1063843e1988Sjohnlev #if !defined(__xpv)
10645b8a6efeSbholler 		/*
10655b8a6efeSbholler 		 * Do not use MONITOR/MWAIT to halt in the idle loop on any AMD
10665b8a6efeSbholler 		 * processors.  AMD does not intend MWAIT to be used in the cpu
10675b8a6efeSbholler 		 * idle loop on current and future processors.  10h and future
10685b8a6efeSbholler 		 * AMD processors use more power in MWAIT than HLT.
10695b8a6efeSbholler 		 * Pre-family-10h Opterons do not have the MWAIT instruction.
10705b8a6efeSbholler 		 */
10715b8a6efeSbholler 		idle_cpu_prefer_mwait = 0;
1072843e1988Sjohnlev #endif
10735b8a6efeSbholler 
10747c478bd9Sstevel@tonic-gate 		break;
10757c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
10767c478bd9Sstevel@tonic-gate 		/*
10777c478bd9Sstevel@tonic-gate 		 * workaround the NT workaround in CMS 4.1
10787c478bd9Sstevel@tonic-gate 		 */
10797c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4 &&
10807c478bd9Sstevel@tonic-gate 		    (cpi->cpi_step == 2 || cpi->cpi_step == 3))
10817c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
10827c478bd9Sstevel@tonic-gate 		break;
10837c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
10847c478bd9Sstevel@tonic-gate 		/*
10857c478bd9Sstevel@tonic-gate 		 * workaround the NT workarounds again
10867c478bd9Sstevel@tonic-gate 		 */
10877c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 6)
10887c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
10897c478bd9Sstevel@tonic-gate 		break;
10907c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
10917c478bd9Sstevel@tonic-gate 		/*
10927c478bd9Sstevel@tonic-gate 		 * We rely heavily on the probing in locore
10937c478bd9Sstevel@tonic-gate 		 * to actually figure out what parts, if any,
10947c478bd9Sstevel@tonic-gate 		 * of the Cyrix cpuid instruction to believe.
10957c478bd9Sstevel@tonic-gate 		 */
10967c478bd9Sstevel@tonic-gate 		switch (x86_type) {
10977c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_486:
10987c478bd9Sstevel@tonic-gate 			mask_edx = 0;
10997c478bd9Sstevel@tonic-gate 			break;
11007c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86:
11017c478bd9Sstevel@tonic-gate 			mask_edx = 0;
11027c478bd9Sstevel@tonic-gate 			break;
11037c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86L:
11047c478bd9Sstevel@tonic-gate 			mask_edx =
11057c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11067c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8;
11077c478bd9Sstevel@tonic-gate 			break;
11087c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86MX:
11097c478bd9Sstevel@tonic-gate 			mask_edx =
11107c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11117c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11127c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11137c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
11147c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11157c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11167c478bd9Sstevel@tonic-gate 			break;
11177c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_GXm:
11187c478bd9Sstevel@tonic-gate 			mask_edx =
11197c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11207c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11217c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11227c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11237c478bd9Sstevel@tonic-gate 			break;
11247c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MediaGX:
11257c478bd9Sstevel@tonic-gate 			break;
11267c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MII:
11277c478bd9Sstevel@tonic-gate 		case X86_TYPE_VIA_CYRIX_III:
11287c478bd9Sstevel@tonic-gate 			mask_edx =
11297c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11307c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_TSC |
11317c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11327c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11337c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
11347c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11357c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11367c478bd9Sstevel@tonic-gate 			break;
11377c478bd9Sstevel@tonic-gate 		default:
11387c478bd9Sstevel@tonic-gate 			break;
11397c478bd9Sstevel@tonic-gate 		}
11407c478bd9Sstevel@tonic-gate 		break;
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 
1143843e1988Sjohnlev #if defined(__xpv)
1144843e1988Sjohnlev 	/*
1145843e1988Sjohnlev 	 * Do not support MONITOR/MWAIT under a hypervisor
1146843e1988Sjohnlev 	 */
1147843e1988Sjohnlev 	mask_ecx &= ~CPUID_INTC_ECX_MON;
11487af88ac7SKuriakose Kuruvilla 	/*
11497af88ac7SKuriakose Kuruvilla 	 * Do not support XSAVE under a hypervisor for now
11507af88ac7SKuriakose Kuruvilla 	 */
11517af88ac7SKuriakose Kuruvilla 	xsave_force_disable = B_TRUE;
11527af88ac7SKuriakose Kuruvilla 
1153843e1988Sjohnlev #endif	/* __xpv */
1154843e1988Sjohnlev 
11557af88ac7SKuriakose Kuruvilla 	if (xsave_force_disable) {
11567af88ac7SKuriakose Kuruvilla 		mask_ecx &= ~CPUID_INTC_ECX_XSAVE;
11577af88ac7SKuriakose Kuruvilla 		mask_ecx &= ~CPUID_INTC_ECX_AVX;
11587af88ac7SKuriakose Kuruvilla 	}
11597af88ac7SKuriakose Kuruvilla 
11607c478bd9Sstevel@tonic-gate 	/*
11617c478bd9Sstevel@tonic-gate 	 * Now we've figured out the masks that determine
11627c478bd9Sstevel@tonic-gate 	 * which bits we choose to believe, apply the masks
11637c478bd9Sstevel@tonic-gate 	 * to the feature words, then map the kernel's view
11647c478bd9Sstevel@tonic-gate 	 * of these feature words into its feature word.
11657c478bd9Sstevel@tonic-gate 	 */
11667c478bd9Sstevel@tonic-gate 	cp->cp_edx &= mask_edx;
11677c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= mask_ecx;
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	/*
1170ae115bc7Smrj 	 * apply any platform restrictions (we don't call this
1171ae115bc7Smrj 	 * immediately after __cpuid_insn here, because we need the
1172ae115bc7Smrj 	 * workarounds applied above first)
11737c478bd9Sstevel@tonic-gate 	 */
1174ae115bc7Smrj 	platform_cpuid_mangle(cpi->cpi_vendor, 1, cp);
11757c478bd9Sstevel@tonic-gate 
1176ae115bc7Smrj 	/*
1177ae115bc7Smrj 	 * fold in overrides from the "eeprom" mechanism
1178ae115bc7Smrj 	 */
11797c478bd9Sstevel@tonic-gate 	cp->cp_edx |= cpuid_feature_edx_include;
11807c478bd9Sstevel@tonic-gate 	cp->cp_edx &= ~cpuid_feature_edx_exclude;
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	cp->cp_ecx |= cpuid_feature_ecx_include;
11837c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= ~cpuid_feature_ecx_exclude;
11847c478bd9Sstevel@tonic-gate 
11857417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PSE) {
11867417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_LARGEPAGE);
11877417cfdeSKuriakose Kuruvilla 	}
11887417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_TSC) {
11897417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_TSC);
11907417cfdeSKuriakose Kuruvilla 	}
11917417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MSR) {
11927417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MSR);
11937417cfdeSKuriakose Kuruvilla 	}
11947417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MTRR) {
11957417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MTRR);
11967417cfdeSKuriakose Kuruvilla 	}
11977417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PGE) {
11987417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PGE);
11997417cfdeSKuriakose Kuruvilla 	}
12007417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CMOV) {
12017417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMOV);
12027417cfdeSKuriakose Kuruvilla 	}
12037417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MMX) {
12047417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MMX);
12057417cfdeSKuriakose Kuruvilla 	}
12067c478bd9Sstevel@tonic-gate 	if ((cp->cp_edx & CPUID_INTC_EDX_MCE) != 0 &&
12077417cfdeSKuriakose Kuruvilla 	    (cp->cp_edx & CPUID_INTC_EDX_MCA) != 0) {
12087417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MCA);
12097417cfdeSKuriakose Kuruvilla 	}
12107417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAE) {
12117417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAE);
12127417cfdeSKuriakose Kuruvilla 	}
12137417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CX8) {
12147417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX8);
12157417cfdeSKuriakose Kuruvilla 	}
12167417cfdeSKuriakose Kuruvilla 	if (cp->cp_ecx & CPUID_INTC_ECX_CX16) {
12177417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX16);
12187417cfdeSKuriakose Kuruvilla 	}
12197417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAT) {
12207417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAT);
12217417cfdeSKuriakose Kuruvilla 	}
12227417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_SEP) {
12237417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_SEP);
12247417cfdeSKuriakose Kuruvilla 	}
12257c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_FXSR) {
12267c478bd9Sstevel@tonic-gate 		/*
12277c478bd9Sstevel@tonic-gate 		 * In our implementation, fxsave/fxrstor
12287c478bd9Sstevel@tonic-gate 		 * are prerequisites before we'll even
12297c478bd9Sstevel@tonic-gate 		 * try and do SSE things.
12307c478bd9Sstevel@tonic-gate 		 */
12317417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE) {
12327417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE);
12337417cfdeSKuriakose Kuruvilla 		}
12347417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE2) {
12357417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE2);
12367417cfdeSKuriakose Kuruvilla 		}
12377417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) {
12387417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE3);
12397417cfdeSKuriakose Kuruvilla 		}
12407417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) {
12417417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSSE3);
12427417cfdeSKuriakose Kuruvilla 		}
12437417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) {
12447417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE4_1);
12457417cfdeSKuriakose Kuruvilla 		}
12467417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) {
12477417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE4_2);
12487417cfdeSKuriakose Kuruvilla 		}
12497417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_AES) {
12507417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_AES);
12517417cfdeSKuriakose Kuruvilla 		}
12527417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) {
12537417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_PCLMULQDQ);
1254d0f8ff6eSkk208521 		}
12557af88ac7SKuriakose Kuruvilla 
12567af88ac7SKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) {
12577af88ac7SKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_XSAVE);
12587af88ac7SKuriakose Kuruvilla 			/* We only test AVX when there is XSAVE */
12597af88ac7SKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_AVX) {
12607af88ac7SKuriakose Kuruvilla 				add_x86_feature(featureset,
12617af88ac7SKuriakose Kuruvilla 				    X86FSET_AVX);
12627af88ac7SKuriakose Kuruvilla 			}
12637af88ac7SKuriakose Kuruvilla 		}
12647c478bd9Sstevel@tonic-gate 	}
12657417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_DE) {
12667417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_DE);
12677417cfdeSKuriakose Kuruvilla 	}
12681d1a3942SBill Holler #if !defined(__xpv)
1269f98fbcecSbholler 	if (cp->cp_ecx & CPUID_INTC_ECX_MON) {
12701d1a3942SBill Holler 
12711d1a3942SBill Holler 		/*
12721d1a3942SBill Holler 		 * We require the CLFLUSH instruction for erratum workaround
12731d1a3942SBill Holler 		 * to use MONITOR/MWAIT.
12741d1a3942SBill Holler 		 */
12751d1a3942SBill Holler 		if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
1276f98fbcecSbholler 			cpi->cpi_mwait.support |= MWAIT_SUPPORT;
12777417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_MWAIT);
12781d1a3942SBill Holler 		} else {
12791d1a3942SBill Holler 			extern int idle_cpu_assert_cflush_monitor;
12801d1a3942SBill Holler 
12811d1a3942SBill Holler 			/*
12821d1a3942SBill Holler 			 * All processors we are aware of which have
12831d1a3942SBill Holler 			 * MONITOR/MWAIT also have CLFLUSH.
12841d1a3942SBill Holler 			 */
12851d1a3942SBill Holler 			if (idle_cpu_assert_cflush_monitor) {
12861d1a3942SBill Holler 				ASSERT((cp->cp_ecx & CPUID_INTC_ECX_MON) &&
12871d1a3942SBill Holler 				    (cp->cp_edx & CPUID_INTC_EDX_CLFSH));
1288f98fbcecSbholler 			}
12891d1a3942SBill Holler 		}
12901d1a3942SBill Holler 	}
12911d1a3942SBill Holler #endif	/* __xpv */
12927c478bd9Sstevel@tonic-gate 
1293faa20166SBryan Cantrill 	if (cp->cp_ecx & CPUID_INTC_ECX_VMX) {
1294faa20166SBryan Cantrill 		add_x86_feature(featureset, X86FSET_VMX);
1295faa20166SBryan Cantrill 	}
1296faa20166SBryan Cantrill 
129786c1f4dcSVikram Hegde 	/*
1298faa20166SBryan Cantrill 	 * Only need it first time, rest of the cpus would follow suit.
129986c1f4dcSVikram Hegde 	 * we only capture this for the bootcpu.
130086c1f4dcSVikram Hegde 	 */
130186c1f4dcSVikram Hegde 	if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
13027417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CLFSH);
130386c1f4dcSVikram Hegde 		x86_clflush_size = (BITX(cp->cp_ebx, 15, 8) * 8);
130486c1f4dcSVikram Hegde 	}
13057417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_PAE))
13067c478bd9Sstevel@tonic-gate 		cpi->cpi_pabits = 36;
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	/*
13097c478bd9Sstevel@tonic-gate 	 * Hyperthreading configuration is slightly tricky on Intel
13107c478bd9Sstevel@tonic-gate 	 * and pure clones, and even trickier on AMD.
13117c478bd9Sstevel@tonic-gate 	 *
13127c478bd9Sstevel@tonic-gate 	 * (AMD chose to set the HTT bit on their CMP processors,
13137c478bd9Sstevel@tonic-gate 	 * even though they're not actually hyperthreaded.  Thus it
13147c478bd9Sstevel@tonic-gate 	 * takes a bit more work to figure out what's really going
1315ae115bc7Smrj 	 * on ... see the handling of the CMP_LGCY bit below)
13167c478bd9Sstevel@tonic-gate 	 */
13177c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_HTT) {
13187c478bd9Sstevel@tonic-gate 		cpi->cpi_ncpu_per_chip = CPI_CPU_COUNT(cpi);
13197c478bd9Sstevel@tonic-gate 		if (cpi->cpi_ncpu_per_chip > 1)
13207417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_HTT);
13218949bcd6Sandrei 	} else {
13228949bcd6Sandrei 		cpi->cpi_ncpu_per_chip = 1;
13237c478bd9Sstevel@tonic-gate 	}
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	/*
13267c478bd9Sstevel@tonic-gate 	 * Work on the "extended" feature information, doing
13277c478bd9Sstevel@tonic-gate 	 * some basic initialization for cpuid_pass2()
13287c478bd9Sstevel@tonic-gate 	 */
13297c478bd9Sstevel@tonic-gate 	xcpuid = 0;
13307c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
13317c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
13325ff02082Sdmick 		if (IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf)
13337c478bd9Sstevel@tonic-gate 			xcpuid++;
13347c478bd9Sstevel@tonic-gate 		break;
13357c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
13367c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
13377c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
13387c478bd9Sstevel@tonic-gate 			xcpuid++;
13397c478bd9Sstevel@tonic-gate 		break;
13407c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
13417c478bd9Sstevel@tonic-gate 		/*
13427c478bd9Sstevel@tonic-gate 		 * Only these Cyrix CPUs are -known- to support
13437c478bd9Sstevel@tonic-gate 		 * extended cpuid operations.
13447c478bd9Sstevel@tonic-gate 		 */
13457c478bd9Sstevel@tonic-gate 		if (x86_type == X86_TYPE_VIA_CYRIX_III ||
13467c478bd9Sstevel@tonic-gate 		    x86_type == X86_TYPE_CYRIX_GXm)
13477c478bd9Sstevel@tonic-gate 			xcpuid++;
13487c478bd9Sstevel@tonic-gate 		break;
13497c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
13507c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
13517c478bd9Sstevel@tonic-gate 	default:
13527c478bd9Sstevel@tonic-gate 		xcpuid++;
13537c478bd9Sstevel@tonic-gate 		break;
13547c478bd9Sstevel@tonic-gate 	}
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	if (xcpuid) {
13577c478bd9Sstevel@tonic-gate 		cp = &cpi->cpi_extd[0];
13588949bcd6Sandrei 		cp->cp_eax = 0x80000000;
13598949bcd6Sandrei 		cpi->cpi_xmaxeax = __cpuid_insn(cp);
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax & 0x80000000) {
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax > CPI_XMAXEAX_MAX)
13657c478bd9Sstevel@tonic-gate 			cpi->cpi_xmaxeax = CPI_XMAXEAX_MAX;
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
13687c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
13697c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
13707c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000001)
13717c478bd9Sstevel@tonic-gate 				break;
13727c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[1];
13738949bcd6Sandrei 			cp->cp_eax = 0x80000001;
13748949bcd6Sandrei 			(void) __cpuid_insn(cp);
1375ae115bc7Smrj 
13767c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
13777c478bd9Sstevel@tonic-gate 			    cpi->cpi_family == 5 &&
13787c478bd9Sstevel@tonic-gate 			    cpi->cpi_model == 6 &&
13797c478bd9Sstevel@tonic-gate 			    cpi->cpi_step == 6) {
13807c478bd9Sstevel@tonic-gate 				/*
13817c478bd9Sstevel@tonic-gate 				 * K6 model 6 uses bit 10 to indicate SYSC
13827c478bd9Sstevel@tonic-gate 				 * Later models use bit 11. Fix it here.
13837c478bd9Sstevel@tonic-gate 				 */
13847c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x400) {
13857c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x400;
13867c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_AMD_EDX_SYSC;
13877c478bd9Sstevel@tonic-gate 				}
13887c478bd9Sstevel@tonic-gate 			}
13897c478bd9Sstevel@tonic-gate 
1390ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000001, cp);
1391ae115bc7Smrj 
13927c478bd9Sstevel@tonic-gate 			/*
13937c478bd9Sstevel@tonic-gate 			 * Compute the additions to the kernel's feature word.
13947c478bd9Sstevel@tonic-gate 			 */
13957417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_NX) {
13967417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_NX);
13977417cfdeSKuriakose Kuruvilla 			}
13987c478bd9Sstevel@tonic-gate 
139919397407SSherry Moore 			/*
140019397407SSherry Moore 			 * Regardless whether or not we boot 64-bit,
140119397407SSherry Moore 			 * we should have a way to identify whether
140219397407SSherry Moore 			 * the CPU is capable of running 64-bit.
140319397407SSherry Moore 			 */
14047417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_LM) {
14057417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_64);
14067417cfdeSKuriakose Kuruvilla 			}
140719397407SSherry Moore 
140802bc52beSkchow #if defined(__amd64)
140902bc52beSkchow 			/* 1 GB large page - enable only for 64 bit kernel */
14107417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_1GPG) {
14117417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_1GPG);
14127417cfdeSKuriakose Kuruvilla 			}
141302bc52beSkchow #endif
141402bc52beSkchow 
1415f8801251Skk208521 			if ((cpi->cpi_vendor == X86_VENDOR_AMD) &&
1416f8801251Skk208521 			    (cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_FXSR) &&
14177417cfdeSKuriakose Kuruvilla 			    (cp->cp_ecx & CPUID_AMD_ECX_SSE4A)) {
14187417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4A);
14197417cfdeSKuriakose Kuruvilla 			}
1420f8801251Skk208521 
14217c478bd9Sstevel@tonic-gate 			/*
1422ae115bc7Smrj 			 * If both the HTT and CMP_LGCY bits are set,
14238949bcd6Sandrei 			 * then we're not actually HyperThreaded.  Read
14248949bcd6Sandrei 			 * "AMD CPUID Specification" for more details.
14257c478bd9Sstevel@tonic-gate 			 */
14267c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
14277417cfdeSKuriakose Kuruvilla 			    is_x86_feature(featureset, X86FSET_HTT) &&
1428ae115bc7Smrj 			    (cp->cp_ecx & CPUID_AMD_ECX_CMP_LGCY)) {
14297417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_HTT);
14307417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_CMP);
14318949bcd6Sandrei 			}
1432ae115bc7Smrj #if defined(__amd64)
14337c478bd9Sstevel@tonic-gate 			/*
14347c478bd9Sstevel@tonic-gate 			 * It's really tricky to support syscall/sysret in
14357c478bd9Sstevel@tonic-gate 			 * the i386 kernel; we rely on sysenter/sysexit
14367c478bd9Sstevel@tonic-gate 			 * instead.  In the amd64 kernel, things are -way-
14377c478bd9Sstevel@tonic-gate 			 * better.
14387c478bd9Sstevel@tonic-gate 			 */
14397417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_SYSC) {
14407417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_ASYSC);
14417417cfdeSKuriakose Kuruvilla 			}
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 			/*
14447c478bd9Sstevel@tonic-gate 			 * While we're thinking about system calls, note
14457c478bd9Sstevel@tonic-gate 			 * that AMD processors don't support sysenter
14467c478bd9Sstevel@tonic-gate 			 * in long mode at all, so don't try to program them.
14477c478bd9Sstevel@tonic-gate 			 */
14487417cfdeSKuriakose Kuruvilla 			if (x86_vendor == X86_VENDOR_AMD) {
14497417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_SEP);
14507417cfdeSKuriakose Kuruvilla 			}
14517c478bd9Sstevel@tonic-gate #endif
14527417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_TSCP) {
14537417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_TSCP);
14547417cfdeSKuriakose Kuruvilla 			}
1455faa20166SBryan Cantrill 
1456faa20166SBryan Cantrill 			if (cp->cp_ecx & CPUID_AMD_ECX_SVM) {
1457faa20166SBryan Cantrill 				add_x86_feature(featureset, X86FSET_SVM);
1458faa20166SBryan Cantrill 			}
1459*7660e73fSHans Rosenfeld 
1460*7660e73fSHans Rosenfeld 			if (cp->cp_ecx & CPUID_AMD_ECX_TOPOEXT) {
1461*7660e73fSHans Rosenfeld 				add_x86_feature(featureset, X86FSET_TOPOEXT);
1462*7660e73fSHans Rosenfeld 			}
14637c478bd9Sstevel@tonic-gate 			break;
14647c478bd9Sstevel@tonic-gate 		default:
14657c478bd9Sstevel@tonic-gate 			break;
14667c478bd9Sstevel@tonic-gate 		}
14677c478bd9Sstevel@tonic-gate 
14688949bcd6Sandrei 		/*
14698949bcd6Sandrei 		 * Get CPUID data about processor cores and hyperthreads.
14708949bcd6Sandrei 		 */
14717c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
14727c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
14738949bcd6Sandrei 			if (cpi->cpi_maxeax >= 4) {
14748949bcd6Sandrei 				cp = &cpi->cpi_std[4];
14758949bcd6Sandrei 				cp->cp_eax = 4;
14768949bcd6Sandrei 				cp->cp_ecx = 0;
14778949bcd6Sandrei 				(void) __cpuid_insn(cp);
1478ae115bc7Smrj 				platform_cpuid_mangle(cpi->cpi_vendor, 4, cp);
14798949bcd6Sandrei 			}
14808949bcd6Sandrei 			/*FALLTHROUGH*/
14817c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
14827c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000008)
14837c478bd9Sstevel@tonic-gate 				break;
14847c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[8];
14858949bcd6Sandrei 			cp->cp_eax = 0x80000008;
14868949bcd6Sandrei 			(void) __cpuid_insn(cp);
1487ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000008, cp);
1488ae115bc7Smrj 
14897c478bd9Sstevel@tonic-gate 			/*
14907c478bd9Sstevel@tonic-gate 			 * Virtual and physical address limits from
14917c478bd9Sstevel@tonic-gate 			 * cpuid override previously guessed values.
14927c478bd9Sstevel@tonic-gate 			 */
14937c478bd9Sstevel@tonic-gate 			cpi->cpi_pabits = BITX(cp->cp_eax, 7, 0);
14947c478bd9Sstevel@tonic-gate 			cpi->cpi_vabits = BITX(cp->cp_eax, 15, 8);
14957c478bd9Sstevel@tonic-gate 			break;
14967c478bd9Sstevel@tonic-gate 		default:
14977c478bd9Sstevel@tonic-gate 			break;
14987c478bd9Sstevel@tonic-gate 		}
14998949bcd6Sandrei 
1500d129bde2Sesaxe 		/*
1501d129bde2Sesaxe 		 * Derive the number of cores per chip
1502d129bde2Sesaxe 		 */
15038949bcd6Sandrei 		switch (cpi->cpi_vendor) {
15048949bcd6Sandrei 		case X86_VENDOR_Intel:
15058949bcd6Sandrei 			if (cpi->cpi_maxeax < 4) {
15068949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
15078949bcd6Sandrei 				break;
15088949bcd6Sandrei 			} else {
15098949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
15108949bcd6Sandrei 				    BITX((cpi)->cpi_std[4].cp_eax, 31, 26) + 1;
15118949bcd6Sandrei 			}
15128949bcd6Sandrei 			break;
15138949bcd6Sandrei 		case X86_VENDOR_AMD:
15148949bcd6Sandrei 			if (cpi->cpi_xmaxeax < 0x80000008) {
15158949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
15168949bcd6Sandrei 				break;
15178949bcd6Sandrei 			} else {
151810569901Sgavinm 				/*
151910569901Sgavinm 				 * On family 0xf cpuid fn 2 ECX[7:0] "NC" is
152010569901Sgavinm 				 * 1 less than the number of physical cores on
152110569901Sgavinm 				 * the chip.  In family 0x10 this value can
152210569901Sgavinm 				 * be affected by "downcoring" - it reflects
152310569901Sgavinm 				 * 1 less than the number of cores actually
152410569901Sgavinm 				 * enabled on this node.
152510569901Sgavinm 				 */
15268949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
15278949bcd6Sandrei 				    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
15288949bcd6Sandrei 			}
15298949bcd6Sandrei 			break;
15308949bcd6Sandrei 		default:
15318949bcd6Sandrei 			cpi->cpi_ncore_per_chip = 1;
15328949bcd6Sandrei 			break;
15337c478bd9Sstevel@tonic-gate 		}
15340e751525SEric Saxe 
15350e751525SEric Saxe 		/*
15360e751525SEric Saxe 		 * Get CPUID data about TSC Invariance in Deep C-State.
15370e751525SEric Saxe 		 */
15380e751525SEric Saxe 		switch (cpi->cpi_vendor) {
15390e751525SEric Saxe 		case X86_VENDOR_Intel:
15400e751525SEric Saxe 			if (cpi->cpi_maxeax >= 7) {
15410e751525SEric Saxe 				cp = &cpi->cpi_extd[7];
15420e751525SEric Saxe 				cp->cp_eax = 0x80000007;
15430e751525SEric Saxe 				cp->cp_ecx = 0;
15440e751525SEric Saxe 				(void) __cpuid_insn(cp);
15450e751525SEric Saxe 			}
15460e751525SEric Saxe 			break;
15470e751525SEric Saxe 		default:
15480e751525SEric Saxe 			break;
15490e751525SEric Saxe 		}
1550fa2e767eSgavinm 	} else {
1551fa2e767eSgavinm 		cpi->cpi_ncore_per_chip = 1;
15528949bcd6Sandrei 	}
15538949bcd6Sandrei 
15548949bcd6Sandrei 	/*
15558949bcd6Sandrei 	 * If more than one core, then this processor is CMP.
15568949bcd6Sandrei 	 */
15577417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncore_per_chip > 1) {
15587417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMP);
15597417cfdeSKuriakose Kuruvilla 	}
1560ae115bc7Smrj 
15618949bcd6Sandrei 	/*
15628949bcd6Sandrei 	 * If the number of cores is the same as the number
15638949bcd6Sandrei 	 * of CPUs, then we cannot have HyperThreading.
15648949bcd6Sandrei 	 */
15657417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncpu_per_chip == cpi->cpi_ncore_per_chip) {
15667417cfdeSKuriakose Kuruvilla 		remove_x86_feature(featureset, X86FSET_HTT);
15677417cfdeSKuriakose Kuruvilla 	}
15688949bcd6Sandrei 
15698031591dSSrihari Venkatesan 	cpi->cpi_apicid = CPI_APIC_ID(cpi);
15708031591dSSrihari Venkatesan 	cpi->cpi_procnodes_per_pkg = 1;
1571*7660e73fSHans Rosenfeld 	cpi->cpi_cores_per_compunit = 1;
15727417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE &&
15737417cfdeSKuriakose Kuruvilla 	    is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) {
15748949bcd6Sandrei 		/*
15758949bcd6Sandrei 		 * Single-core single-threaded processors.
15768949bcd6Sandrei 		 */
15777c478bd9Sstevel@tonic-gate 		cpi->cpi_chipid = -1;
15787c478bd9Sstevel@tonic-gate 		cpi->cpi_clogid = 0;
15798949bcd6Sandrei 		cpi->cpi_coreid = cpu->cpu_id;
158010569901Sgavinm 		cpi->cpi_pkgcoreid = 0;
15818031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_AMD)
15828031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 3, 0);
15838031591dSSrihari Venkatesan 		else
15848031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
15857c478bd9Sstevel@tonic-gate 	} else if (cpi->cpi_ncpu_per_chip > 1) {
15868031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_Intel)
15877417cfdeSKuriakose Kuruvilla 			cpuid_intel_getids(cpu, featureset);
15888031591dSSrihari Venkatesan 		else if (cpi->cpi_vendor == X86_VENDOR_AMD)
15898031591dSSrihari Venkatesan 			cpuid_amd_getids(cpu);
15908031591dSSrihari Venkatesan 		else {
15918949bcd6Sandrei 			/*
15928949bcd6Sandrei 			 * All other processors are currently
15938949bcd6Sandrei 			 * assumed to have single cores.
15948949bcd6Sandrei 			 */
15958949bcd6Sandrei 			cpi->cpi_coreid = cpi->cpi_chipid;
159610569901Sgavinm 			cpi->cpi_pkgcoreid = 0;
15978031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
1598*7660e73fSHans Rosenfeld 			cpi->cpi_compunitid = cpi->cpi_chipid;
15998949bcd6Sandrei 		}
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16028a40a695Sgavinm 	/*
16038a40a695Sgavinm 	 * Synthesize chip "revision" and socket type
16048a40a695Sgavinm 	 */
1605e4b86885SCheng Sean Ye 	cpi->cpi_chiprev = _cpuid_chiprev(cpi->cpi_vendor, cpi->cpi_family,
1606e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
1607e4b86885SCheng Sean Ye 	cpi->cpi_chiprevstr = _cpuid_chiprevstr(cpi->cpi_vendor,
1608e4b86885SCheng Sean Ye 	    cpi->cpi_family, cpi->cpi_model, cpi->cpi_step);
1609e4b86885SCheng Sean Ye 	cpi->cpi_socket = _cpuid_skt(cpi->cpi_vendor, cpi->cpi_family,
1610e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
16118a40a695Sgavinm 
16127c478bd9Sstevel@tonic-gate pass1_done:
16137c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 1;
16147c478bd9Sstevel@tonic-gate }
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate  * Make copies of the cpuid table entries we depend on, in
16187c478bd9Sstevel@tonic-gate  * part for ease of parsing now, in part so that we have only
16197c478bd9Sstevel@tonic-gate  * one place to correct any of it, in part for ease of
16207c478bd9Sstevel@tonic-gate  * later export to userland, and in part so we can look at
16217c478bd9Sstevel@tonic-gate  * this stuff in a crash dump.
16227c478bd9Sstevel@tonic-gate  */
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16257c478bd9Sstevel@tonic-gate void
16267c478bd9Sstevel@tonic-gate cpuid_pass2(cpu_t *cpu)
16277c478bd9Sstevel@tonic-gate {
16287c478bd9Sstevel@tonic-gate 	uint_t n, nmax;
16297c478bd9Sstevel@tonic-gate 	int i;
16308949bcd6Sandrei 	struct cpuid_regs *cp;
16317c478bd9Sstevel@tonic-gate 	uint8_t *dp;
16327c478bd9Sstevel@tonic-gate 	uint32_t *iptr;
16337c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 1);
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
16387c478bd9Sstevel@tonic-gate 		goto pass2_done;
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_maxeax + 1) > NMAX_CPI_STD)
16417c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_STD;
16427c478bd9Sstevel@tonic-gate 	/*
16437c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
16447c478bd9Sstevel@tonic-gate 	 */
16457c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_std[2]; n < nmax; n++, cp++) {
16468949bcd6Sandrei 		cp->cp_eax = n;
1647d129bde2Sesaxe 
1648d129bde2Sesaxe 		/*
1649d129bde2Sesaxe 		 * CPUID function 4 expects %ecx to be initialized
1650d129bde2Sesaxe 		 * with an index which indicates which cache to return
1651d129bde2Sesaxe 		 * information about. The OS is expected to call function 4
1652d129bde2Sesaxe 		 * with %ecx set to 0, 1, 2, ... until it returns with
1653d129bde2Sesaxe 		 * EAX[4:0] set to 0, which indicates there are no more
1654d129bde2Sesaxe 		 * caches.
1655d129bde2Sesaxe 		 *
1656d129bde2Sesaxe 		 * Here, populate cpi_std[4] with the information returned by
1657d129bde2Sesaxe 		 * function 4 when %ecx == 0, and do the rest in cpuid_pass3()
1658d129bde2Sesaxe 		 * when dynamic memory allocation becomes available.
1659d129bde2Sesaxe 		 *
1660d129bde2Sesaxe 		 * Note: we need to explicitly initialize %ecx here, since
1661d129bde2Sesaxe 		 * function 4 may have been previously invoked.
1662d129bde2Sesaxe 		 */
1663d129bde2Sesaxe 		if (n == 4)
1664d129bde2Sesaxe 			cp->cp_ecx = 0;
1665d129bde2Sesaxe 
16668949bcd6Sandrei 		(void) __cpuid_insn(cp);
1667ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, n, cp);
16687c478bd9Sstevel@tonic-gate 		switch (n) {
16697c478bd9Sstevel@tonic-gate 		case 2:
16707c478bd9Sstevel@tonic-gate 			/*
16717c478bd9Sstevel@tonic-gate 			 * "the lower 8 bits of the %eax register
16727c478bd9Sstevel@tonic-gate 			 * contain a value that identifies the number
16737c478bd9Sstevel@tonic-gate 			 * of times the cpuid [instruction] has to be
16747c478bd9Sstevel@tonic-gate 			 * executed to obtain a complete image of the
16757c478bd9Sstevel@tonic-gate 			 * processor's caching systems."
16767c478bd9Sstevel@tonic-gate 			 *
16777c478bd9Sstevel@tonic-gate 			 * How *do* they make this stuff up?
16787c478bd9Sstevel@tonic-gate 			 */
16797c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache = sizeof (*cp) *
16807c478bd9Sstevel@tonic-gate 			    BITX(cp->cp_eax, 7, 0);
16817c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache == 0)
16827c478bd9Sstevel@tonic-gate 				break;
16837c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache--;	/* skip count byte */
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 			/*
16867c478bd9Sstevel@tonic-gate 			 * Well, for now, rather than attempt to implement
16877c478bd9Sstevel@tonic-gate 			 * this slightly dubious algorithm, we just look
16887c478bd9Sstevel@tonic-gate 			 * at the first 15 ..
16897c478bd9Sstevel@tonic-gate 			 */
16907c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache > (sizeof (*cp) - 1))
16917c478bd9Sstevel@tonic-gate 				cpi->cpi_ncache = sizeof (*cp) - 1;
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 			dp = cpi->cpi_cacheinfo;
16947c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_eax, 31, 31) == 0) {
16957c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_eax;
169663d3f7dfSkk208521 				for (i = 1; i < 4; i++)
16977c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16987c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16997c478bd9Sstevel@tonic-gate 			}
17007c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ebx, 31, 31) == 0) {
17017c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ebx;
17027c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
17037c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
17047c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
17057c478bd9Sstevel@tonic-gate 			}
17067c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ecx, 31, 31) == 0) {
17077c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ecx;
17087c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
17097c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
17107c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
17117c478bd9Sstevel@tonic-gate 			}
17127c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_edx, 31, 31) == 0) {
17137c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_edx;
17147c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
17157c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
17167c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
17177c478bd9Sstevel@tonic-gate 			}
17187c478bd9Sstevel@tonic-gate 			break;
1719f98fbcecSbholler 
17207c478bd9Sstevel@tonic-gate 		case 3:	/* Processor serial number, if PSN supported */
1721f98fbcecSbholler 			break;
1722f98fbcecSbholler 
17237c478bd9Sstevel@tonic-gate 		case 4:	/* Deterministic cache parameters */
1724f98fbcecSbholler 			break;
1725f98fbcecSbholler 
17267c478bd9Sstevel@tonic-gate 		case 5:	/* Monitor/Mwait parameters */
17275b8a6efeSbholler 		{
17285b8a6efeSbholler 			size_t mwait_size;
1729f98fbcecSbholler 
1730f98fbcecSbholler 			/*
1731f98fbcecSbholler 			 * check cpi_mwait.support which was set in cpuid_pass1
1732f98fbcecSbholler 			 */
1733f98fbcecSbholler 			if (!(cpi->cpi_mwait.support & MWAIT_SUPPORT))
1734f98fbcecSbholler 				break;
1735f98fbcecSbholler 
17365b8a6efeSbholler 			/*
17375b8a6efeSbholler 			 * Protect ourself from insane mwait line size.
17385b8a6efeSbholler 			 * Workaround for incomplete hardware emulator(s).
17395b8a6efeSbholler 			 */
17405b8a6efeSbholler 			mwait_size = (size_t)MWAIT_SIZE_MAX(cpi);
17415b8a6efeSbholler 			if (mwait_size < sizeof (uint32_t) ||
17425b8a6efeSbholler 			    !ISP2(mwait_size)) {
17435b8a6efeSbholler #if DEBUG
17445b8a6efeSbholler 				cmn_err(CE_NOTE, "Cannot handle cpu %d mwait "
17455d8efbbcSSaurabh Misra 				    "size %ld", cpu->cpu_id, (long)mwait_size);
17465b8a6efeSbholler #endif
17475b8a6efeSbholler 				break;
17485b8a6efeSbholler 			}
17495b8a6efeSbholler 
1750f98fbcecSbholler 			cpi->cpi_mwait.mon_min = (size_t)MWAIT_SIZE_MIN(cpi);
17515b8a6efeSbholler 			cpi->cpi_mwait.mon_max = mwait_size;
1752f98fbcecSbholler 			if (MWAIT_EXTENSION(cpi)) {
1753f98fbcecSbholler 				cpi->cpi_mwait.support |= MWAIT_EXTENSIONS;
1754f98fbcecSbholler 				if (MWAIT_INT_ENABLE(cpi))
1755f98fbcecSbholler 					cpi->cpi_mwait.support |=
1756f98fbcecSbholler 					    MWAIT_ECX_INT_ENABLE;
1757f98fbcecSbholler 			}
1758f98fbcecSbholler 			break;
17595b8a6efeSbholler 		}
17607c478bd9Sstevel@tonic-gate 		default:
17617c478bd9Sstevel@tonic-gate 			break;
17627c478bd9Sstevel@tonic-gate 		}
17637c478bd9Sstevel@tonic-gate 	}
17647c478bd9Sstevel@tonic-gate 
1765b6917abeSmishra 	if (cpi->cpi_maxeax >= 0xB && cpi->cpi_vendor == X86_VENDOR_Intel) {
17665d8efbbcSSaurabh Misra 		struct cpuid_regs regs;
17675d8efbbcSSaurabh Misra 
17685d8efbbcSSaurabh Misra 		cp = &regs;
1769b6917abeSmishra 		cp->cp_eax = 0xB;
17705d8efbbcSSaurabh Misra 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
1771b6917abeSmishra 
1772b6917abeSmishra 		(void) __cpuid_insn(cp);
1773b6917abeSmishra 
1774b6917abeSmishra 		/*
1775b6917abeSmishra 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
1776b6917abeSmishra 		 * indicates that the extended topology enumeration leaf is
1777b6917abeSmishra 		 * available.
1778b6917abeSmishra 		 */
1779b6917abeSmishra 		if (cp->cp_ebx) {
1780b6917abeSmishra 			uint32_t x2apic_id;
1781b6917abeSmishra 			uint_t coreid_shift = 0;
1782b6917abeSmishra 			uint_t ncpu_per_core = 1;
1783b6917abeSmishra 			uint_t chipid_shift = 0;
1784b6917abeSmishra 			uint_t ncpu_per_chip = 1;
1785b6917abeSmishra 			uint_t i;
1786b6917abeSmishra 			uint_t level;
1787b6917abeSmishra 
1788b6917abeSmishra 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
1789b6917abeSmishra 				cp->cp_eax = 0xB;
1790b6917abeSmishra 				cp->cp_ecx = i;
1791b6917abeSmishra 
1792b6917abeSmishra 				(void) __cpuid_insn(cp);
1793b6917abeSmishra 				level = CPI_CPU_LEVEL_TYPE(cp);
1794b6917abeSmishra 
1795b6917abeSmishra 				if (level == 1) {
1796b6917abeSmishra 					x2apic_id = cp->cp_edx;
1797b6917abeSmishra 					coreid_shift = BITX(cp->cp_eax, 4, 0);
1798b6917abeSmishra 					ncpu_per_core = BITX(cp->cp_ebx, 15, 0);
1799b6917abeSmishra 				} else if (level == 2) {
1800b6917abeSmishra 					x2apic_id = cp->cp_edx;
1801b6917abeSmishra 					chipid_shift = BITX(cp->cp_eax, 4, 0);
1802b6917abeSmishra 					ncpu_per_chip = BITX(cp->cp_ebx, 15, 0);
1803b6917abeSmishra 				}
1804b6917abeSmishra 			}
1805b6917abeSmishra 
1806b6917abeSmishra 			cpi->cpi_apicid = x2apic_id;
1807b6917abeSmishra 			cpi->cpi_ncpu_per_chip = ncpu_per_chip;
1808b6917abeSmishra 			cpi->cpi_ncore_per_chip = ncpu_per_chip /
1809b6917abeSmishra 			    ncpu_per_core;
1810b6917abeSmishra 			cpi->cpi_chipid = x2apic_id >> chipid_shift;
1811b6917abeSmishra 			cpi->cpi_clogid = x2apic_id & ((1 << chipid_shift) - 1);
1812b6917abeSmishra 			cpi->cpi_coreid = x2apic_id >> coreid_shift;
1813b6917abeSmishra 			cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
1814b6917abeSmishra 		}
18155d8efbbcSSaurabh Misra 
18165d8efbbcSSaurabh Misra 		/* Make cp NULL so that we don't stumble on others */
18175d8efbbcSSaurabh Misra 		cp = NULL;
1818b6917abeSmishra 	}
1819b6917abeSmishra 
18207af88ac7SKuriakose Kuruvilla 	/*
18217af88ac7SKuriakose Kuruvilla 	 * XSAVE enumeration
18227af88ac7SKuriakose Kuruvilla 	 */
182363408480SHans Rosenfeld 	if (cpi->cpi_maxeax >= 0xD) {
18247af88ac7SKuriakose Kuruvilla 		struct cpuid_regs regs;
18257af88ac7SKuriakose Kuruvilla 		boolean_t cpuid_d_valid = B_TRUE;
18267af88ac7SKuriakose Kuruvilla 
18277af88ac7SKuriakose Kuruvilla 		cp = &regs;
18287af88ac7SKuriakose Kuruvilla 		cp->cp_eax = 0xD;
18297af88ac7SKuriakose Kuruvilla 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
18307af88ac7SKuriakose Kuruvilla 
18317af88ac7SKuriakose Kuruvilla 		(void) __cpuid_insn(cp);
18327af88ac7SKuriakose Kuruvilla 
18337af88ac7SKuriakose Kuruvilla 		/*
18347af88ac7SKuriakose Kuruvilla 		 * Sanity checks for debug
18357af88ac7SKuriakose Kuruvilla 		 */
18367af88ac7SKuriakose Kuruvilla 		if ((cp->cp_eax & XFEATURE_LEGACY_FP) == 0 ||
18377af88ac7SKuriakose Kuruvilla 		    (cp->cp_eax & XFEATURE_SSE) == 0) {
18387af88ac7SKuriakose Kuruvilla 			cpuid_d_valid = B_FALSE;
18397af88ac7SKuriakose Kuruvilla 		}
18407af88ac7SKuriakose Kuruvilla 
18417af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_hw_features_low = cp->cp_eax;
18427af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_hw_features_high = cp->cp_edx;
18437af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_max_size = cp->cp_ecx;
18447af88ac7SKuriakose Kuruvilla 
18457af88ac7SKuriakose Kuruvilla 		/*
18467af88ac7SKuriakose Kuruvilla 		 * If the hw supports AVX, get the size and offset in the save
18477af88ac7SKuriakose Kuruvilla 		 * area for the ymm state.
18487af88ac7SKuriakose Kuruvilla 		 */
18497af88ac7SKuriakose Kuruvilla 		if (cpi->cpi_xsave.xsav_hw_features_low & XFEATURE_AVX) {
18507af88ac7SKuriakose Kuruvilla 			cp->cp_eax = 0xD;
18517af88ac7SKuriakose Kuruvilla 			cp->cp_ecx = 2;
18527af88ac7SKuriakose Kuruvilla 			cp->cp_edx = cp->cp_ebx = 0;
18537af88ac7SKuriakose Kuruvilla 
18547af88ac7SKuriakose Kuruvilla 			(void) __cpuid_insn(cp);
18557af88ac7SKuriakose Kuruvilla 
18567af88ac7SKuriakose Kuruvilla 			if (cp->cp_ebx != CPUID_LEAFD_2_YMM_OFFSET ||
18577af88ac7SKuriakose Kuruvilla 			    cp->cp_eax != CPUID_LEAFD_2_YMM_SIZE) {
18587af88ac7SKuriakose Kuruvilla 				cpuid_d_valid = B_FALSE;
18597af88ac7SKuriakose Kuruvilla 			}
18607af88ac7SKuriakose Kuruvilla 
18617af88ac7SKuriakose Kuruvilla 			cpi->cpi_xsave.ymm_size = cp->cp_eax;
18627af88ac7SKuriakose Kuruvilla 			cpi->cpi_xsave.ymm_offset = cp->cp_ebx;
18637af88ac7SKuriakose Kuruvilla 		}
18647af88ac7SKuriakose Kuruvilla 
18657af88ac7SKuriakose Kuruvilla 		if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) {
18667af88ac7SKuriakose Kuruvilla 			xsave_state_size = 0;
18677af88ac7SKuriakose Kuruvilla 		} else if (cpuid_d_valid) {
18687af88ac7SKuriakose Kuruvilla 			xsave_state_size = cpi->cpi_xsave.xsav_max_size;
18697af88ac7SKuriakose Kuruvilla 		} else {
18707af88ac7SKuriakose Kuruvilla 			/* Broken CPUID 0xD, probably in HVM */
18717af88ac7SKuriakose Kuruvilla 			cmn_err(CE_WARN, "cpu%d: CPUID.0xD returns invalid "
18727af88ac7SKuriakose Kuruvilla 			    "value: hw_low = %d, hw_high = %d, xsave_size = %d"
18737af88ac7SKuriakose Kuruvilla 			    ", ymm_size = %d, ymm_offset = %d\n",
18747af88ac7SKuriakose Kuruvilla 			    cpu->cpu_id, cpi->cpi_xsave.xsav_hw_features_low,
18757af88ac7SKuriakose Kuruvilla 			    cpi->cpi_xsave.xsav_hw_features_high,
18767af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.xsav_max_size,
18777af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.ymm_size,
18787af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.ymm_offset);
18797af88ac7SKuriakose Kuruvilla 
18807af88ac7SKuriakose Kuruvilla 			if (xsave_state_size != 0) {
18817af88ac7SKuriakose Kuruvilla 				/*
18827af88ac7SKuriakose Kuruvilla 				 * This must be a non-boot CPU. We cannot
18837af88ac7SKuriakose Kuruvilla 				 * continue, because boot cpu has already
18847af88ac7SKuriakose Kuruvilla 				 * enabled XSAVE.
18857af88ac7SKuriakose Kuruvilla 				 */
18867af88ac7SKuriakose Kuruvilla 				ASSERT(cpu->cpu_id != 0);
18877af88ac7SKuriakose Kuruvilla 				cmn_err(CE_PANIC, "cpu%d: we have already "
18887af88ac7SKuriakose Kuruvilla 				    "enabled XSAVE on boot cpu, cannot "
18897af88ac7SKuriakose Kuruvilla 				    "continue.", cpu->cpu_id);
18907af88ac7SKuriakose Kuruvilla 			} else {
18917af88ac7SKuriakose Kuruvilla 				/*
18927af88ac7SKuriakose Kuruvilla 				 * Must be from boot CPU, OK to disable XSAVE.
18937af88ac7SKuriakose Kuruvilla 				 */
18947af88ac7SKuriakose Kuruvilla 				ASSERT(cpu->cpu_id == 0);
18957af88ac7SKuriakose Kuruvilla 				remove_x86_feature(x86_featureset,
18967af88ac7SKuriakose Kuruvilla 				    X86FSET_XSAVE);
18977af88ac7SKuriakose Kuruvilla 				remove_x86_feature(x86_featureset, X86FSET_AVX);
18987af88ac7SKuriakose Kuruvilla 				CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_XSAVE;
18997af88ac7SKuriakose Kuruvilla 				CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_AVX;
19007af88ac7SKuriakose Kuruvilla 				xsave_force_disable = B_TRUE;
19017af88ac7SKuriakose Kuruvilla 			}
19027af88ac7SKuriakose Kuruvilla 		}
19037af88ac7SKuriakose Kuruvilla 	}
19047af88ac7SKuriakose Kuruvilla 
19057af88ac7SKuriakose Kuruvilla 
19067c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0)
19077c478bd9Sstevel@tonic-gate 		goto pass2_done;
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_xmaxeax - 0x80000000 + 1) > NMAX_CPI_EXTD)
19107c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_EXTD;
19117c478bd9Sstevel@tonic-gate 	/*
19127c478bd9Sstevel@tonic-gate 	 * Copy the extended properties, fixing them as we go.
19137c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
19147c478bd9Sstevel@tonic-gate 	 */
19157c478bd9Sstevel@tonic-gate 	iptr = (void *)cpi->cpi_brandstr;
19167c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_extd[2]; n < nmax; cp++, n++) {
19178949bcd6Sandrei 		cp->cp_eax = 0x80000000 + n;
19188949bcd6Sandrei 		(void) __cpuid_insn(cp);
1919ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, 0x80000000 + n, cp);
19207c478bd9Sstevel@tonic-gate 		switch (n) {
19217c478bd9Sstevel@tonic-gate 		case 2:
19227c478bd9Sstevel@tonic-gate 		case 3:
19237c478bd9Sstevel@tonic-gate 		case 4:
19247c478bd9Sstevel@tonic-gate 			/*
19257c478bd9Sstevel@tonic-gate 			 * Extract the brand string
19267c478bd9Sstevel@tonic-gate 			 */
19277c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_eax;
19287c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ebx;
19297c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ecx;
19307c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_edx;
19317c478bd9Sstevel@tonic-gate 			break;
19327c478bd9Sstevel@tonic-gate 		case 5:
19337c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
19347c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
19357c478bd9Sstevel@tonic-gate 				/*
19367c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
19377c478bd9Sstevel@tonic-gate 				 * parts to report the sizes of the
19387c478bd9Sstevel@tonic-gate 				 * TLB for large pages. Before then,
19397c478bd9Sstevel@tonic-gate 				 * we don't trust the data.
19407c478bd9Sstevel@tonic-gate 				 */
19417c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
19427c478bd9Sstevel@tonic-gate 				    (cpi->cpi_family == 6 &&
19437c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1))
19447c478bd9Sstevel@tonic-gate 					cp->cp_eax = 0;
19457c478bd9Sstevel@tonic-gate 				break;
19467c478bd9Sstevel@tonic-gate 			default:
19477c478bd9Sstevel@tonic-gate 				break;
19487c478bd9Sstevel@tonic-gate 			}
19497c478bd9Sstevel@tonic-gate 			break;
19507c478bd9Sstevel@tonic-gate 		case 6:
19517c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
19527c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
19537c478bd9Sstevel@tonic-gate 				/*
19547c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
19557c478bd9Sstevel@tonic-gate 				 * AMD parts with L2 TLB's.
19567c478bd9Sstevel@tonic-gate 				 * Before then, don't trust the data.
19577c478bd9Sstevel@tonic-gate 				 */
19587c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
19597c478bd9Sstevel@tonic-gate 				    cpi->cpi_family == 6 &&
19607c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1)
19617c478bd9Sstevel@tonic-gate 					cp->cp_eax = cp->cp_ebx = 0;
19627c478bd9Sstevel@tonic-gate 				/*
19637c478bd9Sstevel@tonic-gate 				 * AMD Duron rev A0 reports L2
19647c478bd9Sstevel@tonic-gate 				 * cache size incorrectly as 1K
19657c478bd9Sstevel@tonic-gate 				 * when it is really 64K
19667c478bd9Sstevel@tonic-gate 				 */
19677c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family == 6 &&
19687c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 3 &&
19697c478bd9Sstevel@tonic-gate 				    cpi->cpi_step == 0) {
19707c478bd9Sstevel@tonic-gate 					cp->cp_ecx &= 0xffff;
19717c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 0x400000;
19727c478bd9Sstevel@tonic-gate 				}
19737c478bd9Sstevel@tonic-gate 				break;
19747c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Cyrix:	/* VIA C3 */
19757c478bd9Sstevel@tonic-gate 				/*
19767c478bd9Sstevel@tonic-gate 				 * VIA C3 processors are a bit messed
19777c478bd9Sstevel@tonic-gate 				 * up w.r.t. encoding cache sizes in %ecx
19787c478bd9Sstevel@tonic-gate 				 */
19797c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family != 6)
19807c478bd9Sstevel@tonic-gate 					break;
19817c478bd9Sstevel@tonic-gate 				/*
19827c478bd9Sstevel@tonic-gate 				 * model 7 and 8 were incorrectly encoded
19837c478bd9Sstevel@tonic-gate 				 *
19847c478bd9Sstevel@tonic-gate 				 * xxx is model 8 really broken?
19857c478bd9Sstevel@tonic-gate 				 */
19867c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 7 ||
19877c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 8)
19887c478bd9Sstevel@tonic-gate 					cp->cp_ecx =
19897c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 31, 24) << 16 |
19907c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 23, 16) << 12 |
19917c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 15, 8) << 8 |
19927c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 7, 0);
19937c478bd9Sstevel@tonic-gate 				/*
19947c478bd9Sstevel@tonic-gate 				 * model 9 stepping 1 has wrong associativity
19957c478bd9Sstevel@tonic-gate 				 */
19967c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 9 && cpi->cpi_step == 1)
19977c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 8 << 12;
19987c478bd9Sstevel@tonic-gate 				break;
19997c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Intel:
20007c478bd9Sstevel@tonic-gate 				/*
20017c478bd9Sstevel@tonic-gate 				 * Extended L2 Cache features function.
20027c478bd9Sstevel@tonic-gate 				 * First appeared on Prescott.
20037c478bd9Sstevel@tonic-gate 				 */
20047c478bd9Sstevel@tonic-gate 			default:
20057c478bd9Sstevel@tonic-gate 				break;
20067c478bd9Sstevel@tonic-gate 			}
20077c478bd9Sstevel@tonic-gate 			break;
20087c478bd9Sstevel@tonic-gate 		default:
20097c478bd9Sstevel@tonic-gate 			break;
20107c478bd9Sstevel@tonic-gate 		}
20117c478bd9Sstevel@tonic-gate 	}
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate pass2_done:
20147c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 2;
20157c478bd9Sstevel@tonic-gate }
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate static const char *
20187c478bd9Sstevel@tonic-gate intel_cpubrand(const struct cpuid_info *cpi)
20197c478bd9Sstevel@tonic-gate {
20207c478bd9Sstevel@tonic-gate 	int i;
20217c478bd9Sstevel@tonic-gate 
20227417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
20237c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
20247c478bd9Sstevel@tonic-gate 		return ("i486");
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
20277c478bd9Sstevel@tonic-gate 	case 5:
20287c478bd9Sstevel@tonic-gate 		return ("Intel Pentium(r)");
20297c478bd9Sstevel@tonic-gate 	case 6:
20307c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
20317c478bd9Sstevel@tonic-gate 			uint_t celeron, xeon;
20328949bcd6Sandrei 			const struct cpuid_regs *cp;
20337c478bd9Sstevel@tonic-gate 		case 0:
20347c478bd9Sstevel@tonic-gate 		case 1:
20357c478bd9Sstevel@tonic-gate 		case 2:
20367c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) Pro");
20377c478bd9Sstevel@tonic-gate 		case 3:
20387c478bd9Sstevel@tonic-gate 		case 4:
20397c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) II");
20407c478bd9Sstevel@tonic-gate 		case 6:
20417c478bd9Sstevel@tonic-gate 			return ("Intel Celeron(r)");
20427c478bd9Sstevel@tonic-gate 		case 5:
20437c478bd9Sstevel@tonic-gate 		case 7:
20447c478bd9Sstevel@tonic-gate 			celeron = xeon = 0;
20457c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_std[2];	/* cache info */
20467c478bd9Sstevel@tonic-gate 
204763d3f7dfSkk208521 			for (i = 1; i < 4; i++) {
20487c478bd9Sstevel@tonic-gate 				uint_t tmp;
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_eax >> (8 * i)) & 0xff;
20517c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
20527c478bd9Sstevel@tonic-gate 					celeron++;
20537c478bd9Sstevel@tonic-gate 				if (tmp >= 0x44 && tmp <= 0x45)
20547c478bd9Sstevel@tonic-gate 					xeon++;
20557c478bd9Sstevel@tonic-gate 			}
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 			for (i = 0; i < 2; i++) {
20587c478bd9Sstevel@tonic-gate 				uint_t tmp;
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ebx >> (8 * i)) & 0xff;
20617c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
20627c478bd9Sstevel@tonic-gate 					celeron++;
20637c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
20647c478bd9Sstevel@tonic-gate 					xeon++;
20657c478bd9Sstevel@tonic-gate 			}
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
20687c478bd9Sstevel@tonic-gate 				uint_t tmp;
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ecx >> (8 * i)) & 0xff;
20717c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
20727c478bd9Sstevel@tonic-gate 					celeron++;
20737c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
20747c478bd9Sstevel@tonic-gate 					xeon++;
20757c478bd9Sstevel@tonic-gate 			}
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
20787c478bd9Sstevel@tonic-gate 				uint_t tmp;
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_edx >> (8 * i)) & 0xff;
20817c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
20827c478bd9Sstevel@tonic-gate 					celeron++;
20837c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
20847c478bd9Sstevel@tonic-gate 					xeon++;
20857c478bd9Sstevel@tonic-gate 			}
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 			if (celeron)
20887c478bd9Sstevel@tonic-gate 				return ("Intel Celeron(r)");
20897c478bd9Sstevel@tonic-gate 			if (xeon)
20907c478bd9Sstevel@tonic-gate 				return (cpi->cpi_model == 5 ?
20917c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) II Xeon(tm)" :
20927c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) III Xeon(tm)");
20937c478bd9Sstevel@tonic-gate 			return (cpi->cpi_model == 5 ?
20947c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) II or Pentium(r) II Xeon(tm)" :
20957c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) III or Pentium(r) III Xeon(tm)");
20967c478bd9Sstevel@tonic-gate 		default:
20977c478bd9Sstevel@tonic-gate 			break;
20987c478bd9Sstevel@tonic-gate 		}
20997c478bd9Sstevel@tonic-gate 	default:
21007c478bd9Sstevel@tonic-gate 		break;
21017c478bd9Sstevel@tonic-gate 	}
21027c478bd9Sstevel@tonic-gate 
21035ff02082Sdmick 	/* BrandID is present if the field is nonzero */
21045ff02082Sdmick 	if (cpi->cpi_brandid != 0) {
21057c478bd9Sstevel@tonic-gate 		static const struct {
21067c478bd9Sstevel@tonic-gate 			uint_t bt_bid;
21077c478bd9Sstevel@tonic-gate 			const char *bt_str;
21087c478bd9Sstevel@tonic-gate 		} brand_tbl[] = {
21097c478bd9Sstevel@tonic-gate 			{ 0x1,	"Intel(r) Celeron(r)" },
21107c478bd9Sstevel@tonic-gate 			{ 0x2,	"Intel(r) Pentium(r) III" },
21117c478bd9Sstevel@tonic-gate 			{ 0x3,	"Intel(r) Pentium(r) III Xeon(tm)" },
21127c478bd9Sstevel@tonic-gate 			{ 0x4,	"Intel(r) Pentium(r) III" },
21137c478bd9Sstevel@tonic-gate 			{ 0x6,	"Mobile Intel(r) Pentium(r) III" },
21147c478bd9Sstevel@tonic-gate 			{ 0x7,	"Mobile Intel(r) Celeron(r)" },
21157c478bd9Sstevel@tonic-gate 			{ 0x8,	"Intel(r) Pentium(r) 4" },
21167c478bd9Sstevel@tonic-gate 			{ 0x9,	"Intel(r) Pentium(r) 4" },
21177c478bd9Sstevel@tonic-gate 			{ 0xa,	"Intel(r) Celeron(r)" },
21187c478bd9Sstevel@tonic-gate 			{ 0xb,	"Intel(r) Xeon(tm)" },
21197c478bd9Sstevel@tonic-gate 			{ 0xc,	"Intel(r) Xeon(tm) MP" },
21207c478bd9Sstevel@tonic-gate 			{ 0xe,	"Mobile Intel(r) Pentium(r) 4" },
21215ff02082Sdmick 			{ 0xf,	"Mobile Intel(r) Celeron(r)" },
21225ff02082Sdmick 			{ 0x11, "Mobile Genuine Intel(r)" },
21235ff02082Sdmick 			{ 0x12, "Intel(r) Celeron(r) M" },
21245ff02082Sdmick 			{ 0x13, "Mobile Intel(r) Celeron(r)" },
21255ff02082Sdmick 			{ 0x14, "Intel(r) Celeron(r)" },
21265ff02082Sdmick 			{ 0x15, "Mobile Genuine Intel(r)" },
21275ff02082Sdmick 			{ 0x16,	"Intel(r) Pentium(r) M" },
21285ff02082Sdmick 			{ 0x17, "Mobile Intel(r) Celeron(r)" }
21297c478bd9Sstevel@tonic-gate 		};
21307c478bd9Sstevel@tonic-gate 		uint_t btblmax = sizeof (brand_tbl) / sizeof (brand_tbl[0]);
21317c478bd9Sstevel@tonic-gate 		uint_t sgn;
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 		sgn = (cpi->cpi_family << 8) |
21347c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model << 4) | cpi->cpi_step;
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 		for (i = 0; i < btblmax; i++)
21377c478bd9Sstevel@tonic-gate 			if (brand_tbl[i].bt_bid == cpi->cpi_brandid)
21387c478bd9Sstevel@tonic-gate 				break;
21397c478bd9Sstevel@tonic-gate 		if (i < btblmax) {
21407c478bd9Sstevel@tonic-gate 			if (sgn == 0x6b1 && cpi->cpi_brandid == 3)
21417c478bd9Sstevel@tonic-gate 				return ("Intel(r) Celeron(r)");
21427c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xb)
21437c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm) MP");
21447c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xe)
21457c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm)");
21467c478bd9Sstevel@tonic-gate 			return (brand_tbl[i].bt_str);
21477c478bd9Sstevel@tonic-gate 		}
21487c478bd9Sstevel@tonic-gate 	}
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 	return (NULL);
21517c478bd9Sstevel@tonic-gate }
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate static const char *
21547c478bd9Sstevel@tonic-gate amd_cpubrand(const struct cpuid_info *cpi)
21557c478bd9Sstevel@tonic-gate {
21567417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
21577c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
21587c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
21617c478bd9Sstevel@tonic-gate 	case 5:
21627c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
21637c478bd9Sstevel@tonic-gate 		case 0:
21647c478bd9Sstevel@tonic-gate 		case 1:
21657c478bd9Sstevel@tonic-gate 		case 2:
21667c478bd9Sstevel@tonic-gate 		case 3:
21677c478bd9Sstevel@tonic-gate 		case 4:
21687c478bd9Sstevel@tonic-gate 		case 5:
21697c478bd9Sstevel@tonic-gate 			return ("AMD-K5(r)");
21707c478bd9Sstevel@tonic-gate 		case 6:
21717c478bd9Sstevel@tonic-gate 		case 7:
21727c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)");
21737c478bd9Sstevel@tonic-gate 		case 8:
21747c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-2");
21757c478bd9Sstevel@tonic-gate 		case 9:
21767c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-III");
21777c478bd9Sstevel@tonic-gate 		default:
21787c478bd9Sstevel@tonic-gate 			return ("AMD (family 5)");
21797c478bd9Sstevel@tonic-gate 		}
21807c478bd9Sstevel@tonic-gate 	case 6:
21817c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
21827c478bd9Sstevel@tonic-gate 		case 1:
21837c478bd9Sstevel@tonic-gate 			return ("AMD-K7(tm)");
21847c478bd9Sstevel@tonic-gate 		case 0:
21857c478bd9Sstevel@tonic-gate 		case 2:
21867c478bd9Sstevel@tonic-gate 		case 4:
21877c478bd9Sstevel@tonic-gate 			return ("AMD Athlon(tm)");
21887c478bd9Sstevel@tonic-gate 		case 3:
21897c478bd9Sstevel@tonic-gate 		case 7:
21907c478bd9Sstevel@tonic-gate 			return ("AMD Duron(tm)");
21917c478bd9Sstevel@tonic-gate 		case 6:
21927c478bd9Sstevel@tonic-gate 		case 8:
21937c478bd9Sstevel@tonic-gate 		case 10:
21947c478bd9Sstevel@tonic-gate 			/*
21957c478bd9Sstevel@tonic-gate 			 * Use the L2 cache size to distinguish
21967c478bd9Sstevel@tonic-gate 			 */
21977c478bd9Sstevel@tonic-gate 			return ((cpi->cpi_extd[6].cp_ecx >> 16) >= 256 ?
21987c478bd9Sstevel@tonic-gate 			    "AMD Athlon(tm)" : "AMD Duron(tm)");
21997c478bd9Sstevel@tonic-gate 		default:
22007c478bd9Sstevel@tonic-gate 			return ("AMD (family 6)");
22017c478bd9Sstevel@tonic-gate 		}
22027c478bd9Sstevel@tonic-gate 	default:
22037c478bd9Sstevel@tonic-gate 		break;
22047c478bd9Sstevel@tonic-gate 	}
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	if (cpi->cpi_family == 0xf && cpi->cpi_model == 5 &&
22077c478bd9Sstevel@tonic-gate 	    cpi->cpi_brandid != 0) {
22087c478bd9Sstevel@tonic-gate 		switch (BITX(cpi->cpi_brandid, 7, 5)) {
22097c478bd9Sstevel@tonic-gate 		case 3:
22107c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) UP 1xx");
22117c478bd9Sstevel@tonic-gate 		case 4:
22127c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) DP 2xx");
22137c478bd9Sstevel@tonic-gate 		case 5:
22147c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) MP 8xx");
22157c478bd9Sstevel@tonic-gate 		default:
22167c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm)");
22177c478bd9Sstevel@tonic-gate 		}
22187c478bd9Sstevel@tonic-gate 	}
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	return (NULL);
22217c478bd9Sstevel@tonic-gate }
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate static const char *
22247c478bd9Sstevel@tonic-gate cyrix_cpubrand(struct cpuid_info *cpi, uint_t type)
22257c478bd9Sstevel@tonic-gate {
22267417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
22277c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5 ||
22287c478bd9Sstevel@tonic-gate 	    type == X86_TYPE_CYRIX_486)
22297c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 	switch (type) {
22327c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86:
22337c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86");
22347c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86L:
22357c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86L");
22367c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86MX:
22377c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86MX");
22387c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_GXm:
22397c478bd9Sstevel@tonic-gate 		return ("Cyrix GXm");
22407c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MediaGX:
22417c478bd9Sstevel@tonic-gate 		return ("Cyrix MediaGX");
22427c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MII:
22437c478bd9Sstevel@tonic-gate 		return ("Cyrix M2");
22447c478bd9Sstevel@tonic-gate 	case X86_TYPE_VIA_CYRIX_III:
22457c478bd9Sstevel@tonic-gate 		return ("VIA Cyrix M3");
22467c478bd9Sstevel@tonic-gate 	default:
22477c478bd9Sstevel@tonic-gate 		/*
22487c478bd9Sstevel@tonic-gate 		 * Have another wild guess ..
22497c478bd9Sstevel@tonic-gate 		 */
22507c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 4 && cpi->cpi_model == 9)
22517c478bd9Sstevel@tonic-gate 			return ("Cyrix 5x86");
22527c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_family == 5) {
22537c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
22547c478bd9Sstevel@tonic-gate 			case 2:
22557c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86");	/* Cyrix M1 */
22567c478bd9Sstevel@tonic-gate 			case 4:
22577c478bd9Sstevel@tonic-gate 				return ("Cyrix MediaGX");
22587c478bd9Sstevel@tonic-gate 			default:
22597c478bd9Sstevel@tonic-gate 				break;
22607c478bd9Sstevel@tonic-gate 			}
22617c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family == 6) {
22627c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
22637c478bd9Sstevel@tonic-gate 			case 0:
22647c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86MX"); /* Cyrix M2? */
22657c478bd9Sstevel@tonic-gate 			case 5:
22667c478bd9Sstevel@tonic-gate 			case 6:
22677c478bd9Sstevel@tonic-gate 			case 7:
22687c478bd9Sstevel@tonic-gate 			case 8:
22697c478bd9Sstevel@tonic-gate 			case 9:
22707c478bd9Sstevel@tonic-gate 				return ("VIA C3");
22717c478bd9Sstevel@tonic-gate 			default:
22727c478bd9Sstevel@tonic-gate 				break;
22737c478bd9Sstevel@tonic-gate 			}
22747c478bd9Sstevel@tonic-gate 		}
22757c478bd9Sstevel@tonic-gate 		break;
22767c478bd9Sstevel@tonic-gate 	}
22777c478bd9Sstevel@tonic-gate 	return (NULL);
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate /*
22817c478bd9Sstevel@tonic-gate  * This only gets called in the case that the CPU extended
22827c478bd9Sstevel@tonic-gate  * feature brand string (0x80000002, 0x80000003, 0x80000004)
22837c478bd9Sstevel@tonic-gate  * aren't available, or contain null bytes for some reason.
22847c478bd9Sstevel@tonic-gate  */
22857c478bd9Sstevel@tonic-gate static void
22867c478bd9Sstevel@tonic-gate fabricate_brandstr(struct cpuid_info *cpi)
22877c478bd9Sstevel@tonic-gate {
22887c478bd9Sstevel@tonic-gate 	const char *brand = NULL;
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
22917c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
22927c478bd9Sstevel@tonic-gate 		brand = intel_cpubrand(cpi);
22937c478bd9Sstevel@tonic-gate 		break;
22947c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
22957c478bd9Sstevel@tonic-gate 		brand = amd_cpubrand(cpi);
22967c478bd9Sstevel@tonic-gate 		break;
22977c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
22987c478bd9Sstevel@tonic-gate 		brand = cyrix_cpubrand(cpi, x86_type);
22997c478bd9Sstevel@tonic-gate 		break;
23007c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NexGen:
23017c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
23027c478bd9Sstevel@tonic-gate 			brand = "NexGen Nx586";
23037c478bd9Sstevel@tonic-gate 		break;
23047c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
23057c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
23067c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
23077c478bd9Sstevel@tonic-gate 			case 4:
23087c478bd9Sstevel@tonic-gate 				brand = "Centaur C6";
23097c478bd9Sstevel@tonic-gate 				break;
23107c478bd9Sstevel@tonic-gate 			case 8:
23117c478bd9Sstevel@tonic-gate 				brand = "Centaur C2";
23127c478bd9Sstevel@tonic-gate 				break;
23137c478bd9Sstevel@tonic-gate 			case 9:
23147c478bd9Sstevel@tonic-gate 				brand = "Centaur C3";
23157c478bd9Sstevel@tonic-gate 				break;
23167c478bd9Sstevel@tonic-gate 			default:
23177c478bd9Sstevel@tonic-gate 				break;
23187c478bd9Sstevel@tonic-gate 			}
23197c478bd9Sstevel@tonic-gate 		break;
23207c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Rise:
23217c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 &&
23227c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model == 0 || cpi->cpi_model == 2))
23237c478bd9Sstevel@tonic-gate 			brand = "Rise mP6";
23247c478bd9Sstevel@tonic-gate 		break;
23257c478bd9Sstevel@tonic-gate 	case X86_VENDOR_SiS:
23267c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
23277c478bd9Sstevel@tonic-gate 			brand = "SiS 55x";
23287c478bd9Sstevel@tonic-gate 		break;
23297c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
23307c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4)
23317c478bd9Sstevel@tonic-gate 			brand = "Transmeta Crusoe TM3x00 or TM5x00";
23327c478bd9Sstevel@tonic-gate 		break;
23337c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NSC:
23347c478bd9Sstevel@tonic-gate 	case X86_VENDOR_UMC:
23357c478bd9Sstevel@tonic-gate 	default:
23367c478bd9Sstevel@tonic-gate 		break;
23377c478bd9Sstevel@tonic-gate 	}
23387c478bd9Sstevel@tonic-gate 	if (brand) {
23397c478bd9Sstevel@tonic-gate 		(void) strcpy((char *)cpi->cpi_brandstr, brand);
23407c478bd9Sstevel@tonic-gate 		return;
23417c478bd9Sstevel@tonic-gate 	}
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	/*
23447c478bd9Sstevel@tonic-gate 	 * If all else fails ...
23457c478bd9Sstevel@tonic-gate 	 */
23467c478bd9Sstevel@tonic-gate 	(void) snprintf(cpi->cpi_brandstr, sizeof (cpi->cpi_brandstr),
23477c478bd9Sstevel@tonic-gate 	    "%s %d.%d.%d", cpi->cpi_vendorstr, cpi->cpi_family,
23487c478bd9Sstevel@tonic-gate 	    cpi->cpi_model, cpi->cpi_step);
23497c478bd9Sstevel@tonic-gate }
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate /*
23527c478bd9Sstevel@tonic-gate  * This routine is called just after kernel memory allocation
23537c478bd9Sstevel@tonic-gate  * becomes available on cpu0, and as part of mp_startup() on
23547c478bd9Sstevel@tonic-gate  * the other cpus.
23557c478bd9Sstevel@tonic-gate  *
2356d129bde2Sesaxe  * Fixup the brand string, and collect any information from cpuid
2357d129bde2Sesaxe  * that requires dynamicically allocated storage to represent.
23587c478bd9Sstevel@tonic-gate  */
23597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
23607c478bd9Sstevel@tonic-gate void
23617c478bd9Sstevel@tonic-gate cpuid_pass3(cpu_t *cpu)
23627c478bd9Sstevel@tonic-gate {
2363d129bde2Sesaxe 	int	i, max, shft, level, size;
2364d129bde2Sesaxe 	struct cpuid_regs regs;
2365d129bde2Sesaxe 	struct cpuid_regs *cp;
23667c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 2);
23697c478bd9Sstevel@tonic-gate 
2370d129bde2Sesaxe 	/*
2371d129bde2Sesaxe 	 * Function 4: Deterministic cache parameters
2372d129bde2Sesaxe 	 *
2373d129bde2Sesaxe 	 * Take this opportunity to detect the number of threads
2374d129bde2Sesaxe 	 * sharing the last level cache, and construct a corresponding
2375d129bde2Sesaxe 	 * cache id. The respective cpuid_info members are initialized
2376d129bde2Sesaxe 	 * to the default case of "no last level cache sharing".
2377d129bde2Sesaxe 	 */
2378d129bde2Sesaxe 	cpi->cpi_ncpu_shr_last_cache = 1;
2379d129bde2Sesaxe 	cpi->cpi_last_lvl_cacheid = cpu->cpu_id;
2380d129bde2Sesaxe 
2381d129bde2Sesaxe 	if (cpi->cpi_maxeax >= 4 && cpi->cpi_vendor == X86_VENDOR_Intel) {
2382d129bde2Sesaxe 
2383d129bde2Sesaxe 		/*
2384d129bde2Sesaxe 		 * Find the # of elements (size) returned by fn 4, and along
2385d129bde2Sesaxe 		 * the way detect last level cache sharing details.
2386d129bde2Sesaxe 		 */
2387d129bde2Sesaxe 		bzero(&regs, sizeof (regs));
2388d129bde2Sesaxe 		cp = &regs;
2389d129bde2Sesaxe 		for (i = 0, max = 0; i < CPI_FN4_ECX_MAX; i++) {
2390d129bde2Sesaxe 			cp->cp_eax = 4;
2391d129bde2Sesaxe 			cp->cp_ecx = i;
2392d129bde2Sesaxe 
2393d129bde2Sesaxe 			(void) __cpuid_insn(cp);
2394d129bde2Sesaxe 
2395d129bde2Sesaxe 			if (CPI_CACHE_TYPE(cp) == 0)
2396d129bde2Sesaxe 				break;
2397d129bde2Sesaxe 			level = CPI_CACHE_LVL(cp);
2398d129bde2Sesaxe 			if (level > max) {
2399d129bde2Sesaxe 				max = level;
2400d129bde2Sesaxe 				cpi->cpi_ncpu_shr_last_cache =
2401d129bde2Sesaxe 				    CPI_NTHR_SHR_CACHE(cp) + 1;
2402d129bde2Sesaxe 			}
2403d129bde2Sesaxe 		}
2404d129bde2Sesaxe 		cpi->cpi_std_4_size = size = i;
2405d129bde2Sesaxe 
2406d129bde2Sesaxe 		/*
2407d129bde2Sesaxe 		 * Allocate the cpi_std_4 array. The first element
2408d129bde2Sesaxe 		 * references the regs for fn 4, %ecx == 0, which
2409d129bde2Sesaxe 		 * cpuid_pass2() stashed in cpi->cpi_std[4].
2410d129bde2Sesaxe 		 */
2411d129bde2Sesaxe 		if (size > 0) {
2412d129bde2Sesaxe 			cpi->cpi_std_4 =
2413d129bde2Sesaxe 			    kmem_alloc(size * sizeof (cp), KM_SLEEP);
2414d129bde2Sesaxe 			cpi->cpi_std_4[0] = &cpi->cpi_std[4];
2415d129bde2Sesaxe 
2416d129bde2Sesaxe 			/*
2417d129bde2Sesaxe 			 * Allocate storage to hold the additional regs
2418d129bde2Sesaxe 			 * for function 4, %ecx == 1 .. cpi_std_4_size.
2419d129bde2Sesaxe 			 *
2420d129bde2Sesaxe 			 * The regs for fn 4, %ecx == 0 has already
2421d129bde2Sesaxe 			 * been allocated as indicated above.
2422d129bde2Sesaxe 			 */
2423d129bde2Sesaxe 			for (i = 1; i < size; i++) {
2424d129bde2Sesaxe 				cp = cpi->cpi_std_4[i] =
2425d129bde2Sesaxe 				    kmem_zalloc(sizeof (regs), KM_SLEEP);
2426d129bde2Sesaxe 				cp->cp_eax = 4;
2427d129bde2Sesaxe 				cp->cp_ecx = i;
2428d129bde2Sesaxe 
2429d129bde2Sesaxe 				(void) __cpuid_insn(cp);
2430d129bde2Sesaxe 			}
2431d129bde2Sesaxe 		}
2432d129bde2Sesaxe 		/*
2433d129bde2Sesaxe 		 * Determine the number of bits needed to represent
2434d129bde2Sesaxe 		 * the number of CPUs sharing the last level cache.
2435d129bde2Sesaxe 		 *
2436d129bde2Sesaxe 		 * Shift off that number of bits from the APIC id to
2437d129bde2Sesaxe 		 * derive the cache id.
2438d129bde2Sesaxe 		 */
2439d129bde2Sesaxe 		shft = 0;
2440d129bde2Sesaxe 		for (i = 1; i < cpi->cpi_ncpu_shr_last_cache; i <<= 1)
2441d129bde2Sesaxe 			shft++;
2442b6917abeSmishra 		cpi->cpi_last_lvl_cacheid = cpi->cpi_apicid >> shft;
2443d129bde2Sesaxe 	}
2444d129bde2Sesaxe 
2445d129bde2Sesaxe 	/*
2446d129bde2Sesaxe 	 * Now fixup the brand string
2447d129bde2Sesaxe 	 */
24487c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0) {
24497c478bd9Sstevel@tonic-gate 		fabricate_brandstr(cpi);
2450d129bde2Sesaxe 	} else {
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 		/*
24537c478bd9Sstevel@tonic-gate 		 * If we successfully extracted a brand string from the cpuid
24547c478bd9Sstevel@tonic-gate 		 * instruction, clean it up by removing leading spaces and
24557c478bd9Sstevel@tonic-gate 		 * similar junk.
24567c478bd9Sstevel@tonic-gate 		 */
24577c478bd9Sstevel@tonic-gate 		if (cpi->cpi_brandstr[0]) {
24587c478bd9Sstevel@tonic-gate 			size_t maxlen = sizeof (cpi->cpi_brandstr);
24597c478bd9Sstevel@tonic-gate 			char *src, *dst;
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 			dst = src = (char *)cpi->cpi_brandstr;
24627c478bd9Sstevel@tonic-gate 			src[maxlen - 1] = '\0';
24637c478bd9Sstevel@tonic-gate 			/*
24647c478bd9Sstevel@tonic-gate 			 * strip leading spaces
24657c478bd9Sstevel@tonic-gate 			 */
24667c478bd9Sstevel@tonic-gate 			while (*src == ' ')
24677c478bd9Sstevel@tonic-gate 				src++;
24687c478bd9Sstevel@tonic-gate 			/*
24697c478bd9Sstevel@tonic-gate 			 * Remove any 'Genuine' or "Authentic" prefixes
24707c478bd9Sstevel@tonic-gate 			 */
24717c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Genuine ", 8) == 0)
24727c478bd9Sstevel@tonic-gate 				src += 8;
24737c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Authentic ", 10) == 0)
24747c478bd9Sstevel@tonic-gate 				src += 10;
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 			/*
24777c478bd9Sstevel@tonic-gate 			 * Now do an in-place copy.
24787c478bd9Sstevel@tonic-gate 			 * Map (R) to (r) and (TM) to (tm).
24797c478bd9Sstevel@tonic-gate 			 * The era of teletypes is long gone, and there's
24807c478bd9Sstevel@tonic-gate 			 * -really- no need to shout.
24817c478bd9Sstevel@tonic-gate 			 */
24827c478bd9Sstevel@tonic-gate 			while (*src != '\0') {
24837c478bd9Sstevel@tonic-gate 				if (src[0] == '(') {
24847c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "R)", 2) == 0) {
24857c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(r)", 3);
24867c478bd9Sstevel@tonic-gate 						src += 3;
24877c478bd9Sstevel@tonic-gate 						dst += 3;
24887c478bd9Sstevel@tonic-gate 						continue;
24897c478bd9Sstevel@tonic-gate 					}
24907c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "TM)", 3) == 0) {
24917c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(tm)", 4);
24927c478bd9Sstevel@tonic-gate 						src += 4;
24937c478bd9Sstevel@tonic-gate 						dst += 4;
24947c478bd9Sstevel@tonic-gate 						continue;
24957c478bd9Sstevel@tonic-gate 					}
24967c478bd9Sstevel@tonic-gate 				}
24977c478bd9Sstevel@tonic-gate 				*dst++ = *src++;
24987c478bd9Sstevel@tonic-gate 			}
24997c478bd9Sstevel@tonic-gate 			*dst = '\0';
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 			/*
25027c478bd9Sstevel@tonic-gate 			 * Finally, remove any trailing spaces
25037c478bd9Sstevel@tonic-gate 			 */
25047c478bd9Sstevel@tonic-gate 			while (--dst > cpi->cpi_brandstr)
25057c478bd9Sstevel@tonic-gate 				if (*dst == ' ')
25067c478bd9Sstevel@tonic-gate 					*dst = '\0';
25077c478bd9Sstevel@tonic-gate 				else
25087c478bd9Sstevel@tonic-gate 					break;
25097c478bd9Sstevel@tonic-gate 		} else
25107c478bd9Sstevel@tonic-gate 			fabricate_brandstr(cpi);
2511d129bde2Sesaxe 	}
25127c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 3;
25137c478bd9Sstevel@tonic-gate }
25147c478bd9Sstevel@tonic-gate 
25157c478bd9Sstevel@tonic-gate /*
25167c478bd9Sstevel@tonic-gate  * This routine is called out of bind_hwcap() much later in the life
25177c478bd9Sstevel@tonic-gate  * of the kernel (post_startup()).  The job of this routine is to resolve
25187c478bd9Sstevel@tonic-gate  * the hardware feature support and kernel support for those features into
25197c478bd9Sstevel@tonic-gate  * what we're actually going to tell applications via the aux vector.
25207c478bd9Sstevel@tonic-gate  */
25217c478bd9Sstevel@tonic-gate uint_t
25227c478bd9Sstevel@tonic-gate cpuid_pass4(cpu_t *cpu)
25237c478bd9Sstevel@tonic-gate {
25247c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
25257c478bd9Sstevel@tonic-gate 	uint_t hwcap_flags = 0;
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
25287c478bd9Sstevel@tonic-gate 		cpu = CPU;
25297c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
25307c478bd9Sstevel@tonic-gate 
25317c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 3);
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax >= 1) {
25347c478bd9Sstevel@tonic-gate 		uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES];
25357c478bd9Sstevel@tonic-gate 		uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES];
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_EDX(cpi);
25387c478bd9Sstevel@tonic-gate 		*ecx = CPI_FEATURES_ECX(cpi);
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 		/*
25417c478bd9Sstevel@tonic-gate 		 * [these require explicit kernel support]
25427c478bd9Sstevel@tonic-gate 		 */
25437417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SEP))
25447c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SEP;
25457c478bd9Sstevel@tonic-gate 
25467417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE))
25477c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE);
25487417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE2))
25497c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SSE2;
25507c478bd9Sstevel@tonic-gate 
25517417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_HTT))
25527c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_HTT;
25537c478bd9Sstevel@tonic-gate 
25547417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE3))
25557c478bd9Sstevel@tonic-gate 			*ecx &= ~CPUID_INTC_ECX_SSE3;
25567c478bd9Sstevel@tonic-gate 
25577417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSSE3))
2558d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSSE3;
25597417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1))
2560d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSE4_1;
25617417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2))
2562d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSE4_2;
25637417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_AES))
2564a50a8b93SKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_AES;
25657417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ))
25667417cfdeSKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_PCLMULQDQ;
25677af88ac7SKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_XSAVE))
25687af88ac7SKuriakose Kuruvilla 			*ecx &= ~(CPUID_INTC_ECX_XSAVE |
25697af88ac7SKuriakose Kuruvilla 			    CPUID_INTC_ECX_OSXSAVE);
25707af88ac7SKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_AVX))
25717af88ac7SKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_AVX;
2572d0f8ff6eSkk208521 
25737c478bd9Sstevel@tonic-gate 		/*
25747c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond x87 fp context]
25757c478bd9Sstevel@tonic-gate 		 */
25767c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
25777c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FPU | CPUID_INTC_EDX_MMX);
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate 		/*
25807c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to things that we
25817c478bd9Sstevel@tonic-gate 		 * think userland will care about.
25827c478bd9Sstevel@tonic-gate 		 */
25837c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SEP)
25847c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SEP;
25857c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE)
25867c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FXSR | AV_386_SSE;
25877c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE2)
25887c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE2;
25897c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_SSE3)
25907c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE3;
2591d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSSE3)
2592d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSSE3;
2593d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSE4_1)
2594d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSE4_1;
2595d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSE4_2)
2596d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSE4_2;
25975087e485SKrishnendu Sadhukhan - Sun Microsystems 		if (*ecx & CPUID_INTC_ECX_MOVBE)
25985087e485SKrishnendu Sadhukhan - Sun Microsystems 			hwcap_flags |= AV_386_MOVBE;
2599a50a8b93SKuriakose Kuruvilla 		if (*ecx & CPUID_INTC_ECX_AES)
2600a50a8b93SKuriakose Kuruvilla 			hwcap_flags |= AV_386_AES;
2601a50a8b93SKuriakose Kuruvilla 		if (*ecx & CPUID_INTC_ECX_PCLMULQDQ)
2602a50a8b93SKuriakose Kuruvilla 			hwcap_flags |= AV_386_PCLMULQDQ;
26037af88ac7SKuriakose Kuruvilla 		if ((*ecx & CPUID_INTC_ECX_XSAVE) &&
2604f3390f39SRobert Mustacchi 		    (*ecx & CPUID_INTC_ECX_OSXSAVE)) {
26057af88ac7SKuriakose Kuruvilla 			hwcap_flags |= AV_386_XSAVE;
2606f3390f39SRobert Mustacchi 
2607f3390f39SRobert Mustacchi 			if (*ecx & CPUID_INTC_ECX_AVX)
2608f3390f39SRobert Mustacchi 				hwcap_flags |= AV_386_AVX;
2609f3390f39SRobert Mustacchi 		}
2610faa20166SBryan Cantrill 		if (*ecx & CPUID_INTC_ECX_VMX)
2611faa20166SBryan Cantrill 			hwcap_flags |= AV_386_VMX;
2612f8801251Skk208521 		if (*ecx & CPUID_INTC_ECX_POPCNT)
2613f8801251Skk208521 			hwcap_flags |= AV_386_POPCNT;
26147c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_FPU)
26157c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FPU;
26167c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_MMX)
26177c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_MMX;
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_TSC)
26207c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_TSC;
26217c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CX8)
26227c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX8;
26237c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CMOV)
26247c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CMOV;
26257c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_CX16)
26267c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX16;
26277c478bd9Sstevel@tonic-gate 	}
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000001)
26307c478bd9Sstevel@tonic-gate 		goto pass4_done;
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
26338949bcd6Sandrei 		struct cpuid_regs cp;
2634ae115bc7Smrj 		uint32_t *edx, *ecx;
26357c478bd9Sstevel@tonic-gate 
2636ae115bc7Smrj 	case X86_VENDOR_Intel:
2637ae115bc7Smrj 		/*
2638ae115bc7Smrj 		 * Seems like Intel duplicated what we necessary
2639ae115bc7Smrj 		 * here to make the initial crop of 64-bit OS's work.
2640ae115bc7Smrj 		 * Hopefully, those are the only "extended" bits
2641ae115bc7Smrj 		 * they'll add.
2642ae115bc7Smrj 		 */
2643ae115bc7Smrj 		/*FALLTHROUGH*/
2644ae115bc7Smrj 
26457c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
26467c478bd9Sstevel@tonic-gate 		edx = &cpi->cpi_support[AMD_EDX_FEATURES];
2647ae115bc7Smrj 		ecx = &cpi->cpi_support[AMD_ECX_FEATURES];
26487c478bd9Sstevel@tonic-gate 
26497c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_XTD_EDX(cpi);
2650ae115bc7Smrj 		*ecx = CPI_FEATURES_XTD_ECX(cpi);
2651ae115bc7Smrj 
2652ae115bc7Smrj 		/*
2653ae115bc7Smrj 		 * [these features require explicit kernel support]
2654ae115bc7Smrj 		 */
2655ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2656ae115bc7Smrj 		case X86_VENDOR_Intel:
26577417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2658d36ea5d8Ssudheer 				*edx &= ~CPUID_AMD_EDX_TSCP;
2659ae115bc7Smrj 			break;
2660ae115bc7Smrj 
2661ae115bc7Smrj 		case X86_VENDOR_AMD:
26627417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2663ae115bc7Smrj 				*edx &= ~CPUID_AMD_EDX_TSCP;
26647417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4A))
2665f8801251Skk208521 				*ecx &= ~CPUID_AMD_ECX_SSE4A;
2666ae115bc7Smrj 			break;
2667ae115bc7Smrj 
2668ae115bc7Smrj 		default:
2669ae115bc7Smrj 			break;
2670ae115bc7Smrj 		}
26717c478bd9Sstevel@tonic-gate 
26727c478bd9Sstevel@tonic-gate 		/*
26737c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond
26747c478bd9Sstevel@tonic-gate 		 * x87 fp context and exception handlers]
26757c478bd9Sstevel@tonic-gate 		 */
26767c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
26777c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_AMD_EDX_MMXamd |
26787c478bd9Sstevel@tonic-gate 			    CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx);
26797c478bd9Sstevel@tonic-gate 
26807417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_NX))
26817c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_AMD_EDX_NX;
2682ae115bc7Smrj #if !defined(__amd64)
26837c478bd9Sstevel@tonic-gate 		*edx &= ~CPUID_AMD_EDX_LM;
26847c478bd9Sstevel@tonic-gate #endif
26857c478bd9Sstevel@tonic-gate 		/*
26867c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to
26877c478bd9Sstevel@tonic-gate 		 * things that we think userland will care about.
26887c478bd9Sstevel@tonic-gate 		 */
2689ae115bc7Smrj #if defined(__amd64)
26907c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_SYSC)
26917c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_SYSC;
2692ae115bc7Smrj #endif
26937c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_MMXamd)
26947c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_MMX;
26957c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNow)
26967c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNow;
26977c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNowx)
26987c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNowx;
2699faa20166SBryan Cantrill 		if (*ecx & CPUID_AMD_ECX_SVM)
2700faa20166SBryan Cantrill 			hwcap_flags |= AV_386_AMD_SVM;
2701ae115bc7Smrj 
2702ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2703ae115bc7Smrj 		case X86_VENDOR_AMD:
2704ae115bc7Smrj 			if (*edx & CPUID_AMD_EDX_TSCP)
2705ae115bc7Smrj 				hwcap_flags |= AV_386_TSCP;
2706ae115bc7Smrj 			if (*ecx & CPUID_AMD_ECX_AHF64)
2707ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2708f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_SSE4A)
2709f8801251Skk208521 				hwcap_flags |= AV_386_AMD_SSE4A;
2710f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_LZCNT)
2711f8801251Skk208521 				hwcap_flags |= AV_386_AMD_LZCNT;
2712ae115bc7Smrj 			break;
2713ae115bc7Smrj 
2714ae115bc7Smrj 		case X86_VENDOR_Intel:
2715d36ea5d8Ssudheer 			if (*edx & CPUID_AMD_EDX_TSCP)
2716d36ea5d8Ssudheer 				hwcap_flags |= AV_386_TSCP;
2717ae115bc7Smrj 			/*
2718ae115bc7Smrj 			 * Aarrgh.
2719ae115bc7Smrj 			 * Intel uses a different bit in the same word.
2720ae115bc7Smrj 			 */
2721ae115bc7Smrj 			if (*ecx & CPUID_INTC_ECX_AHF64)
2722ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2723ae115bc7Smrj 			break;
2724ae115bc7Smrj 
2725ae115bc7Smrj 		default:
2726ae115bc7Smrj 			break;
2727ae115bc7Smrj 		}
27287c478bd9Sstevel@tonic-gate 		break;
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
27318949bcd6Sandrei 		cp.cp_eax = 0x80860001;
27328949bcd6Sandrei 		(void) __cpuid_insn(&cp);
27338949bcd6Sandrei 		cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx;
27347c478bd9Sstevel@tonic-gate 		break;
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	default:
27377c478bd9Sstevel@tonic-gate 		break;
27387c478bd9Sstevel@tonic-gate 	}
27397c478bd9Sstevel@tonic-gate 
27407c478bd9Sstevel@tonic-gate pass4_done:
27417c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 4;
27427c478bd9Sstevel@tonic-gate 	return (hwcap_flags);
27437c478bd9Sstevel@tonic-gate }
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 
27467c478bd9Sstevel@tonic-gate /*
27477c478bd9Sstevel@tonic-gate  * Simulate the cpuid instruction using the data we previously
27487c478bd9Sstevel@tonic-gate  * captured about this CPU.  We try our best to return the truth
27497c478bd9Sstevel@tonic-gate  * about the hardware, independently of kernel support.
27507c478bd9Sstevel@tonic-gate  */
27517c478bd9Sstevel@tonic-gate uint32_t
27528949bcd6Sandrei cpuid_insn(cpu_t *cpu, struct cpuid_regs *cp)
27537c478bd9Sstevel@tonic-gate {
27547c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
27558949bcd6Sandrei 	struct cpuid_regs *xcp;
27567c478bd9Sstevel@tonic-gate 
27577c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
27587c478bd9Sstevel@tonic-gate 		cpu = CPU;
27597c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate 	/*
27647c478bd9Sstevel@tonic-gate 	 * CPUID data is cached in two separate places: cpi_std for standard
27657c478bd9Sstevel@tonic-gate 	 * CPUID functions, and cpi_extd for extended CPUID functions.
27667c478bd9Sstevel@tonic-gate 	 */
27678949bcd6Sandrei 	if (cp->cp_eax <= cpi->cpi_maxeax && cp->cp_eax < NMAX_CPI_STD)
27688949bcd6Sandrei 		xcp = &cpi->cpi_std[cp->cp_eax];
27698949bcd6Sandrei 	else if (cp->cp_eax >= 0x80000000 && cp->cp_eax <= cpi->cpi_xmaxeax &&
27708949bcd6Sandrei 	    cp->cp_eax < 0x80000000 + NMAX_CPI_EXTD)
27718949bcd6Sandrei 		xcp = &cpi->cpi_extd[cp->cp_eax - 0x80000000];
27727c478bd9Sstevel@tonic-gate 	else
27737c478bd9Sstevel@tonic-gate 		/*
27747c478bd9Sstevel@tonic-gate 		 * The caller is asking for data from an input parameter which
27757c478bd9Sstevel@tonic-gate 		 * the kernel has not cached.  In this case we go fetch from
27767c478bd9Sstevel@tonic-gate 		 * the hardware and return the data directly to the user.
27777c478bd9Sstevel@tonic-gate 		 */
27788949bcd6Sandrei 		return (__cpuid_insn(cp));
27798949bcd6Sandrei 
27808949bcd6Sandrei 	cp->cp_eax = xcp->cp_eax;
27818949bcd6Sandrei 	cp->cp_ebx = xcp->cp_ebx;
27828949bcd6Sandrei 	cp->cp_ecx = xcp->cp_ecx;
27838949bcd6Sandrei 	cp->cp_edx = xcp->cp_edx;
27847c478bd9Sstevel@tonic-gate 	return (cp->cp_eax);
27857c478bd9Sstevel@tonic-gate }
27867c478bd9Sstevel@tonic-gate 
27877c478bd9Sstevel@tonic-gate int
27887c478bd9Sstevel@tonic-gate cpuid_checkpass(cpu_t *cpu, int pass)
27897c478bd9Sstevel@tonic-gate {
27907c478bd9Sstevel@tonic-gate 	return (cpu != NULL && cpu->cpu_m.mcpu_cpi != NULL &&
27917c478bd9Sstevel@tonic-gate 	    cpu->cpu_m.mcpu_cpi->cpi_pass >= pass);
27927c478bd9Sstevel@tonic-gate }
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate int
27957c478bd9Sstevel@tonic-gate cpuid_getbrandstr(cpu_t *cpu, char *s, size_t n)
27967c478bd9Sstevel@tonic-gate {
27977c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, "%s", cpu->cpu_m.mcpu_cpi->cpi_brandstr));
28007c478bd9Sstevel@tonic-gate }
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate int
28038949bcd6Sandrei cpuid_is_cmt(cpu_t *cpu)
28047c478bd9Sstevel@tonic-gate {
28057c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
28067c478bd9Sstevel@tonic-gate 		cpu = CPU;
28077c478bd9Sstevel@tonic-gate 
28087c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28097c478bd9Sstevel@tonic-gate 
28107c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_chipid >= 0);
28117c478bd9Sstevel@tonic-gate }
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate /*
28147c478bd9Sstevel@tonic-gate  * AMD and Intel both implement the 64-bit variant of the syscall
28157c478bd9Sstevel@tonic-gate  * instruction (syscallq), so if there's -any- support for syscall,
28167c478bd9Sstevel@tonic-gate  * cpuid currently says "yes, we support this".
28177c478bd9Sstevel@tonic-gate  *
28187c478bd9Sstevel@tonic-gate  * However, Intel decided to -not- implement the 32-bit variant of the
28197c478bd9Sstevel@tonic-gate  * syscall instruction, so we provide a predicate to allow our caller
28207c478bd9Sstevel@tonic-gate  * to test that subtlety here.
2821843e1988Sjohnlev  *
2822843e1988Sjohnlev  * XXPV	Currently, 32-bit syscall instructions don't work via the hypervisor,
2823843e1988Sjohnlev  *	even in the case where the hardware would in fact support it.
28247c478bd9Sstevel@tonic-gate  */
28257c478bd9Sstevel@tonic-gate /*ARGSUSED*/
28267c478bd9Sstevel@tonic-gate int
28277c478bd9Sstevel@tonic-gate cpuid_syscall32_insn(cpu_t *cpu)
28287c478bd9Sstevel@tonic-gate {
28297c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass((cpu == NULL ? CPU : cpu), 1));
28307c478bd9Sstevel@tonic-gate 
2831843e1988Sjohnlev #if !defined(__xpv)
2832ae115bc7Smrj 	if (cpu == NULL)
2833ae115bc7Smrj 		cpu = CPU;
2834ae115bc7Smrj 
2835ae115bc7Smrj 	/*CSTYLED*/
2836ae115bc7Smrj 	{
2837ae115bc7Smrj 		struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
2838ae115bc7Smrj 
2839ae115bc7Smrj 		if (cpi->cpi_vendor == X86_VENDOR_AMD &&
2840ae115bc7Smrj 		    cpi->cpi_xmaxeax >= 0x80000001 &&
2841ae115bc7Smrj 		    (CPI_FEATURES_XTD_EDX(cpi) & CPUID_AMD_EDX_SYSC))
2842ae115bc7Smrj 			return (1);
2843ae115bc7Smrj 	}
2844843e1988Sjohnlev #endif
28457c478bd9Sstevel@tonic-gate 	return (0);
28467c478bd9Sstevel@tonic-gate }
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate int
28497c478bd9Sstevel@tonic-gate cpuid_getidstr(cpu_t *cpu, char *s, size_t n)
28507c478bd9Sstevel@tonic-gate {
28517c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 	static const char fmt[] =
2854ecfa43a5Sdmick 	    "x86 (%s %X family %d model %d step %d clock %d MHz)";
28557c478bd9Sstevel@tonic-gate 	static const char fmt_ht[] =
2856ecfa43a5Sdmick 	    "x86 (chipid 0x%x %s %X family %d model %d step %d clock %d MHz)";
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28597c478bd9Sstevel@tonic-gate 
28608949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
28617c478bd9Sstevel@tonic-gate 		return (snprintf(s, n, fmt_ht, cpi->cpi_chipid,
2862ecfa43a5Sdmick 		    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
2863ecfa43a5Sdmick 		    cpi->cpi_family, cpi->cpi_model,
28647c478bd9Sstevel@tonic-gate 		    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
28657c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, fmt,
2866ecfa43a5Sdmick 	    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
2867ecfa43a5Sdmick 	    cpi->cpi_family, cpi->cpi_model,
28687c478bd9Sstevel@tonic-gate 	    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
28697c478bd9Sstevel@tonic-gate }
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate const char *
28727c478bd9Sstevel@tonic-gate cpuid_getvendorstr(cpu_t *cpu)
28737c478bd9Sstevel@tonic-gate {
28747c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28757c478bd9Sstevel@tonic-gate 	return ((const char *)cpu->cpu_m.mcpu_cpi->cpi_vendorstr);
28767c478bd9Sstevel@tonic-gate }
28777c478bd9Sstevel@tonic-gate 
28787c478bd9Sstevel@tonic-gate uint_t
28797c478bd9Sstevel@tonic-gate cpuid_getvendor(cpu_t *cpu)
28807c478bd9Sstevel@tonic-gate {
28817c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28827c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_vendor);
28837c478bd9Sstevel@tonic-gate }
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate uint_t
28867c478bd9Sstevel@tonic-gate cpuid_getfamily(cpu_t *cpu)
28877c478bd9Sstevel@tonic-gate {
28887c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28897c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_family);
28907c478bd9Sstevel@tonic-gate }
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate uint_t
28937c478bd9Sstevel@tonic-gate cpuid_getmodel(cpu_t *cpu)
28947c478bd9Sstevel@tonic-gate {
28957c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28967c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_model);
28977c478bd9Sstevel@tonic-gate }
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate uint_t
29007c478bd9Sstevel@tonic-gate cpuid_get_ncpu_per_chip(cpu_t *cpu)
29017c478bd9Sstevel@tonic-gate {
29027c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29037c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_per_chip);
29047c478bd9Sstevel@tonic-gate }
29057c478bd9Sstevel@tonic-gate 
29067c478bd9Sstevel@tonic-gate uint_t
29078949bcd6Sandrei cpuid_get_ncore_per_chip(cpu_t *cpu)
29088949bcd6Sandrei {
29098949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
29108949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_ncore_per_chip);
29118949bcd6Sandrei }
29128949bcd6Sandrei 
29138949bcd6Sandrei uint_t
2914d129bde2Sesaxe cpuid_get_ncpu_sharing_last_cache(cpu_t *cpu)
2915d129bde2Sesaxe {
2916d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
2917d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_shr_last_cache);
2918d129bde2Sesaxe }
2919d129bde2Sesaxe 
2920d129bde2Sesaxe id_t
2921d129bde2Sesaxe cpuid_get_last_lvl_cacheid(cpu_t *cpu)
2922d129bde2Sesaxe {
2923d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
2924d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
2925d129bde2Sesaxe }
2926d129bde2Sesaxe 
2927d129bde2Sesaxe uint_t
29287c478bd9Sstevel@tonic-gate cpuid_getstep(cpu_t *cpu)
29297c478bd9Sstevel@tonic-gate {
29307c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29317c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_step);
29327c478bd9Sstevel@tonic-gate }
29337c478bd9Sstevel@tonic-gate 
29342449e17fSsherrym uint_t
29352449e17fSsherrym cpuid_getsig(struct cpu *cpu)
29362449e17fSsherrym {
29372449e17fSsherrym 	ASSERT(cpuid_checkpass(cpu, 1));
29382449e17fSsherrym 	return (cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_eax);
29392449e17fSsherrym }
29402449e17fSsherrym 
29418a40a695Sgavinm uint32_t
29428a40a695Sgavinm cpuid_getchiprev(struct cpu *cpu)
29438a40a695Sgavinm {
29448a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
29458a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprev);
29468a40a695Sgavinm }
29478a40a695Sgavinm 
29488a40a695Sgavinm const char *
29498a40a695Sgavinm cpuid_getchiprevstr(struct cpu *cpu)
29508a40a695Sgavinm {
29518a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
29528a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprevstr);
29538a40a695Sgavinm }
29548a40a695Sgavinm 
29558a40a695Sgavinm uint32_t
29568a40a695Sgavinm cpuid_getsockettype(struct cpu *cpu)
29578a40a695Sgavinm {
29588a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
29598a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_socket);
29608a40a695Sgavinm }
29618a40a695Sgavinm 
296289e921d5SKuriakose Kuruvilla const char *
296389e921d5SKuriakose Kuruvilla cpuid_getsocketstr(cpu_t *cpu)
296489e921d5SKuriakose Kuruvilla {
296589e921d5SKuriakose Kuruvilla 	static const char *socketstr = NULL;
296689e921d5SKuriakose Kuruvilla 	struct cpuid_info *cpi;
296789e921d5SKuriakose Kuruvilla 
296889e921d5SKuriakose Kuruvilla 	ASSERT(cpuid_checkpass(cpu, 1));
296989e921d5SKuriakose Kuruvilla 	cpi = cpu->cpu_m.mcpu_cpi;
297089e921d5SKuriakose Kuruvilla 
297189e921d5SKuriakose Kuruvilla 	/* Assume that socket types are the same across the system */
297289e921d5SKuriakose Kuruvilla 	if (socketstr == NULL)
297389e921d5SKuriakose Kuruvilla 		socketstr = _cpuid_sktstr(cpi->cpi_vendor, cpi->cpi_family,
297489e921d5SKuriakose Kuruvilla 		    cpi->cpi_model, cpi->cpi_step);
297589e921d5SKuriakose Kuruvilla 
297689e921d5SKuriakose Kuruvilla 
297789e921d5SKuriakose Kuruvilla 	return (socketstr);
297889e921d5SKuriakose Kuruvilla }
297989e921d5SKuriakose Kuruvilla 
2980fb2f18f8Sesaxe int
2981fb2f18f8Sesaxe cpuid_get_chipid(cpu_t *cpu)
29827c478bd9Sstevel@tonic-gate {
29837c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29847c478bd9Sstevel@tonic-gate 
29858949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
29867c478bd9Sstevel@tonic-gate 		return (cpu->cpu_m.mcpu_cpi->cpi_chipid);
29877c478bd9Sstevel@tonic-gate 	return (cpu->cpu_id);
29887c478bd9Sstevel@tonic-gate }
29897c478bd9Sstevel@tonic-gate 
29908949bcd6Sandrei id_t
2991fb2f18f8Sesaxe cpuid_get_coreid(cpu_t *cpu)
29928949bcd6Sandrei {
29938949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
29948949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_coreid);
29958949bcd6Sandrei }
29968949bcd6Sandrei 
29977c478bd9Sstevel@tonic-gate int
299810569901Sgavinm cpuid_get_pkgcoreid(cpu_t *cpu)
299910569901Sgavinm {
300010569901Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
300110569901Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_pkgcoreid);
300210569901Sgavinm }
300310569901Sgavinm 
300410569901Sgavinm int
3005fb2f18f8Sesaxe cpuid_get_clogid(cpu_t *cpu)
30067c478bd9Sstevel@tonic-gate {
30077c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30087c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_clogid);
30097c478bd9Sstevel@tonic-gate }
30107c478bd9Sstevel@tonic-gate 
3011b885580bSAlexander Kolbasov int
3012b885580bSAlexander Kolbasov cpuid_get_cacheid(cpu_t *cpu)
3013b885580bSAlexander Kolbasov {
3014b885580bSAlexander Kolbasov 	ASSERT(cpuid_checkpass(cpu, 1));
3015b885580bSAlexander Kolbasov 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
3016b885580bSAlexander Kolbasov }
3017b885580bSAlexander Kolbasov 
30188031591dSSrihari Venkatesan uint_t
30198031591dSSrihari Venkatesan cpuid_get_procnodeid(cpu_t *cpu)
30208031591dSSrihari Venkatesan {
30218031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
30228031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodeid);
30238031591dSSrihari Venkatesan }
30248031591dSSrihari Venkatesan 
30258031591dSSrihari Venkatesan uint_t
30268031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg(cpu_t *cpu)
30278031591dSSrihari Venkatesan {
30288031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
30298031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg);
30308031591dSSrihari Venkatesan }
30318031591dSSrihari Venkatesan 
3032*7660e73fSHans Rosenfeld uint_t
3033*7660e73fSHans Rosenfeld cpuid_get_compunitid(cpu_t *cpu)
3034*7660e73fSHans Rosenfeld {
3035*7660e73fSHans Rosenfeld 	ASSERT(cpuid_checkpass(cpu, 1));
3036*7660e73fSHans Rosenfeld 	return (cpu->cpu_m.mcpu_cpi->cpi_compunitid);
3037*7660e73fSHans Rosenfeld }
3038*7660e73fSHans Rosenfeld 
3039*7660e73fSHans Rosenfeld uint_t
3040*7660e73fSHans Rosenfeld cpuid_get_cores_per_compunit(cpu_t *cpu)
3041*7660e73fSHans Rosenfeld {
3042*7660e73fSHans Rosenfeld 	ASSERT(cpuid_checkpass(cpu, 1));
3043*7660e73fSHans Rosenfeld 	return (cpu->cpu_m.mcpu_cpi->cpi_cores_per_compunit);
3044*7660e73fSHans Rosenfeld }
3045*7660e73fSHans Rosenfeld 
30462ef50f01SJoe Bonasera /*ARGSUSED*/
30472ef50f01SJoe Bonasera int
30482ef50f01SJoe Bonasera cpuid_have_cr8access(cpu_t *cpu)
30492ef50f01SJoe Bonasera {
30502ef50f01SJoe Bonasera #if defined(__amd64)
30512ef50f01SJoe Bonasera 	return (1);
30522ef50f01SJoe Bonasera #else
30532ef50f01SJoe Bonasera 	struct cpuid_info *cpi;
30542ef50f01SJoe Bonasera 
30552ef50f01SJoe Bonasera 	ASSERT(cpu != NULL);
30562ef50f01SJoe Bonasera 	cpi = cpu->cpu_m.mcpu_cpi;
30572ef50f01SJoe Bonasera 	if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 &&
30582ef50f01SJoe Bonasera 	    (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0)
30592ef50f01SJoe Bonasera 		return (1);
30602ef50f01SJoe Bonasera 	return (0);
30612ef50f01SJoe Bonasera #endif
30622ef50f01SJoe Bonasera }
30632ef50f01SJoe Bonasera 
3064fa96bd91SMichael Corcoran uint32_t
3065fa96bd91SMichael Corcoran cpuid_get_apicid(cpu_t *cpu)
3066fa96bd91SMichael Corcoran {
3067fa96bd91SMichael Corcoran 	ASSERT(cpuid_checkpass(cpu, 1));
3068fa96bd91SMichael Corcoran 	if (cpu->cpu_m.mcpu_cpi->cpi_maxeax < 1) {
3069fa96bd91SMichael Corcoran 		return (UINT32_MAX);
3070fa96bd91SMichael Corcoran 	} else {
3071fa96bd91SMichael Corcoran 		return (cpu->cpu_m.mcpu_cpi->cpi_apicid);
3072fa96bd91SMichael Corcoran 	}
3073fa96bd91SMichael Corcoran }
3074fa96bd91SMichael Corcoran 
30757c478bd9Sstevel@tonic-gate void
30767c478bd9Sstevel@tonic-gate cpuid_get_addrsize(cpu_t *cpu, uint_t *pabits, uint_t *vabits)
30777c478bd9Sstevel@tonic-gate {
30787c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
30817c478bd9Sstevel@tonic-gate 		cpu = CPU;
30827c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30857c478bd9Sstevel@tonic-gate 
30867c478bd9Sstevel@tonic-gate 	if (pabits)
30877c478bd9Sstevel@tonic-gate 		*pabits = cpi->cpi_pabits;
30887c478bd9Sstevel@tonic-gate 	if (vabits)
30897c478bd9Sstevel@tonic-gate 		*vabits = cpi->cpi_vabits;
30907c478bd9Sstevel@tonic-gate }
30917c478bd9Sstevel@tonic-gate 
30927c478bd9Sstevel@tonic-gate /*
30937c478bd9Sstevel@tonic-gate  * Returns the number of data TLB entries for a corresponding
30947c478bd9Sstevel@tonic-gate  * pagesize.  If it can't be computed, or isn't known, the
30957c478bd9Sstevel@tonic-gate  * routine returns zero.  If you ask about an architecturally
30967c478bd9Sstevel@tonic-gate  * impossible pagesize, the routine will panic (so that the
30977c478bd9Sstevel@tonic-gate  * hat implementor knows that things are inconsistent.)
30987c478bd9Sstevel@tonic-gate  */
30997c478bd9Sstevel@tonic-gate uint_t
31007c478bd9Sstevel@tonic-gate cpuid_get_dtlb_nent(cpu_t *cpu, size_t pagesize)
31017c478bd9Sstevel@tonic-gate {
31027c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
31037c478bd9Sstevel@tonic-gate 	uint_t dtlb_nent = 0;
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
31067c478bd9Sstevel@tonic-gate 		cpu = CPU;
31077c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
31087c478bd9Sstevel@tonic-gate 
31097c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate 	/*
31127c478bd9Sstevel@tonic-gate 	 * Check the L2 TLB info
31137c478bd9Sstevel@tonic-gate 	 */
31147c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000006) {
31158949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[6];
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 		switch (pagesize) {
31187c478bd9Sstevel@tonic-gate 
31197c478bd9Sstevel@tonic-gate 		case 4 * 1024:
31207c478bd9Sstevel@tonic-gate 			/*
31217c478bd9Sstevel@tonic-gate 			 * All zero in the top 16 bits of the register
31227c478bd9Sstevel@tonic-gate 			 * indicates a unified TLB. Size is in low 16 bits.
31237c478bd9Sstevel@tonic-gate 			 */
31247c478bd9Sstevel@tonic-gate 			if ((cp->cp_ebx & 0xffff0000) == 0)
31257c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_ebx & 0x0000ffff;
31267c478bd9Sstevel@tonic-gate 			else
31277c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_ebx, 27, 16);
31287c478bd9Sstevel@tonic-gate 			break;
31297c478bd9Sstevel@tonic-gate 
31307c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
31317c478bd9Sstevel@tonic-gate 			if ((cp->cp_eax & 0xffff0000) == 0)
31327c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_eax & 0x0000ffff;
31337c478bd9Sstevel@tonic-gate 			else
31347c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_eax, 27, 16);
31357c478bd9Sstevel@tonic-gate 			break;
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 		default:
31387c478bd9Sstevel@tonic-gate 			panic("unknown L2 pagesize");
31397c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
31407c478bd9Sstevel@tonic-gate 		}
31417c478bd9Sstevel@tonic-gate 	}
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 	if (dtlb_nent != 0)
31447c478bd9Sstevel@tonic-gate 		return (dtlb_nent);
31457c478bd9Sstevel@tonic-gate 
31467c478bd9Sstevel@tonic-gate 	/*
31477c478bd9Sstevel@tonic-gate 	 * No L2 TLB support for this size, try L1.
31487c478bd9Sstevel@tonic-gate 	 */
31497c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000005) {
31508949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[5];
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 		switch (pagesize) {
31537c478bd9Sstevel@tonic-gate 		case 4 * 1024:
31547c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_ebx, 23, 16);
31557c478bd9Sstevel@tonic-gate 			break;
31567c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
31577c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_eax, 23, 16);
31587c478bd9Sstevel@tonic-gate 			break;
31597c478bd9Sstevel@tonic-gate 		default:
31607c478bd9Sstevel@tonic-gate 			panic("unknown L1 d-TLB pagesize");
31617c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
31627c478bd9Sstevel@tonic-gate 		}
31637c478bd9Sstevel@tonic-gate 	}
31647c478bd9Sstevel@tonic-gate 
31657c478bd9Sstevel@tonic-gate 	return (dtlb_nent);
31667c478bd9Sstevel@tonic-gate }
31677c478bd9Sstevel@tonic-gate 
31687c478bd9Sstevel@tonic-gate /*
31697c478bd9Sstevel@tonic-gate  * Return 0 if the erratum is not present or not applicable, positive
31707c478bd9Sstevel@tonic-gate  * if it is, and negative if the status of the erratum is unknown.
31717c478bd9Sstevel@tonic-gate  *
31727c478bd9Sstevel@tonic-gate  * See "Revision Guide for AMD Athlon(tm) 64 and AMD Opteron(tm)
31732201b277Skucharsk  * Processors" #25759, Rev 3.57, August 2005
31747c478bd9Sstevel@tonic-gate  */
31757c478bd9Sstevel@tonic-gate int
31767c478bd9Sstevel@tonic-gate cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum)
31777c478bd9Sstevel@tonic-gate {
31787c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
31798949bcd6Sandrei 	uint_t eax;
31807c478bd9Sstevel@tonic-gate 
3181ea99987eSsethg 	/*
3182ea99987eSsethg 	 * Bail out if this CPU isn't an AMD CPU, or if it's
3183ea99987eSsethg 	 * a legacy (32-bit) AMD CPU.
3184ea99987eSsethg 	 */
3185ea99987eSsethg 	if (cpi->cpi_vendor != X86_VENDOR_AMD ||
3186875b116eSkchow 	    cpi->cpi_family == 4 || cpi->cpi_family == 5 ||
3187875b116eSkchow 	    cpi->cpi_family == 6)
31888a40a695Sgavinm 
31897c478bd9Sstevel@tonic-gate 		return (0);
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 	eax = cpi->cpi_std[1].cp_eax;
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate #define	SH_B0(eax)	(eax == 0xf40 || eax == 0xf50)
31947c478bd9Sstevel@tonic-gate #define	SH_B3(eax) 	(eax == 0xf51)
3195ee88d2b9Skchow #define	B(eax)		(SH_B0(eax) || SH_B3(eax))
31967c478bd9Sstevel@tonic-gate 
31977c478bd9Sstevel@tonic-gate #define	SH_C0(eax)	(eax == 0xf48 || eax == 0xf58)
31987c478bd9Sstevel@tonic-gate 
31997c478bd9Sstevel@tonic-gate #define	SH_CG(eax)	(eax == 0xf4a || eax == 0xf5a || eax == 0xf7a)
32007c478bd9Sstevel@tonic-gate #define	DH_CG(eax)	(eax == 0xfc0 || eax == 0xfe0 || eax == 0xff0)
32017c478bd9Sstevel@tonic-gate #define	CH_CG(eax)	(eax == 0xf82 || eax == 0xfb2)
3202ee88d2b9Skchow #define	CG(eax)		(SH_CG(eax) || DH_CG(eax) || CH_CG(eax))
32037c478bd9Sstevel@tonic-gate 
32047c478bd9Sstevel@tonic-gate #define	SH_D0(eax)	(eax == 0x10f40 || eax == 0x10f50 || eax == 0x10f70)
32057c478bd9Sstevel@tonic-gate #define	DH_D0(eax)	(eax == 0x10fc0 || eax == 0x10ff0)
32067c478bd9Sstevel@tonic-gate #define	CH_D0(eax)	(eax == 0x10f80 || eax == 0x10fb0)
3207ee88d2b9Skchow #define	D0(eax)		(SH_D0(eax) || DH_D0(eax) || CH_D0(eax))
32087c478bd9Sstevel@tonic-gate 
32097c478bd9Sstevel@tonic-gate #define	SH_E0(eax)	(eax == 0x20f50 || eax == 0x20f40 || eax == 0x20f70)
32107c478bd9Sstevel@tonic-gate #define	JH_E1(eax)	(eax == 0x20f10)	/* JH8_E0 had 0x20f30 */
32117c478bd9Sstevel@tonic-gate #define	DH_E3(eax)	(eax == 0x20fc0 || eax == 0x20ff0)
32127c478bd9Sstevel@tonic-gate #define	SH_E4(eax)	(eax == 0x20f51 || eax == 0x20f71)
32137c478bd9Sstevel@tonic-gate #define	BH_E4(eax)	(eax == 0x20fb1)
32147c478bd9Sstevel@tonic-gate #define	SH_E5(eax)	(eax == 0x20f42)
32157c478bd9Sstevel@tonic-gate #define	DH_E6(eax)	(eax == 0x20ff2 || eax == 0x20fc2)
32167c478bd9Sstevel@tonic-gate #define	JH_E6(eax)	(eax == 0x20f12 || eax == 0x20f32)
3217ee88d2b9Skchow #define	EX(eax)		(SH_E0(eax) || JH_E1(eax) || DH_E3(eax) || \
3218ee88d2b9Skchow 			    SH_E4(eax) || BH_E4(eax) || SH_E5(eax) || \
3219ee88d2b9Skchow 			    DH_E6(eax) || JH_E6(eax))
32207c478bd9Sstevel@tonic-gate 
3221512cf780Skchow #define	DR_AX(eax)	(eax == 0x100f00 || eax == 0x100f01 || eax == 0x100f02)
3222512cf780Skchow #define	DR_B0(eax)	(eax == 0x100f20)
3223512cf780Skchow #define	DR_B1(eax)	(eax == 0x100f21)
3224512cf780Skchow #define	DR_BA(eax)	(eax == 0x100f2a)
3225512cf780Skchow #define	DR_B2(eax)	(eax == 0x100f22)
3226512cf780Skchow #define	DR_B3(eax)	(eax == 0x100f23)
3227512cf780Skchow #define	RB_C0(eax)	(eax == 0x100f40)
3228512cf780Skchow 
32297c478bd9Sstevel@tonic-gate 	switch (erratum) {
32307c478bd9Sstevel@tonic-gate 	case 1:
3231875b116eSkchow 		return (cpi->cpi_family < 0x10);
32327c478bd9Sstevel@tonic-gate 	case 51:	/* what does the asterisk mean? */
32337c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
32347c478bd9Sstevel@tonic-gate 	case 52:
32357c478bd9Sstevel@tonic-gate 		return (B(eax));
32367c478bd9Sstevel@tonic-gate 	case 57:
3237512cf780Skchow 		return (cpi->cpi_family <= 0x11);
32387c478bd9Sstevel@tonic-gate 	case 58:
32397c478bd9Sstevel@tonic-gate 		return (B(eax));
32407c478bd9Sstevel@tonic-gate 	case 60:
3241512cf780Skchow 		return (cpi->cpi_family <= 0x11);
32427c478bd9Sstevel@tonic-gate 	case 61:
32437c478bd9Sstevel@tonic-gate 	case 62:
32447c478bd9Sstevel@tonic-gate 	case 63:
32457c478bd9Sstevel@tonic-gate 	case 64:
32467c478bd9Sstevel@tonic-gate 	case 65:
32477c478bd9Sstevel@tonic-gate 	case 66:
32487c478bd9Sstevel@tonic-gate 	case 68:
32497c478bd9Sstevel@tonic-gate 	case 69:
32507c478bd9Sstevel@tonic-gate 	case 70:
32517c478bd9Sstevel@tonic-gate 	case 71:
32527c478bd9Sstevel@tonic-gate 		return (B(eax));
32537c478bd9Sstevel@tonic-gate 	case 72:
32547c478bd9Sstevel@tonic-gate 		return (SH_B0(eax));
32557c478bd9Sstevel@tonic-gate 	case 74:
32567c478bd9Sstevel@tonic-gate 		return (B(eax));
32577c478bd9Sstevel@tonic-gate 	case 75:
3258875b116eSkchow 		return (cpi->cpi_family < 0x10);
32597c478bd9Sstevel@tonic-gate 	case 76:
32607c478bd9Sstevel@tonic-gate 		return (B(eax));
32617c478bd9Sstevel@tonic-gate 	case 77:
3262512cf780Skchow 		return (cpi->cpi_family <= 0x11);
32637c478bd9Sstevel@tonic-gate 	case 78:
32647c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32657c478bd9Sstevel@tonic-gate 	case 79:
32667c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
32677c478bd9Sstevel@tonic-gate 	case 80:
32687c478bd9Sstevel@tonic-gate 	case 81:
32697c478bd9Sstevel@tonic-gate 	case 82:
32707c478bd9Sstevel@tonic-gate 		return (B(eax));
32717c478bd9Sstevel@tonic-gate 	case 83:
32727c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
32737c478bd9Sstevel@tonic-gate 	case 85:
3274875b116eSkchow 		return (cpi->cpi_family < 0x10);
32757c478bd9Sstevel@tonic-gate 	case 86:
32767c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
32777c478bd9Sstevel@tonic-gate 	case 88:
32787c478bd9Sstevel@tonic-gate #if !defined(__amd64)
32797c478bd9Sstevel@tonic-gate 		return (0);
32807c478bd9Sstevel@tonic-gate #else
32817c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32827c478bd9Sstevel@tonic-gate #endif
32837c478bd9Sstevel@tonic-gate 	case 89:
3284875b116eSkchow 		return (cpi->cpi_family < 0x10);
32857c478bd9Sstevel@tonic-gate 	case 90:
32867c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
32877c478bd9Sstevel@tonic-gate 	case 91:
32887c478bd9Sstevel@tonic-gate 	case 92:
32897c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32907c478bd9Sstevel@tonic-gate 	case 93:
32917c478bd9Sstevel@tonic-gate 		return (SH_C0(eax));
32927c478bd9Sstevel@tonic-gate 	case 94:
32937c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
32947c478bd9Sstevel@tonic-gate 	case 95:
32957c478bd9Sstevel@tonic-gate #if !defined(__amd64)
32967c478bd9Sstevel@tonic-gate 		return (0);
32977c478bd9Sstevel@tonic-gate #else
32987c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32997c478bd9Sstevel@tonic-gate #endif
33007c478bd9Sstevel@tonic-gate 	case 96:
33017c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
33027c478bd9Sstevel@tonic-gate 	case 97:
33037c478bd9Sstevel@tonic-gate 	case 98:
33047c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
33057c478bd9Sstevel@tonic-gate 	case 99:
33067c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
33077c478bd9Sstevel@tonic-gate 	case 100:
33087c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
33097c478bd9Sstevel@tonic-gate 	case 101:
33107c478bd9Sstevel@tonic-gate 	case 103:
33117c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
33127c478bd9Sstevel@tonic-gate 	case 104:
33137c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
33147c478bd9Sstevel@tonic-gate 	case 105:
33157c478bd9Sstevel@tonic-gate 	case 106:
33167c478bd9Sstevel@tonic-gate 	case 107:
33177c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
33187c478bd9Sstevel@tonic-gate 	case 108:
33197c478bd9Sstevel@tonic-gate 		return (DH_CG(eax));
33207c478bd9Sstevel@tonic-gate 	case 109:
33217c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
33227c478bd9Sstevel@tonic-gate 	case 110:
33237c478bd9Sstevel@tonic-gate 		return (D0(eax) || EX(eax));
33247c478bd9Sstevel@tonic-gate 	case 111:
33257c478bd9Sstevel@tonic-gate 		return (CG(eax));
33267c478bd9Sstevel@tonic-gate 	case 112:
33277c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
33287c478bd9Sstevel@tonic-gate 	case 113:
33297c478bd9Sstevel@tonic-gate 		return (eax == 0x20fc0);
33307c478bd9Sstevel@tonic-gate 	case 114:
33317c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
33327c478bd9Sstevel@tonic-gate 	case 115:
33337c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax));
33347c478bd9Sstevel@tonic-gate 	case 116:
33357c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
33367c478bd9Sstevel@tonic-gate 	case 117:
33377c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
33387c478bd9Sstevel@tonic-gate 	case 118:
33397c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || SH_E4(eax) || BH_E4(eax) ||
33407c478bd9Sstevel@tonic-gate 		    JH_E6(eax));
33417c478bd9Sstevel@tonic-gate 	case 121:
33427c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
33437c478bd9Sstevel@tonic-gate 	case 122:
3344512cf780Skchow 		return (cpi->cpi_family < 0x10 || cpi->cpi_family == 0x11);
33457c478bd9Sstevel@tonic-gate 	case 123:
33467c478bd9Sstevel@tonic-gate 		return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax));
33472201b277Skucharsk 	case 131:
3348875b116eSkchow 		return (cpi->cpi_family < 0x10);
3349ef50d8c0Sesaxe 	case 6336786:
3350ef50d8c0Sesaxe 		/*
3351ef50d8c0Sesaxe 		 * Test for AdvPowerMgmtInfo.TscPStateInvariant
3352875b116eSkchow 		 * if this is a K8 family or newer processor
3353ef50d8c0Sesaxe 		 */
3354ef50d8c0Sesaxe 		if (CPI_FAMILY(cpi) == 0xf) {
33558949bcd6Sandrei 			struct cpuid_regs regs;
33568949bcd6Sandrei 			regs.cp_eax = 0x80000007;
33578949bcd6Sandrei 			(void) __cpuid_insn(&regs);
33588949bcd6Sandrei 			return (!(regs.cp_edx & 0x100));
3359ef50d8c0Sesaxe 		}
3360ef50d8c0Sesaxe 		return (0);
3361ee88d2b9Skchow 	case 6323525:
3362ee88d2b9Skchow 		return (((((eax >> 12) & 0xff00) + (eax & 0xf00)) |
3363ee88d2b9Skchow 		    (((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0))) < 0xf40);
3364ee88d2b9Skchow 
3365512cf780Skchow 	case 6671130:
3366512cf780Skchow 		/*
3367512cf780Skchow 		 * check for processors (pre-Shanghai) that do not provide
3368512cf780Skchow 		 * optimal management of 1gb ptes in its tlb.
3369512cf780Skchow 		 */
3370512cf780Skchow 		return (cpi->cpi_family == 0x10 && cpi->cpi_model < 4);
3371512cf780Skchow 
3372512cf780Skchow 	case 298:
3373512cf780Skchow 		return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) ||
3374512cf780Skchow 		    DR_B2(eax) || RB_C0(eax));
3375512cf780Skchow 
33765e54b56dSHans Rosenfeld 	case 721:
33775e54b56dSHans Rosenfeld #if defined(__amd64)
33785e54b56dSHans Rosenfeld 		return (cpi->cpi_family == 0x10 || cpi->cpi_family == 0x12);
33795e54b56dSHans Rosenfeld #else
33805e54b56dSHans Rosenfeld 		return (0);
33815e54b56dSHans Rosenfeld #endif
33825e54b56dSHans Rosenfeld 
3383512cf780Skchow 	default:
3384512cf780Skchow 		return (-1);
3385512cf780Skchow 
3386512cf780Skchow 	}
3387512cf780Skchow }
3388512cf780Skchow 
3389512cf780Skchow /*
3390512cf780Skchow  * Determine if specified erratum is present via OSVW (OS Visible Workaround).
3391512cf780Skchow  * Return 1 if erratum is present, 0 if not present and -1 if indeterminate.
3392512cf780Skchow  */
3393512cf780Skchow int
3394512cf780Skchow osvw_opteron_erratum(cpu_t *cpu, uint_t erratum)
3395512cf780Skchow {
3396512cf780Skchow 	struct cpuid_info	*cpi;
3397512cf780Skchow 	uint_t			osvwid;
3398512cf780Skchow 	static int		osvwfeature = -1;
3399512cf780Skchow 	uint64_t		osvwlength;
3400512cf780Skchow 
3401512cf780Skchow 
3402512cf780Skchow 	cpi = cpu->cpu_m.mcpu_cpi;
3403512cf780Skchow 
3404512cf780Skchow 	/* confirm OSVW supported */
3405512cf780Skchow 	if (osvwfeature == -1) {
3406512cf780Skchow 		osvwfeature = cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW;
3407512cf780Skchow 	} else {
3408512cf780Skchow 		/* assert that osvw feature setting is consistent on all cpus */
3409512cf780Skchow 		ASSERT(osvwfeature ==
3410512cf780Skchow 		    (cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW));
3411512cf780Skchow 	}
3412512cf780Skchow 	if (!osvwfeature)
3413512cf780Skchow 		return (-1);
3414512cf780Skchow 
3415512cf780Skchow 	osvwlength = rdmsr(MSR_AMD_OSVW_ID_LEN) & OSVW_ID_LEN_MASK;
3416512cf780Skchow 
3417512cf780Skchow 	switch (erratum) {
3418512cf780Skchow 	case 298:	/* osvwid is 0 */
3419512cf780Skchow 		osvwid = 0;
3420512cf780Skchow 		if (osvwlength <= (uint64_t)osvwid) {
3421512cf780Skchow 			/* osvwid 0 is unknown */
3422512cf780Skchow 			return (-1);
3423512cf780Skchow 		}
3424512cf780Skchow 
3425512cf780Skchow 		/*
3426512cf780Skchow 		 * Check the OSVW STATUS MSR to determine the state
3427512cf780Skchow 		 * of the erratum where:
3428512cf780Skchow 		 *   0 - fixed by HW
3429512cf780Skchow 		 *   1 - BIOS has applied the workaround when BIOS
3430512cf780Skchow 		 *   workaround is available. (Or for other errata,
3431512cf780Skchow 		 *   OS workaround is required.)
3432512cf780Skchow 		 * For a value of 1, caller will confirm that the
3433512cf780Skchow 		 * erratum 298 workaround has indeed been applied by BIOS.
3434512cf780Skchow 		 *
3435512cf780Skchow 		 * A 1 may be set in cpus that have a HW fix
3436512cf780Skchow 		 * in a mixed cpu system. Regarding erratum 298:
3437512cf780Skchow 		 *   In a multiprocessor platform, the workaround above
3438512cf780Skchow 		 *   should be applied to all processors regardless of
3439512cf780Skchow 		 *   silicon revision when an affected processor is
3440512cf780Skchow 		 *   present.
3441512cf780Skchow 		 */
3442512cf780Skchow 
3443512cf780Skchow 		return (rdmsr(MSR_AMD_OSVW_STATUS +
3444512cf780Skchow 		    (osvwid / OSVW_ID_CNT_PER_MSR)) &
3445512cf780Skchow 		    (1ULL << (osvwid % OSVW_ID_CNT_PER_MSR)));
3446512cf780Skchow 
34477c478bd9Sstevel@tonic-gate 	default:
34487c478bd9Sstevel@tonic-gate 		return (-1);
34497c478bd9Sstevel@tonic-gate 	}
34507c478bd9Sstevel@tonic-gate }
34517c478bd9Sstevel@tonic-gate 
34527c478bd9Sstevel@tonic-gate static const char assoc_str[] = "associativity";
34537c478bd9Sstevel@tonic-gate static const char line_str[] = "line-size";
34547c478bd9Sstevel@tonic-gate static const char size_str[] = "size";
34557c478bd9Sstevel@tonic-gate 
34567c478bd9Sstevel@tonic-gate static void
34577c478bd9Sstevel@tonic-gate add_cache_prop(dev_info_t *devi, const char *label, const char *type,
34587c478bd9Sstevel@tonic-gate     uint32_t val)
34597c478bd9Sstevel@tonic-gate {
34607c478bd9Sstevel@tonic-gate 	char buf[128];
34617c478bd9Sstevel@tonic-gate 
34627c478bd9Sstevel@tonic-gate 	/*
34637c478bd9Sstevel@tonic-gate 	 * ndi_prop_update_int() is used because it is desirable for
34647c478bd9Sstevel@tonic-gate 	 * DDI_PROP_HW_DEF and DDI_PROP_DONTSLEEP to be set.
34657c478bd9Sstevel@tonic-gate 	 */
34667c478bd9Sstevel@tonic-gate 	if (snprintf(buf, sizeof (buf), "%s-%s", label, type) < sizeof (buf))
34677c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, buf, val);
34687c478bd9Sstevel@tonic-gate }
34697c478bd9Sstevel@tonic-gate 
34707c478bd9Sstevel@tonic-gate /*
34717c478bd9Sstevel@tonic-gate  * Intel-style cache/tlb description
34727c478bd9Sstevel@tonic-gate  *
34737c478bd9Sstevel@tonic-gate  * Standard cpuid level 2 gives a randomly ordered
34747c478bd9Sstevel@tonic-gate  * selection of tags that index into a table that describes
34757c478bd9Sstevel@tonic-gate  * cache and tlb properties.
34767c478bd9Sstevel@tonic-gate  */
34777c478bd9Sstevel@tonic-gate 
34787c478bd9Sstevel@tonic-gate static const char l1_icache_str[] = "l1-icache";
34797c478bd9Sstevel@tonic-gate static const char l1_dcache_str[] = "l1-dcache";
34807c478bd9Sstevel@tonic-gate static const char l2_cache_str[] = "l2-cache";
3481ae115bc7Smrj static const char l3_cache_str[] = "l3-cache";
34827c478bd9Sstevel@tonic-gate static const char itlb4k_str[] = "itlb-4K";
34837c478bd9Sstevel@tonic-gate static const char dtlb4k_str[] = "dtlb-4K";
3484824e4fecSvd224797 static const char itlb2M_str[] = "itlb-2M";
34857c478bd9Sstevel@tonic-gate static const char itlb4M_str[] = "itlb-4M";
34867c478bd9Sstevel@tonic-gate static const char dtlb4M_str[] = "dtlb-4M";
348725dfb062Sksadhukh static const char dtlb24_str[] = "dtlb0-2M-4M";
34887c478bd9Sstevel@tonic-gate static const char itlb424_str[] = "itlb-4K-2M-4M";
348925dfb062Sksadhukh static const char itlb24_str[] = "itlb-2M-4M";
34907c478bd9Sstevel@tonic-gate static const char dtlb44_str[] = "dtlb-4K-4M";
34917c478bd9Sstevel@tonic-gate static const char sl1_dcache_str[] = "sectored-l1-dcache";
34927c478bd9Sstevel@tonic-gate static const char sl2_cache_str[] = "sectored-l2-cache";
34937c478bd9Sstevel@tonic-gate static const char itrace_str[] = "itrace-cache";
34947c478bd9Sstevel@tonic-gate static const char sl3_cache_str[] = "sectored-l3-cache";
349525dfb062Sksadhukh static const char sh_l2_tlb4k_str[] = "shared-l2-tlb-4k";
34967c478bd9Sstevel@tonic-gate 
34977c478bd9Sstevel@tonic-gate static const struct cachetab {
34987c478bd9Sstevel@tonic-gate 	uint8_t 	ct_code;
34997c478bd9Sstevel@tonic-gate 	uint8_t		ct_assoc;
35007c478bd9Sstevel@tonic-gate 	uint16_t 	ct_line_size;
35017c478bd9Sstevel@tonic-gate 	size_t		ct_size;
35027c478bd9Sstevel@tonic-gate 	const char	*ct_label;
35037c478bd9Sstevel@tonic-gate } intel_ctab[] = {
3504824e4fecSvd224797 	/*
3505824e4fecSvd224797 	 * maintain descending order!
3506824e4fecSvd224797 	 *
3507824e4fecSvd224797 	 * Codes ignored - Reason
3508824e4fecSvd224797 	 * ----------------------
3509824e4fecSvd224797 	 * 40H - intel_cpuid_4_cache_info() disambiguates l2/l3 cache
3510824e4fecSvd224797 	 * f0H/f1H - Currently we do not interpret prefetch size by design
3511824e4fecSvd224797 	 */
351225dfb062Sksadhukh 	{ 0xe4, 16, 64, 8*1024*1024, l3_cache_str},
351325dfb062Sksadhukh 	{ 0xe3, 16, 64, 4*1024*1024, l3_cache_str},
351425dfb062Sksadhukh 	{ 0xe2, 16, 64, 2*1024*1024, l3_cache_str},
351525dfb062Sksadhukh 	{ 0xde, 12, 64, 6*1024*1024, l3_cache_str},
351625dfb062Sksadhukh 	{ 0xdd, 12, 64, 3*1024*1024, l3_cache_str},
351725dfb062Sksadhukh 	{ 0xdc, 12, 64, ((1*1024*1024)+(512*1024)), l3_cache_str},
351825dfb062Sksadhukh 	{ 0xd8, 8, 64, 4*1024*1024, l3_cache_str},
351925dfb062Sksadhukh 	{ 0xd7, 8, 64, 2*1024*1024, l3_cache_str},
352025dfb062Sksadhukh 	{ 0xd6, 8, 64, 1*1024*1024, l3_cache_str},
352125dfb062Sksadhukh 	{ 0xd2, 4, 64, 2*1024*1024, l3_cache_str},
352225dfb062Sksadhukh 	{ 0xd1, 4, 64, 1*1024*1024, l3_cache_str},
352325dfb062Sksadhukh 	{ 0xd0, 4, 64, 512*1024, l3_cache_str},
352425dfb062Sksadhukh 	{ 0xca, 4, 0, 512, sh_l2_tlb4k_str},
3525824e4fecSvd224797 	{ 0xc0, 4, 0, 8, dtlb44_str },
3526824e4fecSvd224797 	{ 0xba, 4, 0, 64, dtlb4k_str },
3527ae115bc7Smrj 	{ 0xb4, 4, 0, 256, dtlb4k_str },
35287c478bd9Sstevel@tonic-gate 	{ 0xb3, 4, 0, 128, dtlb4k_str },
352925dfb062Sksadhukh 	{ 0xb2, 4, 0, 64, itlb4k_str },
35307c478bd9Sstevel@tonic-gate 	{ 0xb0, 4, 0, 128, itlb4k_str },
35317c478bd9Sstevel@tonic-gate 	{ 0x87, 8, 64, 1024*1024, l2_cache_str},
35327c478bd9Sstevel@tonic-gate 	{ 0x86, 4, 64, 512*1024, l2_cache_str},
35337c478bd9Sstevel@tonic-gate 	{ 0x85, 8, 32, 2*1024*1024, l2_cache_str},
35347c478bd9Sstevel@tonic-gate 	{ 0x84, 8, 32, 1024*1024, l2_cache_str},
35357c478bd9Sstevel@tonic-gate 	{ 0x83, 8, 32, 512*1024, l2_cache_str},
35367c478bd9Sstevel@tonic-gate 	{ 0x82, 8, 32, 256*1024, l2_cache_str},
3537824e4fecSvd224797 	{ 0x80, 8, 64, 512*1024, l2_cache_str},
35387c478bd9Sstevel@tonic-gate 	{ 0x7f, 2, 64, 512*1024, l2_cache_str},
35397c478bd9Sstevel@tonic-gate 	{ 0x7d, 8, 64, 2*1024*1024, sl2_cache_str},
35407c478bd9Sstevel@tonic-gate 	{ 0x7c, 8, 64, 1024*1024, sl2_cache_str},
35417c478bd9Sstevel@tonic-gate 	{ 0x7b, 8, 64, 512*1024, sl2_cache_str},
35427c478bd9Sstevel@tonic-gate 	{ 0x7a, 8, 64, 256*1024, sl2_cache_str},
35437c478bd9Sstevel@tonic-gate 	{ 0x79, 8, 64, 128*1024, sl2_cache_str},
35447c478bd9Sstevel@tonic-gate 	{ 0x78, 8, 64, 1024*1024, l2_cache_str},
3545ae115bc7Smrj 	{ 0x73, 8, 0, 64*1024, itrace_str},
35467c478bd9Sstevel@tonic-gate 	{ 0x72, 8, 0, 32*1024, itrace_str},
35477c478bd9Sstevel@tonic-gate 	{ 0x71, 8, 0, 16*1024, itrace_str},
35487c478bd9Sstevel@tonic-gate 	{ 0x70, 8, 0, 12*1024, itrace_str},
35497c478bd9Sstevel@tonic-gate 	{ 0x68, 4, 64, 32*1024, sl1_dcache_str},
35507c478bd9Sstevel@tonic-gate 	{ 0x67, 4, 64, 16*1024, sl1_dcache_str},
35517c478bd9Sstevel@tonic-gate 	{ 0x66, 4, 64, 8*1024, sl1_dcache_str},
35527c478bd9Sstevel@tonic-gate 	{ 0x60, 8, 64, 16*1024, sl1_dcache_str},
35537c478bd9Sstevel@tonic-gate 	{ 0x5d, 0, 0, 256, dtlb44_str},
35547c478bd9Sstevel@tonic-gate 	{ 0x5c, 0, 0, 128, dtlb44_str},
35557c478bd9Sstevel@tonic-gate 	{ 0x5b, 0, 0, 64, dtlb44_str},
355625dfb062Sksadhukh 	{ 0x5a, 4, 0, 32, dtlb24_str},
3557824e4fecSvd224797 	{ 0x59, 0, 0, 16, dtlb4k_str},
3558824e4fecSvd224797 	{ 0x57, 4, 0, 16, dtlb4k_str},
3559824e4fecSvd224797 	{ 0x56, 4, 0, 16, dtlb4M_str},
356025dfb062Sksadhukh 	{ 0x55, 0, 0, 7, itlb24_str},
35617c478bd9Sstevel@tonic-gate 	{ 0x52, 0, 0, 256, itlb424_str},
35627c478bd9Sstevel@tonic-gate 	{ 0x51, 0, 0, 128, itlb424_str},
35637c478bd9Sstevel@tonic-gate 	{ 0x50, 0, 0, 64, itlb424_str},
3564824e4fecSvd224797 	{ 0x4f, 0, 0, 32, itlb4k_str},
3565824e4fecSvd224797 	{ 0x4e, 24, 64, 6*1024*1024, l2_cache_str},
3566ae115bc7Smrj 	{ 0x4d, 16, 64, 16*1024*1024, l3_cache_str},
3567ae115bc7Smrj 	{ 0x4c, 12, 64, 12*1024*1024, l3_cache_str},
3568ae115bc7Smrj 	{ 0x4b, 16, 64, 8*1024*1024, l3_cache_str},
3569ae115bc7Smrj 	{ 0x4a, 12, 64, 6*1024*1024, l3_cache_str},
3570ae115bc7Smrj 	{ 0x49, 16, 64, 4*1024*1024, l3_cache_str},
3571824e4fecSvd224797 	{ 0x48, 12, 64, 3*1024*1024, l2_cache_str},
3572ae115bc7Smrj 	{ 0x47, 8, 64, 8*1024*1024, l3_cache_str},
3573ae115bc7Smrj 	{ 0x46, 4, 64, 4*1024*1024, l3_cache_str},
35747c478bd9Sstevel@tonic-gate 	{ 0x45, 4, 32, 2*1024*1024, l2_cache_str},
35757c478bd9Sstevel@tonic-gate 	{ 0x44, 4, 32, 1024*1024, l2_cache_str},
35767c478bd9Sstevel@tonic-gate 	{ 0x43, 4, 32, 512*1024, l2_cache_str},
35777c478bd9Sstevel@tonic-gate 	{ 0x42, 4, 32, 256*1024, l2_cache_str},
35787c478bd9Sstevel@tonic-gate 	{ 0x41, 4, 32, 128*1024, l2_cache_str},
3579ae115bc7Smrj 	{ 0x3e, 4, 64, 512*1024, sl2_cache_str},
3580ae115bc7Smrj 	{ 0x3d, 6, 64, 384*1024, sl2_cache_str},
35817c478bd9Sstevel@tonic-gate 	{ 0x3c, 4, 64, 256*1024, sl2_cache_str},
35827c478bd9Sstevel@tonic-gate 	{ 0x3b, 2, 64, 128*1024, sl2_cache_str},
3583ae115bc7Smrj 	{ 0x3a, 6, 64, 192*1024, sl2_cache_str},
35847c478bd9Sstevel@tonic-gate 	{ 0x39, 4, 64, 128*1024, sl2_cache_str},
35857c478bd9Sstevel@tonic-gate 	{ 0x30, 8, 64, 32*1024, l1_icache_str},
35867c478bd9Sstevel@tonic-gate 	{ 0x2c, 8, 64, 32*1024, l1_dcache_str},
35877c478bd9Sstevel@tonic-gate 	{ 0x29, 8, 64, 4096*1024, sl3_cache_str},
35887c478bd9Sstevel@tonic-gate 	{ 0x25, 8, 64, 2048*1024, sl3_cache_str},
35897c478bd9Sstevel@tonic-gate 	{ 0x23, 8, 64, 1024*1024, sl3_cache_str},
35907c478bd9Sstevel@tonic-gate 	{ 0x22, 4, 64, 512*1024, sl3_cache_str},
3591824e4fecSvd224797 	{ 0x0e, 6, 64, 24*1024, l1_dcache_str},
359225dfb062Sksadhukh 	{ 0x0d, 4, 32, 16*1024, l1_dcache_str},
35937c478bd9Sstevel@tonic-gate 	{ 0x0c, 4, 32, 16*1024, l1_dcache_str},
3594ae115bc7Smrj 	{ 0x0b, 4, 0, 4, itlb4M_str},
35957c478bd9Sstevel@tonic-gate 	{ 0x0a, 2, 32, 8*1024, l1_dcache_str},
35967c478bd9Sstevel@tonic-gate 	{ 0x08, 4, 32, 16*1024, l1_icache_str},
35977c478bd9Sstevel@tonic-gate 	{ 0x06, 4, 32, 8*1024, l1_icache_str},
3598824e4fecSvd224797 	{ 0x05, 4, 0, 32, dtlb4M_str},
35997c478bd9Sstevel@tonic-gate 	{ 0x04, 4, 0, 8, dtlb4M_str},
36007c478bd9Sstevel@tonic-gate 	{ 0x03, 4, 0, 64, dtlb4k_str},
36017c478bd9Sstevel@tonic-gate 	{ 0x02, 4, 0, 2, itlb4M_str},
36027c478bd9Sstevel@tonic-gate 	{ 0x01, 4, 0, 32, itlb4k_str},
36037c478bd9Sstevel@tonic-gate 	{ 0 }
36047c478bd9Sstevel@tonic-gate };
36057c478bd9Sstevel@tonic-gate 
36067c478bd9Sstevel@tonic-gate static const struct cachetab cyrix_ctab[] = {
36077c478bd9Sstevel@tonic-gate 	{ 0x70, 4, 0, 32, "tlb-4K" },
36087c478bd9Sstevel@tonic-gate 	{ 0x80, 4, 16, 16*1024, "l1-cache" },
36097c478bd9Sstevel@tonic-gate 	{ 0 }
36107c478bd9Sstevel@tonic-gate };
36117c478bd9Sstevel@tonic-gate 
36127c478bd9Sstevel@tonic-gate /*
36137c478bd9Sstevel@tonic-gate  * Search a cache table for a matching entry
36147c478bd9Sstevel@tonic-gate  */
36157c478bd9Sstevel@tonic-gate static const struct cachetab *
36167c478bd9Sstevel@tonic-gate find_cacheent(const struct cachetab *ct, uint_t code)
36177c478bd9Sstevel@tonic-gate {
36187c478bd9Sstevel@tonic-gate 	if (code != 0) {
36197c478bd9Sstevel@tonic-gate 		for (; ct->ct_code != 0; ct++)
36207c478bd9Sstevel@tonic-gate 			if (ct->ct_code <= code)
36217c478bd9Sstevel@tonic-gate 				break;
36227c478bd9Sstevel@tonic-gate 		if (ct->ct_code == code)
36237c478bd9Sstevel@tonic-gate 			return (ct);
36247c478bd9Sstevel@tonic-gate 	}
36257c478bd9Sstevel@tonic-gate 	return (NULL);
36267c478bd9Sstevel@tonic-gate }
36277c478bd9Sstevel@tonic-gate 
36287c478bd9Sstevel@tonic-gate /*
36297dee861bSksadhukh  * Populate cachetab entry with L2 or L3 cache-information using
36307dee861bSksadhukh  * cpuid function 4. This function is called from intel_walk_cacheinfo()
36317dee861bSksadhukh  * when descriptor 0x49 is encountered. It returns 0 if no such cache
36327dee861bSksadhukh  * information is found.
36337dee861bSksadhukh  */
36347dee861bSksadhukh static int
36357dee861bSksadhukh intel_cpuid_4_cache_info(struct cachetab *ct, struct cpuid_info *cpi)
36367dee861bSksadhukh {
36377dee861bSksadhukh 	uint32_t level, i;
36387dee861bSksadhukh 	int ret = 0;
36397dee861bSksadhukh 
36407dee861bSksadhukh 	for (i = 0; i < cpi->cpi_std_4_size; i++) {
36417dee861bSksadhukh 		level = CPI_CACHE_LVL(cpi->cpi_std_4[i]);
36427dee861bSksadhukh 
36437dee861bSksadhukh 		if (level == 2 || level == 3) {
36447dee861bSksadhukh 			ct->ct_assoc = CPI_CACHE_WAYS(cpi->cpi_std_4[i]) + 1;
36457dee861bSksadhukh 			ct->ct_line_size =
36467dee861bSksadhukh 			    CPI_CACHE_COH_LN_SZ(cpi->cpi_std_4[i]) + 1;
36477dee861bSksadhukh 			ct->ct_size = ct->ct_assoc *
36487dee861bSksadhukh 			    (CPI_CACHE_PARTS(cpi->cpi_std_4[i]) + 1) *
36497dee861bSksadhukh 			    ct->ct_line_size *
36507dee861bSksadhukh 			    (cpi->cpi_std_4[i]->cp_ecx + 1);
36517dee861bSksadhukh 
36527dee861bSksadhukh 			if (level == 2) {
36537dee861bSksadhukh 				ct->ct_label = l2_cache_str;
36547dee861bSksadhukh 			} else if (level == 3) {
36557dee861bSksadhukh 				ct->ct_label = l3_cache_str;
36567dee861bSksadhukh 			}
36577dee861bSksadhukh 			ret = 1;
36587dee861bSksadhukh 		}
36597dee861bSksadhukh 	}
36607dee861bSksadhukh 
36617dee861bSksadhukh 	return (ret);
36627dee861bSksadhukh }
36637dee861bSksadhukh 
36647dee861bSksadhukh /*
36657c478bd9Sstevel@tonic-gate  * Walk the cacheinfo descriptor, applying 'func' to every valid element
36667c478bd9Sstevel@tonic-gate  * The walk is terminated if the walker returns non-zero.
36677c478bd9Sstevel@tonic-gate  */
36687c478bd9Sstevel@tonic-gate static void
36697c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(struct cpuid_info *cpi,
36707c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
36717c478bd9Sstevel@tonic-gate {
36727c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
3673824e4fecSvd224797 	struct cachetab des_49_ct, des_b1_ct;
36747c478bd9Sstevel@tonic-gate 	uint8_t *dp;
36757c478bd9Sstevel@tonic-gate 	int i;
36767c478bd9Sstevel@tonic-gate 
36777c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
36787c478bd9Sstevel@tonic-gate 		return;
3679f1d742a9Sksadhukh 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
3680f1d742a9Sksadhukh 		/*
3681f1d742a9Sksadhukh 		 * For overloaded descriptor 0x49 we use cpuid function 4
36827dee861bSksadhukh 		 * if supported by the current processor, to create
3683f1d742a9Sksadhukh 		 * cache information.
3684824e4fecSvd224797 		 * For overloaded descriptor 0xb1 we use X86_PAE flag
3685824e4fecSvd224797 		 * to disambiguate the cache information.
3686f1d742a9Sksadhukh 		 */
36877dee861bSksadhukh 		if (*dp == 0x49 && cpi->cpi_maxeax >= 0x4 &&
36887dee861bSksadhukh 		    intel_cpuid_4_cache_info(&des_49_ct, cpi) == 1) {
36897dee861bSksadhukh 				ct = &des_49_ct;
3690824e4fecSvd224797 		} else if (*dp == 0xb1) {
3691824e4fecSvd224797 			des_b1_ct.ct_code = 0xb1;
3692824e4fecSvd224797 			des_b1_ct.ct_assoc = 4;
3693824e4fecSvd224797 			des_b1_ct.ct_line_size = 0;
36947417cfdeSKuriakose Kuruvilla 			if (is_x86_feature(x86_featureset, X86FSET_PAE)) {
3695824e4fecSvd224797 				des_b1_ct.ct_size = 8;
3696824e4fecSvd224797 				des_b1_ct.ct_label = itlb2M_str;
3697824e4fecSvd224797 			} else {
3698824e4fecSvd224797 				des_b1_ct.ct_size = 4;
3699824e4fecSvd224797 				des_b1_ct.ct_label = itlb4M_str;
3700824e4fecSvd224797 			}
3701824e4fecSvd224797 			ct = &des_b1_ct;
37027dee861bSksadhukh 		} else {
37037dee861bSksadhukh 			if ((ct = find_cacheent(intel_ctab, *dp)) == NULL) {
3704f1d742a9Sksadhukh 				continue;
3705f1d742a9Sksadhukh 			}
37067dee861bSksadhukh 		}
3707f1d742a9Sksadhukh 
37087dee861bSksadhukh 		if (func(arg, ct) != 0) {
37097c478bd9Sstevel@tonic-gate 			break;
37107c478bd9Sstevel@tonic-gate 		}
37117c478bd9Sstevel@tonic-gate 	}
3712f1d742a9Sksadhukh }
37137c478bd9Sstevel@tonic-gate 
37147c478bd9Sstevel@tonic-gate /*
37157c478bd9Sstevel@tonic-gate  * (Like the Intel one, except for Cyrix CPUs)
37167c478bd9Sstevel@tonic-gate  */
37177c478bd9Sstevel@tonic-gate static void
37187c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(struct cpuid_info *cpi,
37197c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
37207c478bd9Sstevel@tonic-gate {
37217c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
37227c478bd9Sstevel@tonic-gate 	uint8_t *dp;
37237c478bd9Sstevel@tonic-gate 	int i;
37247c478bd9Sstevel@tonic-gate 
37257c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
37267c478bd9Sstevel@tonic-gate 		return;
37277c478bd9Sstevel@tonic-gate 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
37287c478bd9Sstevel@tonic-gate 		/*
37297c478bd9Sstevel@tonic-gate 		 * Search Cyrix-specific descriptor table first ..
37307c478bd9Sstevel@tonic-gate 		 */
37317c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(cyrix_ctab, *dp)) != NULL) {
37327c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
37337c478bd9Sstevel@tonic-gate 				break;
37347c478bd9Sstevel@tonic-gate 			continue;
37357c478bd9Sstevel@tonic-gate 		}
37367c478bd9Sstevel@tonic-gate 		/*
37377c478bd9Sstevel@tonic-gate 		 * .. else fall back to the Intel one
37387c478bd9Sstevel@tonic-gate 		 */
37397c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(intel_ctab, *dp)) != NULL) {
37407c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
37417c478bd9Sstevel@tonic-gate 				break;
37427c478bd9Sstevel@tonic-gate 			continue;
37437c478bd9Sstevel@tonic-gate 		}
37447c478bd9Sstevel@tonic-gate 	}
37457c478bd9Sstevel@tonic-gate }
37467c478bd9Sstevel@tonic-gate 
37477c478bd9Sstevel@tonic-gate /*
37487c478bd9Sstevel@tonic-gate  * A cacheinfo walker that adds associativity, line-size, and size properties
37497c478bd9Sstevel@tonic-gate  * to the devinfo node it is passed as an argument.
37507c478bd9Sstevel@tonic-gate  */
37517c478bd9Sstevel@tonic-gate static int
37527c478bd9Sstevel@tonic-gate add_cacheent_props(void *arg, const struct cachetab *ct)
37537c478bd9Sstevel@tonic-gate {
37547c478bd9Sstevel@tonic-gate 	dev_info_t *devi = arg;
37557c478bd9Sstevel@tonic-gate 
37567c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, assoc_str, ct->ct_assoc);
37577c478bd9Sstevel@tonic-gate 	if (ct->ct_line_size != 0)
37587c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, ct->ct_label, line_str,
37597c478bd9Sstevel@tonic-gate 		    ct->ct_line_size);
37607c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, size_str, ct->ct_size);
37617c478bd9Sstevel@tonic-gate 	return (0);
37627c478bd9Sstevel@tonic-gate }
37637c478bd9Sstevel@tonic-gate 
3764f1d742a9Sksadhukh 
37657c478bd9Sstevel@tonic-gate static const char fully_assoc[] = "fully-associative?";
37667c478bd9Sstevel@tonic-gate 
37677c478bd9Sstevel@tonic-gate /*
37687c478bd9Sstevel@tonic-gate  * AMD style cache/tlb description
37697c478bd9Sstevel@tonic-gate  *
37707c478bd9Sstevel@tonic-gate  * Extended functions 5 and 6 directly describe properties of
37717c478bd9Sstevel@tonic-gate  * tlbs and various cache levels.
37727c478bd9Sstevel@tonic-gate  */
37737c478bd9Sstevel@tonic-gate static void
37747c478bd9Sstevel@tonic-gate add_amd_assoc(dev_info_t *devi, const char *label, uint_t assoc)
37757c478bd9Sstevel@tonic-gate {
37767c478bd9Sstevel@tonic-gate 	switch (assoc) {
37777c478bd9Sstevel@tonic-gate 	case 0:	/* reserved; ignore */
37787c478bd9Sstevel@tonic-gate 		break;
37797c478bd9Sstevel@tonic-gate 	default:
37807c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
37817c478bd9Sstevel@tonic-gate 		break;
37827c478bd9Sstevel@tonic-gate 	case 0xff:
37837c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
37847c478bd9Sstevel@tonic-gate 		break;
37857c478bd9Sstevel@tonic-gate 	}
37867c478bd9Sstevel@tonic-gate }
37877c478bd9Sstevel@tonic-gate 
37887c478bd9Sstevel@tonic-gate static void
37897c478bd9Sstevel@tonic-gate add_amd_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
37907c478bd9Sstevel@tonic-gate {
37917c478bd9Sstevel@tonic-gate 	if (size == 0)
37927c478bd9Sstevel@tonic-gate 		return;
37937c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
37947c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
37957c478bd9Sstevel@tonic-gate }
37967c478bd9Sstevel@tonic-gate 
37977c478bd9Sstevel@tonic-gate static void
37987c478bd9Sstevel@tonic-gate add_amd_cache(dev_info_t *devi, const char *label,
37997c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
38007c478bd9Sstevel@tonic-gate {
38017c478bd9Sstevel@tonic-gate 	if (size == 0 || line_size == 0)
38027c478bd9Sstevel@tonic-gate 		return;
38037c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
38047c478bd9Sstevel@tonic-gate 	/*
38057c478bd9Sstevel@tonic-gate 	 * Most AMD parts have a sectored cache. Multiple cache lines are
38067c478bd9Sstevel@tonic-gate 	 * associated with each tag. A sector consists of all cache lines
38077c478bd9Sstevel@tonic-gate 	 * associated with a tag. For example, the AMD K6-III has a sector
38087c478bd9Sstevel@tonic-gate 	 * size of 2 cache lines per tag.
38097c478bd9Sstevel@tonic-gate 	 */
38107c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
38117c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
38127c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
38137c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
38147c478bd9Sstevel@tonic-gate }
38157c478bd9Sstevel@tonic-gate 
38167c478bd9Sstevel@tonic-gate static void
38177c478bd9Sstevel@tonic-gate add_amd_l2_assoc(dev_info_t *devi, const char *label, uint_t assoc)
38187c478bd9Sstevel@tonic-gate {
38197c478bd9Sstevel@tonic-gate 	switch (assoc) {
38207c478bd9Sstevel@tonic-gate 	case 0:	/* off */
38217c478bd9Sstevel@tonic-gate 		break;
38227c478bd9Sstevel@tonic-gate 	case 1:
38237c478bd9Sstevel@tonic-gate 	case 2:
38247c478bd9Sstevel@tonic-gate 	case 4:
38257c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
38267c478bd9Sstevel@tonic-gate 		break;
38277c478bd9Sstevel@tonic-gate 	case 6:
38287c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 8);
38297c478bd9Sstevel@tonic-gate 		break;
38307c478bd9Sstevel@tonic-gate 	case 8:
38317c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 16);
38327c478bd9Sstevel@tonic-gate 		break;
38337c478bd9Sstevel@tonic-gate 	case 0xf:
38347c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
38357c478bd9Sstevel@tonic-gate 		break;
38367c478bd9Sstevel@tonic-gate 	default: /* reserved; ignore */
38377c478bd9Sstevel@tonic-gate 		break;
38387c478bd9Sstevel@tonic-gate 	}
38397c478bd9Sstevel@tonic-gate }
38407c478bd9Sstevel@tonic-gate 
38417c478bd9Sstevel@tonic-gate static void
38427c478bd9Sstevel@tonic-gate add_amd_l2_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
38437c478bd9Sstevel@tonic-gate {
38447c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0)
38457c478bd9Sstevel@tonic-gate 		return;
38467c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
38477c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
38487c478bd9Sstevel@tonic-gate }
38497c478bd9Sstevel@tonic-gate 
38507c478bd9Sstevel@tonic-gate static void
38517c478bd9Sstevel@tonic-gate add_amd_l2_cache(dev_info_t *devi, const char *label,
38527c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
38537c478bd9Sstevel@tonic-gate {
38547c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0 || line_size == 0)
38557c478bd9Sstevel@tonic-gate 		return;
38567c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
38577c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
38587c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
38597c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
38607c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
38617c478bd9Sstevel@tonic-gate }
38627c478bd9Sstevel@tonic-gate 
38637c478bd9Sstevel@tonic-gate static void
38647c478bd9Sstevel@tonic-gate amd_cache_info(struct cpuid_info *cpi, dev_info_t *devi)
38657c478bd9Sstevel@tonic-gate {
38668949bcd6Sandrei 	struct cpuid_regs *cp;
38677c478bd9Sstevel@tonic-gate 
38687c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000005)
38697c478bd9Sstevel@tonic-gate 		return;
38707c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[5];
38717c478bd9Sstevel@tonic-gate 
38727c478bd9Sstevel@tonic-gate 	/*
38737c478bd9Sstevel@tonic-gate 	 * 4M/2M L1 TLB configuration
38747c478bd9Sstevel@tonic-gate 	 *
38757c478bd9Sstevel@tonic-gate 	 * We report the size for 2M pages because AMD uses two
38767c478bd9Sstevel@tonic-gate 	 * TLB entries for one 4M page.
38777c478bd9Sstevel@tonic-gate 	 */
38787c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "dtlb-2M",
38797c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 31, 24), BITX(cp->cp_eax, 23, 16));
38807c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "itlb-2M",
38817c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 15, 8), BITX(cp->cp_eax, 7, 0));
38827c478bd9Sstevel@tonic-gate 
38837c478bd9Sstevel@tonic-gate 	/*
38847c478bd9Sstevel@tonic-gate 	 * 4K L1 TLB configuration
38857c478bd9Sstevel@tonic-gate 	 */
38867c478bd9Sstevel@tonic-gate 
38877c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
38887c478bd9Sstevel@tonic-gate 		uint_t nentries;
38897c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
38907c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5) {
38917c478bd9Sstevel@tonic-gate 			/*
38927c478bd9Sstevel@tonic-gate 			 * Crusoe processors have 256 TLB entries, but
38937c478bd9Sstevel@tonic-gate 			 * cpuid data format constrains them to only
38947c478bd9Sstevel@tonic-gate 			 * reporting 255 of them.
38957c478bd9Sstevel@tonic-gate 			 */
38967c478bd9Sstevel@tonic-gate 			if ((nentries = BITX(cp->cp_ebx, 23, 16)) == 255)
38977c478bd9Sstevel@tonic-gate 				nentries = 256;
38987c478bd9Sstevel@tonic-gate 			/*
38997c478bd9Sstevel@tonic-gate 			 * Crusoe processors also have a unified TLB
39007c478bd9Sstevel@tonic-gate 			 */
39017c478bd9Sstevel@tonic-gate 			add_amd_tlb(devi, "tlb-4K", BITX(cp->cp_ebx, 31, 24),
39027c478bd9Sstevel@tonic-gate 			    nentries);
39037c478bd9Sstevel@tonic-gate 			break;
39047c478bd9Sstevel@tonic-gate 		}
39057c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
39067c478bd9Sstevel@tonic-gate 	default:
39077c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, itlb4k_str,
39087c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 31, 24), BITX(cp->cp_ebx, 23, 16));
39097c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, dtlb4k_str,
39107c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 15, 8), BITX(cp->cp_ebx, 7, 0));
39117c478bd9Sstevel@tonic-gate 		break;
39127c478bd9Sstevel@tonic-gate 	}
39137c478bd9Sstevel@tonic-gate 
39147c478bd9Sstevel@tonic-gate 	/*
39157c478bd9Sstevel@tonic-gate 	 * data L1 cache configuration
39167c478bd9Sstevel@tonic-gate 	 */
39177c478bd9Sstevel@tonic-gate 
39187c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_dcache_str,
39197c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 24), BITX(cp->cp_ecx, 23, 16),
39207c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 15, 8), BITX(cp->cp_ecx, 7, 0));
39217c478bd9Sstevel@tonic-gate 
39227c478bd9Sstevel@tonic-gate 	/*
39237c478bd9Sstevel@tonic-gate 	 * code L1 cache configuration
39247c478bd9Sstevel@tonic-gate 	 */
39257c478bd9Sstevel@tonic-gate 
39267c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_icache_str,
39277c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 31, 24), BITX(cp->cp_edx, 23, 16),
39287c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 15, 8), BITX(cp->cp_edx, 7, 0));
39297c478bd9Sstevel@tonic-gate 
39307c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
39317c478bd9Sstevel@tonic-gate 		return;
39327c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
39337c478bd9Sstevel@tonic-gate 
39347c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for large pages */
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_eax, 31, 16) == 0)
39377c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-2M",
39387c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
39397c478bd9Sstevel@tonic-gate 	else {
39407c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-2M",
39417c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
39427c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-2M",
39437c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
39447c478bd9Sstevel@tonic-gate 	}
39457c478bd9Sstevel@tonic-gate 
39467c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for 4K pages */
39477c478bd9Sstevel@tonic-gate 
39487c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_ebx, 31, 16) == 0) {
39497c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-4K",
39507c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
39517c478bd9Sstevel@tonic-gate 	} else {
39527c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-4K",
39537c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
39547c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-4K",
39557c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
39567c478bd9Sstevel@tonic-gate 	}
39577c478bd9Sstevel@tonic-gate 
39587c478bd9Sstevel@tonic-gate 	add_amd_l2_cache(devi, l2_cache_str,
39597c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 16), BITX(cp->cp_ecx, 15, 12),
39607c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 11, 8), BITX(cp->cp_ecx, 7, 0));
39617c478bd9Sstevel@tonic-gate }
39627c478bd9Sstevel@tonic-gate 
39637c478bd9Sstevel@tonic-gate /*
39647c478bd9Sstevel@tonic-gate  * There are two basic ways that the x86 world describes it cache
39657c478bd9Sstevel@tonic-gate  * and tlb architecture - Intel's way and AMD's way.
39667c478bd9Sstevel@tonic-gate  *
39677c478bd9Sstevel@tonic-gate  * Return which flavor of cache architecture we should use
39687c478bd9Sstevel@tonic-gate  */
39697c478bd9Sstevel@tonic-gate static int
39707c478bd9Sstevel@tonic-gate x86_which_cacheinfo(struct cpuid_info *cpi)
39717c478bd9Sstevel@tonic-gate {
39727c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
39737c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
39747c478bd9Sstevel@tonic-gate 		if (cpi->cpi_maxeax >= 2)
39757c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
39767c478bd9Sstevel@tonic-gate 		break;
39777c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
39787c478bd9Sstevel@tonic-gate 		/*
39797c478bd9Sstevel@tonic-gate 		 * The K5 model 1 was the first part from AMD that reported
39807c478bd9Sstevel@tonic-gate 		 * cache sizes via extended cpuid functions.
39817c478bd9Sstevel@tonic-gate 		 */
39827c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
39837c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
39847c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
39857c478bd9Sstevel@tonic-gate 		break;
39867c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
39877c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5)
39887c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
39897c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
39907c478bd9Sstevel@tonic-gate 	default:
39917c478bd9Sstevel@tonic-gate 		/*
39927c478bd9Sstevel@tonic-gate 		 * If they have extended CPU data for 0x80000005
39937c478bd9Sstevel@tonic-gate 		 * then we assume they have AMD-format cache
39947c478bd9Sstevel@tonic-gate 		 * information.
39957c478bd9Sstevel@tonic-gate 		 *
39967c478bd9Sstevel@tonic-gate 		 * If not, and the vendor happens to be Cyrix,
39977c478bd9Sstevel@tonic-gate 		 * then try our-Cyrix specific handler.
39987c478bd9Sstevel@tonic-gate 		 *
39997c478bd9Sstevel@tonic-gate 		 * If we're not Cyrix, then assume we're using Intel's
40007c478bd9Sstevel@tonic-gate 		 * table-driven format instead.
40017c478bd9Sstevel@tonic-gate 		 */
40027c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax >= 0x80000005)
40037c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
40047c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_vendor == X86_VENDOR_Cyrix)
40057c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Cyrix);
40067c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_maxeax >= 2)
40077c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
40087c478bd9Sstevel@tonic-gate 		break;
40097c478bd9Sstevel@tonic-gate 	}
40107c478bd9Sstevel@tonic-gate 	return (-1);
40117c478bd9Sstevel@tonic-gate }
40127c478bd9Sstevel@tonic-gate 
40137c478bd9Sstevel@tonic-gate void
4014fa96bd91SMichael Corcoran cpuid_set_cpu_properties(void *dip, processorid_t cpu_id,
4015fa96bd91SMichael Corcoran     struct cpuid_info *cpi)
40167c478bd9Sstevel@tonic-gate {
40177c478bd9Sstevel@tonic-gate 	dev_info_t *cpu_devi;
40187c478bd9Sstevel@tonic-gate 	int create;
40197c478bd9Sstevel@tonic-gate 
4020fa96bd91SMichael Corcoran 	cpu_devi = (dev_info_t *)dip;
40217c478bd9Sstevel@tonic-gate 
40227c478bd9Sstevel@tonic-gate 	/* device_type */
40237c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
40247c478bd9Sstevel@tonic-gate 	    "device_type", "cpu");
40257c478bd9Sstevel@tonic-gate 
40267c478bd9Sstevel@tonic-gate 	/* reg */
40277c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40287c478bd9Sstevel@tonic-gate 	    "reg", cpu_id);
40297c478bd9Sstevel@tonic-gate 
40307c478bd9Sstevel@tonic-gate 	/* cpu-mhz, and clock-frequency */
40317c478bd9Sstevel@tonic-gate 	if (cpu_freq > 0) {
40327c478bd9Sstevel@tonic-gate 		long long mul;
40337c478bd9Sstevel@tonic-gate 
40347c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40357c478bd9Sstevel@tonic-gate 		    "cpu-mhz", cpu_freq);
40367c478bd9Sstevel@tonic-gate 		if ((mul = cpu_freq * 1000000LL) <= INT_MAX)
40377c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40387c478bd9Sstevel@tonic-gate 			    "clock-frequency", (int)mul);
40397c478bd9Sstevel@tonic-gate 	}
40407c478bd9Sstevel@tonic-gate 
40417417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) {
40427c478bd9Sstevel@tonic-gate 		return;
40437c478bd9Sstevel@tonic-gate 	}
40447c478bd9Sstevel@tonic-gate 
40457c478bd9Sstevel@tonic-gate 	/* vendor-id */
40467c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
40477c478bd9Sstevel@tonic-gate 	    "vendor-id", cpi->cpi_vendorstr);
40487c478bd9Sstevel@tonic-gate 
40497c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax == 0) {
40507c478bd9Sstevel@tonic-gate 		return;
40517c478bd9Sstevel@tonic-gate 	}
40527c478bd9Sstevel@tonic-gate 
40537c478bd9Sstevel@tonic-gate 	/*
40547c478bd9Sstevel@tonic-gate 	 * family, model, and step
40557c478bd9Sstevel@tonic-gate 	 */
40567c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40577c478bd9Sstevel@tonic-gate 	    "family", CPI_FAMILY(cpi));
40587c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40597c478bd9Sstevel@tonic-gate 	    "cpu-model", CPI_MODEL(cpi));
40607c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40617c478bd9Sstevel@tonic-gate 	    "stepping-id", CPI_STEP(cpi));
40627c478bd9Sstevel@tonic-gate 
40637c478bd9Sstevel@tonic-gate 	/* type */
40647c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40657c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
40667c478bd9Sstevel@tonic-gate 		create = 1;
40677c478bd9Sstevel@tonic-gate 		break;
40687c478bd9Sstevel@tonic-gate 	default:
40697c478bd9Sstevel@tonic-gate 		create = 0;
40707c478bd9Sstevel@tonic-gate 		break;
40717c478bd9Sstevel@tonic-gate 	}
40727c478bd9Sstevel@tonic-gate 	if (create)
40737c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40747c478bd9Sstevel@tonic-gate 		    "type", CPI_TYPE(cpi));
40757c478bd9Sstevel@tonic-gate 
40767c478bd9Sstevel@tonic-gate 	/* ext-family */
40777c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40787c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
40797c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
40807c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
40817c478bd9Sstevel@tonic-gate 		break;
40827c478bd9Sstevel@tonic-gate 	default:
40837c478bd9Sstevel@tonic-gate 		create = 0;
40847c478bd9Sstevel@tonic-gate 		break;
40857c478bd9Sstevel@tonic-gate 	}
40867c478bd9Sstevel@tonic-gate 	if (create)
40877c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40887c478bd9Sstevel@tonic-gate 		    "ext-family", CPI_FAMILY_XTD(cpi));
40897c478bd9Sstevel@tonic-gate 
40907c478bd9Sstevel@tonic-gate 	/* ext-model */
40917c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40927c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
409363d3f7dfSkk208521 		create = IS_EXTENDED_MODEL_INTEL(cpi);
409468c91426Sdmick 		break;
40957c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
4096ee88d2b9Skchow 		create = CPI_FAMILY(cpi) == 0xf;
40977c478bd9Sstevel@tonic-gate 		break;
40987c478bd9Sstevel@tonic-gate 	default:
40997c478bd9Sstevel@tonic-gate 		create = 0;
41007c478bd9Sstevel@tonic-gate 		break;
41017c478bd9Sstevel@tonic-gate 	}
41027c478bd9Sstevel@tonic-gate 	if (create)
41037c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41047c478bd9Sstevel@tonic-gate 		    "ext-model", CPI_MODEL_XTD(cpi));
41057c478bd9Sstevel@tonic-gate 
41067c478bd9Sstevel@tonic-gate 	/* generation */
41077c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41087c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41097c478bd9Sstevel@tonic-gate 		/*
41107c478bd9Sstevel@tonic-gate 		 * AMD K5 model 1 was the first part to support this
41117c478bd9Sstevel@tonic-gate 		 */
41127c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
41137c478bd9Sstevel@tonic-gate 		break;
41147c478bd9Sstevel@tonic-gate 	default:
41157c478bd9Sstevel@tonic-gate 		create = 0;
41167c478bd9Sstevel@tonic-gate 		break;
41177c478bd9Sstevel@tonic-gate 	}
41187c478bd9Sstevel@tonic-gate 	if (create)
41197c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41207c478bd9Sstevel@tonic-gate 		    "generation", BITX((cpi)->cpi_extd[1].cp_eax, 11, 8));
41217c478bd9Sstevel@tonic-gate 
41227c478bd9Sstevel@tonic-gate 	/* brand-id */
41237c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41247c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41257c478bd9Sstevel@tonic-gate 		/*
41267c478bd9Sstevel@tonic-gate 		 * brand id first appeared on Pentium III Xeon model 8,
41277c478bd9Sstevel@tonic-gate 		 * and Celeron model 8 processors and Opteron
41287c478bd9Sstevel@tonic-gate 		 */
41297c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family > 6 ||
41307c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 6 && cpi->cpi_model >= 8);
41317c478bd9Sstevel@tonic-gate 		break;
41327c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41337c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
41347c478bd9Sstevel@tonic-gate 		break;
41357c478bd9Sstevel@tonic-gate 	default:
41367c478bd9Sstevel@tonic-gate 		create = 0;
41377c478bd9Sstevel@tonic-gate 		break;
41387c478bd9Sstevel@tonic-gate 	}
41397c478bd9Sstevel@tonic-gate 	if (create && cpi->cpi_brandid != 0) {
41407c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41417c478bd9Sstevel@tonic-gate 		    "brand-id", cpi->cpi_brandid);
41427c478bd9Sstevel@tonic-gate 	}
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate 	/* chunks, and apic-id */
41457c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41467c478bd9Sstevel@tonic-gate 		/*
41477c478bd9Sstevel@tonic-gate 		 * first available on Pentium IV and Opteron (K8)
41487c478bd9Sstevel@tonic-gate 		 */
41495ff02082Sdmick 	case X86_VENDOR_Intel:
41505ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
41515ff02082Sdmick 		break;
41525ff02082Sdmick 	case X86_VENDOR_AMD:
41537c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
41547c478bd9Sstevel@tonic-gate 		break;
41557c478bd9Sstevel@tonic-gate 	default:
41567c478bd9Sstevel@tonic-gate 		create = 0;
41577c478bd9Sstevel@tonic-gate 		break;
41587c478bd9Sstevel@tonic-gate 	}
41597c478bd9Sstevel@tonic-gate 	if (create) {
41607c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41617c478bd9Sstevel@tonic-gate 		    "chunks", CPI_CHUNKS(cpi));
41627c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
4163b6917abeSmishra 		    "apic-id", cpi->cpi_apicid);
41647aec1d6eScindi 		if (cpi->cpi_chipid >= 0) {
41657c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41667c478bd9Sstevel@tonic-gate 			    "chip#", cpi->cpi_chipid);
41677aec1d6eScindi 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41687aec1d6eScindi 			    "clog#", cpi->cpi_clogid);
41697aec1d6eScindi 		}
41707c478bd9Sstevel@tonic-gate 	}
41717c478bd9Sstevel@tonic-gate 
41727c478bd9Sstevel@tonic-gate 	/* cpuid-features */
41737c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41747c478bd9Sstevel@tonic-gate 	    "cpuid-features", CPI_FEATURES_EDX(cpi));
41757c478bd9Sstevel@tonic-gate 
41767c478bd9Sstevel@tonic-gate 
41777c478bd9Sstevel@tonic-gate 	/* cpuid-features-ecx */
41787c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41797c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41805ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
41817c478bd9Sstevel@tonic-gate 		break;
418263408480SHans Rosenfeld 	case X86_VENDOR_AMD:
418363408480SHans Rosenfeld 		create = cpi->cpi_family >= 0xf;
418463408480SHans Rosenfeld 		break;
41857c478bd9Sstevel@tonic-gate 	default:
41867c478bd9Sstevel@tonic-gate 		create = 0;
41877c478bd9Sstevel@tonic-gate 		break;
41887c478bd9Sstevel@tonic-gate 	}
41897c478bd9Sstevel@tonic-gate 	if (create)
41907c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41917c478bd9Sstevel@tonic-gate 		    "cpuid-features-ecx", CPI_FEATURES_ECX(cpi));
41927c478bd9Sstevel@tonic-gate 
41937c478bd9Sstevel@tonic-gate 	/* ext-cpuid-features */
41947c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41955ff02082Sdmick 	case X86_VENDOR_Intel:
41967c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41977c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
41987c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
41997c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
42007c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
42017c478bd9Sstevel@tonic-gate 		break;
42027c478bd9Sstevel@tonic-gate 	default:
42037c478bd9Sstevel@tonic-gate 		create = 0;
42047c478bd9Sstevel@tonic-gate 		break;
42057c478bd9Sstevel@tonic-gate 	}
42065ff02082Sdmick 	if (create) {
42077c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42087c478bd9Sstevel@tonic-gate 		    "ext-cpuid-features", CPI_FEATURES_XTD_EDX(cpi));
42095ff02082Sdmick 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42105ff02082Sdmick 		    "ext-cpuid-features-ecx", CPI_FEATURES_XTD_ECX(cpi));
42115ff02082Sdmick 	}
42127c478bd9Sstevel@tonic-gate 
42137c478bd9Sstevel@tonic-gate 	/*
42147c478bd9Sstevel@tonic-gate 	 * Brand String first appeared in Intel Pentium IV, AMD K5
42157c478bd9Sstevel@tonic-gate 	 * model 1, and Cyrix GXm.  On earlier models we try and
42167c478bd9Sstevel@tonic-gate 	 * simulate something similar .. so this string should always
42177c478bd9Sstevel@tonic-gate 	 * same -something- about the processor, however lame.
42187c478bd9Sstevel@tonic-gate 	 */
42197c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
42207c478bd9Sstevel@tonic-gate 	    "brand-string", cpi->cpi_brandstr);
42217c478bd9Sstevel@tonic-gate 
42227c478bd9Sstevel@tonic-gate 	/*
42237c478bd9Sstevel@tonic-gate 	 * Finally, cache and tlb information
42247c478bd9Sstevel@tonic-gate 	 */
42257c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
42267c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
42277c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
42287c478bd9Sstevel@tonic-gate 		break;
42297c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
42307c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
42317c478bd9Sstevel@tonic-gate 		break;
42327c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
42337c478bd9Sstevel@tonic-gate 		amd_cache_info(cpi, cpu_devi);
42347c478bd9Sstevel@tonic-gate 		break;
42357c478bd9Sstevel@tonic-gate 	default:
42367c478bd9Sstevel@tonic-gate 		break;
42377c478bd9Sstevel@tonic-gate 	}
42387c478bd9Sstevel@tonic-gate }
42397c478bd9Sstevel@tonic-gate 
42407c478bd9Sstevel@tonic-gate struct l2info {
42417c478bd9Sstevel@tonic-gate 	int *l2i_csz;
42427c478bd9Sstevel@tonic-gate 	int *l2i_lsz;
42437c478bd9Sstevel@tonic-gate 	int *l2i_assoc;
42447c478bd9Sstevel@tonic-gate 	int l2i_ret;
42457c478bd9Sstevel@tonic-gate };
42467c478bd9Sstevel@tonic-gate 
42477c478bd9Sstevel@tonic-gate /*
42487c478bd9Sstevel@tonic-gate  * A cacheinfo walker that fetches the size, line-size and associativity
42497c478bd9Sstevel@tonic-gate  * of the L2 cache
42507c478bd9Sstevel@tonic-gate  */
42517c478bd9Sstevel@tonic-gate static int
42527c478bd9Sstevel@tonic-gate intel_l2cinfo(void *arg, const struct cachetab *ct)
42537c478bd9Sstevel@tonic-gate {
42547c478bd9Sstevel@tonic-gate 	struct l2info *l2i = arg;
42557c478bd9Sstevel@tonic-gate 	int *ip;
42567c478bd9Sstevel@tonic-gate 
42577c478bd9Sstevel@tonic-gate 	if (ct->ct_label != l2_cache_str &&
42587c478bd9Sstevel@tonic-gate 	    ct->ct_label != sl2_cache_str)
42597c478bd9Sstevel@tonic-gate 		return (0);	/* not an L2 -- keep walking */
42607c478bd9Sstevel@tonic-gate 
42617c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_csz) != NULL)
42627c478bd9Sstevel@tonic-gate 		*ip = ct->ct_size;
42637c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_lsz) != NULL)
42647c478bd9Sstevel@tonic-gate 		*ip = ct->ct_line_size;
42657c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_assoc) != NULL)
42667c478bd9Sstevel@tonic-gate 		*ip = ct->ct_assoc;
42677c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = ct->ct_size;
42687c478bd9Sstevel@tonic-gate 	return (1);		/* was an L2 -- terminate walk */
42697c478bd9Sstevel@tonic-gate }
42707c478bd9Sstevel@tonic-gate 
4271606303c9Skchow /*
4272606303c9Skchow  * AMD L2/L3 Cache and TLB Associativity Field Definition:
4273606303c9Skchow  *
4274606303c9Skchow  *	Unlike the associativity for the L1 cache and tlb where the 8 bit
4275606303c9Skchow  *	value is the associativity, the associativity for the L2 cache and
4276606303c9Skchow  *	tlb is encoded in the following table. The 4 bit L2 value serves as
4277606303c9Skchow  *	an index into the amd_afd[] array to determine the associativity.
4278606303c9Skchow  *	-1 is undefined. 0 is fully associative.
4279606303c9Skchow  */
4280606303c9Skchow 
4281606303c9Skchow static int amd_afd[] =
4282606303c9Skchow 	{-1, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, 0};
4283606303c9Skchow 
42847c478bd9Sstevel@tonic-gate static void
42857c478bd9Sstevel@tonic-gate amd_l2cacheinfo(struct cpuid_info *cpi, struct l2info *l2i)
42867c478bd9Sstevel@tonic-gate {
42878949bcd6Sandrei 	struct cpuid_regs *cp;
42887c478bd9Sstevel@tonic-gate 	uint_t size, assoc;
4289606303c9Skchow 	int i;
42907c478bd9Sstevel@tonic-gate 	int *ip;
42917c478bd9Sstevel@tonic-gate 
42927c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
42937c478bd9Sstevel@tonic-gate 		return;
42947c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
42957c478bd9Sstevel@tonic-gate 
4296606303c9Skchow 	if ((i = BITX(cp->cp_ecx, 15, 12)) != 0 &&
42977c478bd9Sstevel@tonic-gate 	    (size = BITX(cp->cp_ecx, 31, 16)) != 0) {
42987c478bd9Sstevel@tonic-gate 		uint_t cachesz = size * 1024;
4299606303c9Skchow 		assoc = amd_afd[i];
43007c478bd9Sstevel@tonic-gate 
4301606303c9Skchow 		ASSERT(assoc != -1);
43027c478bd9Sstevel@tonic-gate 
43037c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_csz) != NULL)
43047c478bd9Sstevel@tonic-gate 			*ip = cachesz;
43057c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_lsz) != NULL)
43067c478bd9Sstevel@tonic-gate 			*ip = BITX(cp->cp_ecx, 7, 0);
43077c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_assoc) != NULL)
43087c478bd9Sstevel@tonic-gate 			*ip = assoc;
43097c478bd9Sstevel@tonic-gate 		l2i->l2i_ret = cachesz;
43107c478bd9Sstevel@tonic-gate 	}
43117c478bd9Sstevel@tonic-gate }
43127c478bd9Sstevel@tonic-gate 
43137c478bd9Sstevel@tonic-gate int
43147c478bd9Sstevel@tonic-gate getl2cacheinfo(cpu_t *cpu, int *csz, int *lsz, int *assoc)
43157c478bd9Sstevel@tonic-gate {
43167c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
43177c478bd9Sstevel@tonic-gate 	struct l2info __l2info, *l2i = &__l2info;
43187c478bd9Sstevel@tonic-gate 
43197c478bd9Sstevel@tonic-gate 	l2i->l2i_csz = csz;
43207c478bd9Sstevel@tonic-gate 	l2i->l2i_lsz = lsz;
43217c478bd9Sstevel@tonic-gate 	l2i->l2i_assoc = assoc;
43227c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = -1;
43237c478bd9Sstevel@tonic-gate 
43247c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
43257c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
43267c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
43277c478bd9Sstevel@tonic-gate 		break;
43287c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
43297c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
43307c478bd9Sstevel@tonic-gate 		break;
43317c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
43327c478bd9Sstevel@tonic-gate 		amd_l2cacheinfo(cpi, l2i);
43337c478bd9Sstevel@tonic-gate 		break;
43347c478bd9Sstevel@tonic-gate 	default:
43357c478bd9Sstevel@tonic-gate 		break;
43367c478bd9Sstevel@tonic-gate 	}
43377c478bd9Sstevel@tonic-gate 	return (l2i->l2i_ret);
43387c478bd9Sstevel@tonic-gate }
4339f98fbcecSbholler 
4340843e1988Sjohnlev #if !defined(__xpv)
4341843e1988Sjohnlev 
43425b8a6efeSbholler uint32_t *
43435b8a6efeSbholler cpuid_mwait_alloc(cpu_t *cpu)
43445b8a6efeSbholler {
43455b8a6efeSbholler 	uint32_t	*ret;
43465b8a6efeSbholler 	size_t		mwait_size;
43475b8a6efeSbholler 
4348a3114836SGerry Liu 	ASSERT(cpuid_checkpass(CPU, 2));
43495b8a6efeSbholler 
4350a3114836SGerry Liu 	mwait_size = CPU->cpu_m.mcpu_cpi->cpi_mwait.mon_max;
43515b8a6efeSbholler 	if (mwait_size == 0)
43525b8a6efeSbholler 		return (NULL);
43535b8a6efeSbholler 
43545b8a6efeSbholler 	/*
43555b8a6efeSbholler 	 * kmem_alloc() returns cache line size aligned data for mwait_size
43565b8a6efeSbholler 	 * allocations.  mwait_size is currently cache line sized.  Neither
43575b8a6efeSbholler 	 * of these implementation details are guarantied to be true in the
43585b8a6efeSbholler 	 * future.
43595b8a6efeSbholler 	 *
43605b8a6efeSbholler 	 * First try allocating mwait_size as kmem_alloc() currently returns
43615b8a6efeSbholler 	 * correctly aligned memory.  If kmem_alloc() does not return
43625b8a6efeSbholler 	 * mwait_size aligned memory, then use mwait_size ROUNDUP.
43635b8a6efeSbholler 	 *
43645b8a6efeSbholler 	 * Set cpi_mwait.buf_actual and cpi_mwait.size_actual in case we
43655b8a6efeSbholler 	 * decide to free this memory.
43665b8a6efeSbholler 	 */
43675b8a6efeSbholler 	ret = kmem_zalloc(mwait_size, KM_SLEEP);
43685b8a6efeSbholler 	if (ret == (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size)) {
43695b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
43705b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size;
43715b8a6efeSbholler 		*ret = MWAIT_RUNNING;
43725b8a6efeSbholler 		return (ret);
43735b8a6efeSbholler 	} else {
43745b8a6efeSbholler 		kmem_free(ret, mwait_size);
43755b8a6efeSbholler 		ret = kmem_zalloc(mwait_size * 2, KM_SLEEP);
43765b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
43775b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size * 2;
43785b8a6efeSbholler 		ret = (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size);
43795b8a6efeSbholler 		*ret = MWAIT_RUNNING;
43805b8a6efeSbholler 		return (ret);
43815b8a6efeSbholler 	}
43825b8a6efeSbholler }
43835b8a6efeSbholler 
43845b8a6efeSbholler void
43855b8a6efeSbholler cpuid_mwait_free(cpu_t *cpu)
4386f98fbcecSbholler {
4387a3114836SGerry Liu 	if (cpu->cpu_m.mcpu_cpi == NULL) {
4388a3114836SGerry Liu 		return;
4389a3114836SGerry Liu 	}
43905b8a6efeSbholler 
43915b8a6efeSbholler 	if (cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual != NULL &&
43925b8a6efeSbholler 	    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual > 0) {
43935b8a6efeSbholler 		kmem_free(cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual,
43945b8a6efeSbholler 		    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual);
43955b8a6efeSbholler 	}
43965b8a6efeSbholler 
43975b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = NULL;
43985b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = 0;
4399f98fbcecSbholler }
4400843e1988Sjohnlev 
4401247dbb3dSsudheer void
4402247dbb3dSsudheer patch_tsc_read(int flag)
4403247dbb3dSsudheer {
4404247dbb3dSsudheer 	size_t cnt;
4405e4b86885SCheng Sean Ye 
4406247dbb3dSsudheer 	switch (flag) {
4407247dbb3dSsudheer 	case X86_NO_TSC:
4408247dbb3dSsudheer 		cnt = &_no_rdtsc_end - &_no_rdtsc_start;
44092b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt);
4410247dbb3dSsudheer 		break;
4411247dbb3dSsudheer 	case X86_HAVE_TSCP:
4412247dbb3dSsudheer 		cnt = &_tscp_end - &_tscp_start;
44132b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt);
4414247dbb3dSsudheer 		break;
4415247dbb3dSsudheer 	case X86_TSC_MFENCE:
4416247dbb3dSsudheer 		cnt = &_tsc_mfence_end - &_tsc_mfence_start;
44172b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read,
44182b0bcb26Ssudheer 		    (void *)&_tsc_mfence_start, cnt);
4419247dbb3dSsudheer 		break;
442015363b27Ssudheer 	case X86_TSC_LFENCE:
442115363b27Ssudheer 		cnt = &_tsc_lfence_end - &_tsc_lfence_start;
442215363b27Ssudheer 		(void) memcpy((void *)tsc_read,
442315363b27Ssudheer 		    (void *)&_tsc_lfence_start, cnt);
442415363b27Ssudheer 		break;
4425247dbb3dSsudheer 	default:
4426247dbb3dSsudheer 		break;
4427247dbb3dSsudheer 	}
4428247dbb3dSsudheer }
4429247dbb3dSsudheer 
44300e751525SEric Saxe int
44310e751525SEric Saxe cpuid_deep_cstates_supported(void)
44320e751525SEric Saxe {
44330e751525SEric Saxe 	struct cpuid_info *cpi;
44340e751525SEric Saxe 	struct cpuid_regs regs;
44350e751525SEric Saxe 
44360e751525SEric Saxe 	ASSERT(cpuid_checkpass(CPU, 1));
44370e751525SEric Saxe 
44380e751525SEric Saxe 	cpi = CPU->cpu_m.mcpu_cpi;
44390e751525SEric Saxe 
44407417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID))
44410e751525SEric Saxe 		return (0);
44420e751525SEric Saxe 
44430e751525SEric Saxe 	switch (cpi->cpi_vendor) {
44440e751525SEric Saxe 	case X86_VENDOR_Intel:
44450e751525SEric Saxe 		if (cpi->cpi_xmaxeax < 0x80000007)
44460e751525SEric Saxe 			return (0);
44470e751525SEric Saxe 
44480e751525SEric Saxe 		/*
44490e751525SEric Saxe 		 * TSC run at a constant rate in all ACPI C-states?
44500e751525SEric Saxe 		 */
44510e751525SEric Saxe 		regs.cp_eax = 0x80000007;
44520e751525SEric Saxe 		(void) __cpuid_insn(&regs);
44530e751525SEric Saxe 		return (regs.cp_edx & CPUID_TSC_CSTATE_INVARIANCE);
44540e751525SEric Saxe 
44550e751525SEric Saxe 	default:
44560e751525SEric Saxe 		return (0);
44570e751525SEric Saxe 	}
44580e751525SEric Saxe }
44590e751525SEric Saxe 
4460e774b42bSBill Holler #endif	/* !__xpv */
4461e774b42bSBill Holler 
4462e774b42bSBill Holler void
4463e774b42bSBill Holler post_startup_cpu_fixups(void)
4464e774b42bSBill Holler {
4465e774b42bSBill Holler #ifndef __xpv
4466e774b42bSBill Holler 	/*
4467e774b42bSBill Holler 	 * Some AMD processors support C1E state. Entering this state will
4468e774b42bSBill Holler 	 * cause the local APIC timer to stop, which we can't deal with at
4469e774b42bSBill Holler 	 * this time.
4470e774b42bSBill Holler 	 */
4471e774b42bSBill Holler 	if (cpuid_getvendor(CPU) == X86_VENDOR_AMD) {
4472e774b42bSBill Holler 		on_trap_data_t otd;
4473e774b42bSBill Holler 		uint64_t reg;
4474e774b42bSBill Holler 
4475e774b42bSBill Holler 		if (!on_trap(&otd, OT_DATA_ACCESS)) {
4476e774b42bSBill Holler 			reg = rdmsr(MSR_AMD_INT_PENDING_CMP_HALT);
4477e774b42bSBill Holler 			/* Disable C1E state if it is enabled by BIOS */
4478e774b42bSBill Holler 			if ((reg >> AMD_ACTONCMPHALT_SHIFT) &
4479e774b42bSBill Holler 			    AMD_ACTONCMPHALT_MASK) {
4480e774b42bSBill Holler 				reg &= ~(AMD_ACTONCMPHALT_MASK <<
4481e774b42bSBill Holler 				    AMD_ACTONCMPHALT_SHIFT);
4482e774b42bSBill Holler 				wrmsr(MSR_AMD_INT_PENDING_CMP_HALT, reg);
4483e774b42bSBill Holler 			}
4484e774b42bSBill Holler 		}
4485e774b42bSBill Holler 		no_trap();
4486e774b42bSBill Holler 	}
4487e774b42bSBill Holler #endif	/* !__xpv */
4488e774b42bSBill Holler }
4489e774b42bSBill Holler 
4490cef70d2cSBill Holler /*
44917af88ac7SKuriakose Kuruvilla  * Setup necessary registers to enable XSAVE feature on this processor.
44927af88ac7SKuriakose Kuruvilla  * This function needs to be called early enough, so that no xsave/xrstor
44937af88ac7SKuriakose Kuruvilla  * ops will execute on the processor before the MSRs are properly set up.
44947af88ac7SKuriakose Kuruvilla  *
44957af88ac7SKuriakose Kuruvilla  * Current implementation has the following assumption:
44967af88ac7SKuriakose Kuruvilla  * - cpuid_pass1() is done, so that X86 features are known.
44977af88ac7SKuriakose Kuruvilla  * - fpu_probe() is done, so that fp_save_mech is chosen.
44987af88ac7SKuriakose Kuruvilla  */
44997af88ac7SKuriakose Kuruvilla void
45007af88ac7SKuriakose Kuruvilla xsave_setup_msr(cpu_t *cpu)
45017af88ac7SKuriakose Kuruvilla {
45027af88ac7SKuriakose Kuruvilla 	ASSERT(fp_save_mech == FP_XSAVE);
45037af88ac7SKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
45047af88ac7SKuriakose Kuruvilla 
45057af88ac7SKuriakose Kuruvilla 	/* Enable OSXSAVE in CR4. */
45067af88ac7SKuriakose Kuruvilla 	setcr4(getcr4() | CR4_OSXSAVE);
45077af88ac7SKuriakose Kuruvilla 	/*
45087af88ac7SKuriakose Kuruvilla 	 * Update SW copy of ECX, so that /dev/cpu/self/cpuid will report
45097af88ac7SKuriakose Kuruvilla 	 * correct value.
45107af88ac7SKuriakose Kuruvilla 	 */
45117af88ac7SKuriakose Kuruvilla 	cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_ecx |= CPUID_INTC_ECX_OSXSAVE;
45127af88ac7SKuriakose Kuruvilla 	setup_xfem();
45137af88ac7SKuriakose Kuruvilla }
45147af88ac7SKuriakose Kuruvilla 
45157af88ac7SKuriakose Kuruvilla /*
4516cef70d2cSBill Holler  * Starting with the Westmere processor the local
4517cef70d2cSBill Holler  * APIC timer will continue running in all C-states,
4518cef70d2cSBill Holler  * including the deepest C-states.
4519cef70d2cSBill Holler  */
4520cef70d2cSBill Holler int
4521cef70d2cSBill Holler cpuid_arat_supported(void)
4522cef70d2cSBill Holler {
4523cef70d2cSBill Holler 	struct cpuid_info *cpi;
4524cef70d2cSBill Holler 	struct cpuid_regs regs;
4525cef70d2cSBill Holler 
4526cef70d2cSBill Holler 	ASSERT(cpuid_checkpass(CPU, 1));
45277417cfdeSKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
4528cef70d2cSBill Holler 
4529cef70d2cSBill Holler 	cpi = CPU->cpu_m.mcpu_cpi;
4530cef70d2cSBill Holler 
4531cef70d2cSBill Holler 	switch (cpi->cpi_vendor) {
4532cef70d2cSBill Holler 	case X86_VENDOR_Intel:
4533cef70d2cSBill Holler 		/*
4534cef70d2cSBill Holler 		 * Always-running Local APIC Timer is
4535cef70d2cSBill Holler 		 * indicated by CPUID.6.EAX[2].
4536cef70d2cSBill Holler 		 */
4537cef70d2cSBill Holler 		if (cpi->cpi_maxeax >= 6) {
4538cef70d2cSBill Holler 			regs.cp_eax = 6;
4539cef70d2cSBill Holler 			(void) cpuid_insn(NULL, &regs);
4540cef70d2cSBill Holler 			return (regs.cp_eax & CPUID_CSTATE_ARAT);
4541cef70d2cSBill Holler 		} else {
4542cef70d2cSBill Holler 			return (0);
4543cef70d2cSBill Holler 		}
4544cef70d2cSBill Holler 	default:
4545cef70d2cSBill Holler 		return (0);
4546cef70d2cSBill Holler 	}
4547cef70d2cSBill Holler }
4548cef70d2cSBill Holler 
4549f21ed392Saubrey.li@intel.com /*
4550f21ed392Saubrey.li@intel.com  * Check support for Intel ENERGY_PERF_BIAS feature
4551f21ed392Saubrey.li@intel.com  */
4552f21ed392Saubrey.li@intel.com int
4553f21ed392Saubrey.li@intel.com cpuid_iepb_supported(struct cpu *cp)
4554f21ed392Saubrey.li@intel.com {
4555f21ed392Saubrey.li@intel.com 	struct cpuid_info *cpi = cp->cpu_m.mcpu_cpi;
4556f21ed392Saubrey.li@intel.com 	struct cpuid_regs regs;
4557f21ed392Saubrey.li@intel.com 
4558f21ed392Saubrey.li@intel.com 	ASSERT(cpuid_checkpass(cp, 1));
4559f21ed392Saubrey.li@intel.com 
45607417cfdeSKuriakose Kuruvilla 	if (!(is_x86_feature(x86_featureset, X86FSET_CPUID)) ||
45617417cfdeSKuriakose Kuruvilla 	    !(is_x86_feature(x86_featureset, X86FSET_MSR))) {
4562f21ed392Saubrey.li@intel.com 		return (0);
4563f21ed392Saubrey.li@intel.com 	}
4564f21ed392Saubrey.li@intel.com 
4565f21ed392Saubrey.li@intel.com 	/*
4566f21ed392Saubrey.li@intel.com 	 * Intel ENERGY_PERF_BIAS MSR is indicated by
4567f21ed392Saubrey.li@intel.com 	 * capability bit CPUID.6.ECX.3
4568f21ed392Saubrey.li@intel.com 	 */
4569f21ed392Saubrey.li@intel.com 	if ((cpi->cpi_vendor != X86_VENDOR_Intel) || (cpi->cpi_maxeax < 6))
4570f21ed392Saubrey.li@intel.com 		return (0);
4571f21ed392Saubrey.li@intel.com 
4572f21ed392Saubrey.li@intel.com 	regs.cp_eax = 0x6;
4573f21ed392Saubrey.li@intel.com 	(void) cpuid_insn(NULL, &regs);
4574f21ed392Saubrey.li@intel.com 	return (regs.cp_ecx & CPUID_EPB_SUPPORT);
4575f21ed392Saubrey.li@intel.com }
4576f21ed392Saubrey.li@intel.com 
457741afdfa7SKrishnendu Sadhukhan - Sun Microsystems /*
457841afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Check support for TSC deadline timer
457941afdfa7SKrishnendu Sadhukhan - Sun Microsystems  *
458041afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * TSC deadline timer provides a superior software programming
458141afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * model over local APIC timer that eliminates "time drifts".
458241afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Instead of specifying a relative time, software specifies an
458341afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * absolute time as the target at which the processor should
458441afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * generate a timer event.
458541afdfa7SKrishnendu Sadhukhan - Sun Microsystems  */
458641afdfa7SKrishnendu Sadhukhan - Sun Microsystems int
458741afdfa7SKrishnendu Sadhukhan - Sun Microsystems cpuid_deadline_tsc_supported(void)
458841afdfa7SKrishnendu Sadhukhan - Sun Microsystems {
458941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	struct cpuid_info *cpi = CPU->cpu_m.mcpu_cpi;
459041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	struct cpuid_regs regs;
459141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
459241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	ASSERT(cpuid_checkpass(CPU, 1));
459341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
459441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
459541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	switch (cpi->cpi_vendor) {
459641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	case X86_VENDOR_Intel:
459741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		if (cpi->cpi_maxeax >= 1) {
459841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			regs.cp_eax = 1;
459941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			(void) cpuid_insn(NULL, &regs);
460041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			return (regs.cp_ecx & CPUID_DEADLINE_TSC);
460141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		} else {
460241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			return (0);
460341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		}
460441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	default:
460541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		return (0);
460641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	}
460741afdfa7SKrishnendu Sadhukhan - Sun Microsystems }
460841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
460922cc0e45SBill Holler #if defined(__amd64) && !defined(__xpv)
461022cc0e45SBill Holler /*
461122cc0e45SBill Holler  * Patch in versions of bcopy for high performance Intel Nhm processors
461222cc0e45SBill Holler  * and later...
461322cc0e45SBill Holler  */
461422cc0e45SBill Holler void
461522cc0e45SBill Holler patch_memops(uint_t vendor)
461622cc0e45SBill Holler {
461722cc0e45SBill Holler 	size_t cnt, i;
461822cc0e45SBill Holler 	caddr_t to, from;
461922cc0e45SBill Holler 
46207417cfdeSKuriakose Kuruvilla 	if ((vendor == X86_VENDOR_Intel) &&
46217417cfdeSKuriakose Kuruvilla 	    is_x86_feature(x86_featureset, X86FSET_SSE4_2)) {
462222cc0e45SBill Holler 		cnt = &bcopy_patch_end - &bcopy_patch_start;
462322cc0e45SBill Holler 		to = &bcopy_ck_size;
462422cc0e45SBill Holler 		from = &bcopy_patch_start;
462522cc0e45SBill Holler 		for (i = 0; i < cnt; i++) {
462622cc0e45SBill Holler 			*to++ = *from++;
462722cc0e45SBill Holler 		}
462822cc0e45SBill Holler 	}
462922cc0e45SBill Holler }
463022cc0e45SBill Holler #endif  /* __amd64 && !__xpv */
46312d2efdc6SVuong Nguyen 
46322d2efdc6SVuong Nguyen /*
46332d2efdc6SVuong Nguyen  * This function finds the number of bits to represent the number of cores per
46342d2efdc6SVuong Nguyen  * chip and the number of strands per core for the Intel platforms.
46352d2efdc6SVuong Nguyen  * It re-uses the x2APIC cpuid code of the cpuid_pass2().
46362d2efdc6SVuong Nguyen  */
46372d2efdc6SVuong Nguyen void
46382d2efdc6SVuong Nguyen cpuid_get_ext_topo(uint_t vendor, uint_t *core_nbits, uint_t *strand_nbits)
46392d2efdc6SVuong Nguyen {
46402d2efdc6SVuong Nguyen 	struct cpuid_regs regs;
46412d2efdc6SVuong Nguyen 	struct cpuid_regs *cp = &regs;
46422d2efdc6SVuong Nguyen 
46432d2efdc6SVuong Nguyen 	if (vendor != X86_VENDOR_Intel) {
46442d2efdc6SVuong Nguyen 		return;
46452d2efdc6SVuong Nguyen 	}
46462d2efdc6SVuong Nguyen 
46472d2efdc6SVuong Nguyen 	/* if the cpuid level is 0xB, extended topo is available. */
46482d2efdc6SVuong Nguyen 	cp->cp_eax = 0;
46492d2efdc6SVuong Nguyen 	if (__cpuid_insn(cp) >= 0xB) {
46502d2efdc6SVuong Nguyen 
46512d2efdc6SVuong Nguyen 		cp->cp_eax = 0xB;
46522d2efdc6SVuong Nguyen 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
46532d2efdc6SVuong Nguyen 		(void) __cpuid_insn(cp);
46542d2efdc6SVuong Nguyen 
46552d2efdc6SVuong Nguyen 		/*
46562d2efdc6SVuong Nguyen 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
46572d2efdc6SVuong Nguyen 		 * indicates that the extended topology enumeration leaf is
46582d2efdc6SVuong Nguyen 		 * available.
46592d2efdc6SVuong Nguyen 		 */
46602d2efdc6SVuong Nguyen 		if (cp->cp_ebx) {
46612d2efdc6SVuong Nguyen 			uint_t coreid_shift = 0;
46622d2efdc6SVuong Nguyen 			uint_t chipid_shift = 0;
46632d2efdc6SVuong Nguyen 			uint_t i;
46642d2efdc6SVuong Nguyen 			uint_t level;
46652d2efdc6SVuong Nguyen 
46662d2efdc6SVuong Nguyen 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
46672d2efdc6SVuong Nguyen 				cp->cp_eax = 0xB;
46682d2efdc6SVuong Nguyen 				cp->cp_ecx = i;
46692d2efdc6SVuong Nguyen 
46702d2efdc6SVuong Nguyen 				(void) __cpuid_insn(cp);
46712d2efdc6SVuong Nguyen 				level = CPI_CPU_LEVEL_TYPE(cp);
46722d2efdc6SVuong Nguyen 
46732d2efdc6SVuong Nguyen 				if (level == 1) {
46742d2efdc6SVuong Nguyen 					/*
46752d2efdc6SVuong Nguyen 					 * Thread level processor topology
46762d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
46772d2efdc6SVuong Nguyen 					 * to get the coreid.
46782d2efdc6SVuong Nguyen 					 */
46792d2efdc6SVuong Nguyen 					coreid_shift = BITX(cp->cp_eax, 4, 0);
46802d2efdc6SVuong Nguyen 				} else if (level == 2) {
46812d2efdc6SVuong Nguyen 					/*
46822d2efdc6SVuong Nguyen 					 * Core level processor topology
46832d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
46842d2efdc6SVuong Nguyen 					 * to get the chipid.
46852d2efdc6SVuong Nguyen 					 */
46862d2efdc6SVuong Nguyen 					chipid_shift = BITX(cp->cp_eax, 4, 0);
46872d2efdc6SVuong Nguyen 				}
46882d2efdc6SVuong Nguyen 			}
46892d2efdc6SVuong Nguyen 
46902d2efdc6SVuong Nguyen 			if (coreid_shift > 0 && chipid_shift > coreid_shift) {
46912d2efdc6SVuong Nguyen 				*strand_nbits = coreid_shift;
46922d2efdc6SVuong Nguyen 				*core_nbits = chipid_shift - coreid_shift;
46932d2efdc6SVuong Nguyen 			}
46942d2efdc6SVuong Nguyen 		}
46952d2efdc6SVuong Nguyen 	}
46962d2efdc6SVuong Nguyen }
4697