xref: /titanic_52/usr/src/uts/i86pc/os/cpuid.c (revision dfea898ab532c75e4d1426e0ff2cc5e0d67aa72f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ee88d2b9Skchow  * Common Development and Distribution License (the "License").
6ee88d2b9Skchow  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
226e5580c9SFrank Van Der Linden  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
24cef70d2cSBill Holler /*
2541afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Copyright (c) 2010, Intel Corporation.
26cef70d2cSBill Holler  * All rights reserved.
27cef70d2cSBill Holler  */
288031591dSSrihari Venkatesan /*
298031591dSSrihari Venkatesan  * Portions Copyright 2009 Advanced Micro Devices, Inc.
308031591dSSrihari Venkatesan  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Various routines to handle identification
347c478bd9Sstevel@tonic-gate  * and classification of x86 processors.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
397c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h>
407c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
417c478bd9Sstevel@tonic-gate #include <sys/systm.h>
427c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
437c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
457c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
467c478bd9Sstevel@tonic-gate #include <sys/processor.h>
475b8a6efeSbholler #include <sys/sysmacros.h>
48fb2f18f8Sesaxe #include <sys/pg.h>
497c478bd9Sstevel@tonic-gate #include <sys/fp.h>
507c478bd9Sstevel@tonic-gate #include <sys/controlregs.h>
517c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
52*dfea898aSKuriakose Kuruvilla #include <sys/auxv_386.h>
537c478bd9Sstevel@tonic-gate #include <sys/memnode.h>
548031591dSSrihari Venkatesan #include <sys/pci_cfgspace.h>
557c478bd9Sstevel@tonic-gate 
56e4b86885SCheng Sean Ye #ifdef __xpv
57e4b86885SCheng Sean Ye #include <sys/hypervisor.h>
58e774b42bSBill Holler #else
59e774b42bSBill Holler #include <sys/ontrap.h>
60e4b86885SCheng Sean Ye #endif
61e4b86885SCheng Sean Ye 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * Pass 0 of cpuid feature analysis happens in locore. It contains special code
647c478bd9Sstevel@tonic-gate  * to recognize Cyrix processors that are not cpuid-compliant, and to deal with
657c478bd9Sstevel@tonic-gate  * them accordingly. For most modern processors, feature detection occurs here
667c478bd9Sstevel@tonic-gate  * in pass 1.
677c478bd9Sstevel@tonic-gate  *
687c478bd9Sstevel@tonic-gate  * Pass 1 of cpuid feature analysis happens just at the beginning of mlsetup()
697c478bd9Sstevel@tonic-gate  * for the boot CPU and does the basic analysis that the early kernel needs.
707417cfdeSKuriakose Kuruvilla  * x86_featureset is set based on the return value of cpuid_pass1() of the boot
717c478bd9Sstevel@tonic-gate  * CPU.
727c478bd9Sstevel@tonic-gate  *
737c478bd9Sstevel@tonic-gate  * Pass 1 includes:
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  *	o Determining vendor/model/family/stepping and setting x86_type and
767c478bd9Sstevel@tonic-gate  *	  x86_vendor accordingly.
777c478bd9Sstevel@tonic-gate  *	o Processing the feature flags returned by the cpuid instruction while
787c478bd9Sstevel@tonic-gate  *	  applying any workarounds or tricks for the specific processor.
797c478bd9Sstevel@tonic-gate  *	o Mapping the feature flags into Solaris feature bits (X86_*).
807c478bd9Sstevel@tonic-gate  *	o Processing extended feature flags if supported by the processor,
817c478bd9Sstevel@tonic-gate  *	  again while applying specific processor knowledge.
827c478bd9Sstevel@tonic-gate  *	o Determining the CMT characteristics of the system.
837c478bd9Sstevel@tonic-gate  *
847c478bd9Sstevel@tonic-gate  * Pass 1 is done on non-boot CPUs during their initialization and the results
857c478bd9Sstevel@tonic-gate  * are used only as a meager attempt at ensuring that all processors within the
867c478bd9Sstevel@tonic-gate  * system support the same features.
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * Pass 2 of cpuid feature analysis happens just at the beginning
897c478bd9Sstevel@tonic-gate  * of startup().  It just copies in and corrects the remainder
907c478bd9Sstevel@tonic-gate  * of the cpuid data we depend on: standard cpuid functions that we didn't
917c478bd9Sstevel@tonic-gate  * need for pass1 feature analysis, and extended cpuid functions beyond the
927c478bd9Sstevel@tonic-gate  * simple feature processing done in pass1.
937c478bd9Sstevel@tonic-gate  *
947c478bd9Sstevel@tonic-gate  * Pass 3 of cpuid analysis is invoked after basic kernel services; in
957c478bd9Sstevel@tonic-gate  * particular kernel memory allocation has been made available. It creates a
967c478bd9Sstevel@tonic-gate  * readable brand string based on the data collected in the first two passes.
977c478bd9Sstevel@tonic-gate  *
987c478bd9Sstevel@tonic-gate  * Pass 4 of cpuid analysis is invoked after post_startup() when all
997c478bd9Sstevel@tonic-gate  * the support infrastructure for various hardware features has been
1007c478bd9Sstevel@tonic-gate  * initialized. It determines which processor features will be reported
1017c478bd9Sstevel@tonic-gate  * to userland via the aux vector.
1027c478bd9Sstevel@tonic-gate  *
1037c478bd9Sstevel@tonic-gate  * All passes are executed on all CPUs, but only the boot CPU determines what
1047c478bd9Sstevel@tonic-gate  * features the kernel will use.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Much of the worst junk in this file is for the support of processors
1077c478bd9Sstevel@tonic-gate  * that didn't really implement the cpuid instruction properly.
1087c478bd9Sstevel@tonic-gate  *
1097c478bd9Sstevel@tonic-gate  * NOTE: The accessor functions (cpuid_get*) are aware of, and ASSERT upon,
1107c478bd9Sstevel@tonic-gate  * the pass numbers.  Accordingly, changes to the pass code may require changes
1117c478bd9Sstevel@tonic-gate  * to the accessor code.
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate uint_t x86_vendor = X86_VENDOR_IntelClone;
1157c478bd9Sstevel@tonic-gate uint_t x86_type = X86_TYPE_OTHER;
11686c1f4dcSVikram Hegde uint_t x86_clflush_size = 0;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4046376;
1197c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4064495;
1207c478bd9Sstevel@tonic-gate 
121*dfea898aSKuriakose Kuruvilla uchar_t x86_featureset[BT_SIZEOFMAP(NUM_X86_FEATURES)];
1227417cfdeSKuriakose Kuruvilla 
123*dfea898aSKuriakose Kuruvilla static char *x86_feature_names[NUM_X86_FEATURES] = {
1247417cfdeSKuriakose Kuruvilla 	"lgpg",
1257417cfdeSKuriakose Kuruvilla 	"tsc",
1267417cfdeSKuriakose Kuruvilla 	"msr",
1277417cfdeSKuriakose Kuruvilla 	"mtrr",
1287417cfdeSKuriakose Kuruvilla 	"pge",
1297417cfdeSKuriakose Kuruvilla 	"de",
1307417cfdeSKuriakose Kuruvilla 	"cmov",
1317417cfdeSKuriakose Kuruvilla 	"mmx",
1327417cfdeSKuriakose Kuruvilla 	"mca",
1337417cfdeSKuriakose Kuruvilla 	"pae",
1347417cfdeSKuriakose Kuruvilla 	"cv8",
1357417cfdeSKuriakose Kuruvilla 	"pat",
1367417cfdeSKuriakose Kuruvilla 	"sep",
1377417cfdeSKuriakose Kuruvilla 	"sse",
1387417cfdeSKuriakose Kuruvilla 	"sse2",
1397417cfdeSKuriakose Kuruvilla 	"htt",
1407417cfdeSKuriakose Kuruvilla 	"asysc",
1417417cfdeSKuriakose Kuruvilla 	"nx",
1427417cfdeSKuriakose Kuruvilla 	"sse3",
1437417cfdeSKuriakose Kuruvilla 	"cx16",
1447417cfdeSKuriakose Kuruvilla 	"cmp",
1457417cfdeSKuriakose Kuruvilla 	"tscp",
1467417cfdeSKuriakose Kuruvilla 	"mwait",
1477417cfdeSKuriakose Kuruvilla 	"sse4a",
1487417cfdeSKuriakose Kuruvilla 	"cpuid",
1497417cfdeSKuriakose Kuruvilla 	"ssse3",
1507417cfdeSKuriakose Kuruvilla 	"sse4_1",
1517417cfdeSKuriakose Kuruvilla 	"sse4_2",
1527417cfdeSKuriakose Kuruvilla 	"1gpg",
1537417cfdeSKuriakose Kuruvilla 	"clfsh",
1547417cfdeSKuriakose Kuruvilla 	"64",
1557417cfdeSKuriakose Kuruvilla 	"aes",
1567af88ac7SKuriakose Kuruvilla 	"pclmulqdq",
1577af88ac7SKuriakose Kuruvilla 	"xsave",
1587af88ac7SKuriakose Kuruvilla 	"avx" };
1597417cfdeSKuriakose Kuruvilla 
1607417cfdeSKuriakose Kuruvilla boolean_t
1617417cfdeSKuriakose Kuruvilla is_x86_feature(void *featureset, uint_t feature)
1627417cfdeSKuriakose Kuruvilla {
1637417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1647417cfdeSKuriakose Kuruvilla 	return (BT_TEST((ulong_t *)featureset, feature));
1657417cfdeSKuriakose Kuruvilla }
1667417cfdeSKuriakose Kuruvilla 
1677417cfdeSKuriakose Kuruvilla void
1687417cfdeSKuriakose Kuruvilla add_x86_feature(void *featureset, uint_t feature)
1697417cfdeSKuriakose Kuruvilla {
1707417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1717417cfdeSKuriakose Kuruvilla 	BT_SET((ulong_t *)featureset, feature);
1727417cfdeSKuriakose Kuruvilla }
1737417cfdeSKuriakose Kuruvilla 
1747417cfdeSKuriakose Kuruvilla void
1757417cfdeSKuriakose Kuruvilla remove_x86_feature(void *featureset, uint_t feature)
1767417cfdeSKuriakose Kuruvilla {
1777417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1787417cfdeSKuriakose Kuruvilla 	BT_CLEAR((ulong_t *)featureset, feature);
1797417cfdeSKuriakose Kuruvilla }
1807417cfdeSKuriakose Kuruvilla 
1817417cfdeSKuriakose Kuruvilla boolean_t
1827417cfdeSKuriakose Kuruvilla compare_x86_featureset(void *setA, void *setB)
1837417cfdeSKuriakose Kuruvilla {
1847417cfdeSKuriakose Kuruvilla 	/*
1857417cfdeSKuriakose Kuruvilla 	 * We assume that the unused bits of the bitmap are always zero.
1867417cfdeSKuriakose Kuruvilla 	 */
1877417cfdeSKuriakose Kuruvilla 	if (memcmp(setA, setB, BT_SIZEOFMAP(NUM_X86_FEATURES)) == 0) {
1887417cfdeSKuriakose Kuruvilla 		return (B_TRUE);
1897417cfdeSKuriakose Kuruvilla 	} else {
1907417cfdeSKuriakose Kuruvilla 		return (B_FALSE);
1917417cfdeSKuriakose Kuruvilla 	}
1927417cfdeSKuriakose Kuruvilla }
1937417cfdeSKuriakose Kuruvilla 
1947417cfdeSKuriakose Kuruvilla void
1957417cfdeSKuriakose Kuruvilla print_x86_featureset(void *featureset)
1967417cfdeSKuriakose Kuruvilla {
1977417cfdeSKuriakose Kuruvilla 	uint_t i;
1987417cfdeSKuriakose Kuruvilla 
1997417cfdeSKuriakose Kuruvilla 	for (i = 0; i < NUM_X86_FEATURES; i++) {
2007417cfdeSKuriakose Kuruvilla 		if (is_x86_feature(featureset, i)) {
2017417cfdeSKuriakose Kuruvilla 			cmn_err(CE_CONT, "?x86_feature: %s\n",
2027417cfdeSKuriakose Kuruvilla 			    x86_feature_names[i]);
2037417cfdeSKuriakose Kuruvilla 		}
2047417cfdeSKuriakose Kuruvilla 	}
2057417cfdeSKuriakose Kuruvilla }
2067417cfdeSKuriakose Kuruvilla 
2077c478bd9Sstevel@tonic-gate uint_t enable486;
2087af88ac7SKuriakose Kuruvilla 
2097af88ac7SKuriakose Kuruvilla static size_t xsave_state_size = 0;
2107af88ac7SKuriakose Kuruvilla uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE);
2117af88ac7SKuriakose Kuruvilla boolean_t xsave_force_disable = B_FALSE;
2127af88ac7SKuriakose Kuruvilla 
2137997e108SSurya Prakki /*
214b9bfdccdSStuart Maybee  * This is set to platform type Solaris is running on.
2157997e108SSurya Prakki  */
216349b53ddSStuart Maybee static int platform_type = -1;
217349b53ddSStuart Maybee 
218349b53ddSStuart Maybee #if !defined(__xpv)
219349b53ddSStuart Maybee /*
220349b53ddSStuart Maybee  * Variable to patch if hypervisor platform detection needs to be
221349b53ddSStuart Maybee  * disabled (e.g. platform_type will always be HW_NATIVE if this is 0).
222349b53ddSStuart Maybee  */
223349b53ddSStuart Maybee int enable_platform_detection = 1;
224349b53ddSStuart Maybee #endif
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate /*
227f98fbcecSbholler  * monitor/mwait info.
2285b8a6efeSbholler  *
2295b8a6efeSbholler  * size_actual and buf_actual are the real address and size allocated to get
2305b8a6efeSbholler  * proper mwait_buf alignement.  buf_actual and size_actual should be passed
2315b8a6efeSbholler  * to kmem_free().  Currently kmem_alloc() and mwait happen to both use
2325b8a6efeSbholler  * processor cache-line alignment, but this is not guarantied in the furture.
233f98fbcecSbholler  */
234f98fbcecSbholler struct mwait_info {
235f98fbcecSbholler 	size_t		mon_min;	/* min size to avoid missed wakeups */
236f98fbcecSbholler 	size_t		mon_max;	/* size to avoid false wakeups */
2375b8a6efeSbholler 	size_t		size_actual;	/* size actually allocated */
2385b8a6efeSbholler 	void		*buf_actual;	/* memory actually allocated */
239f98fbcecSbholler 	uint32_t	support;	/* processor support of monitor/mwait */
240f98fbcecSbholler };
241f98fbcecSbholler 
242f98fbcecSbholler /*
2437af88ac7SKuriakose Kuruvilla  * xsave/xrestor info.
2447af88ac7SKuriakose Kuruvilla  *
2457af88ac7SKuriakose Kuruvilla  * This structure contains HW feature bits and size of the xsave save area.
2467af88ac7SKuriakose Kuruvilla  * Note: the kernel will use the maximum size required for all hardware
2477af88ac7SKuriakose Kuruvilla  * features. It is not optimize for potential memory savings if features at
2487af88ac7SKuriakose Kuruvilla  * the end of the save area are not enabled.
2497af88ac7SKuriakose Kuruvilla  */
2507af88ac7SKuriakose Kuruvilla struct xsave_info {
2517af88ac7SKuriakose Kuruvilla 	uint32_t	xsav_hw_features_low;   /* Supported HW features */
2527af88ac7SKuriakose Kuruvilla 	uint32_t	xsav_hw_features_high;  /* Supported HW features */
2537af88ac7SKuriakose Kuruvilla 	size_t		xsav_max_size;  /* max size save area for HW features */
2547af88ac7SKuriakose Kuruvilla 	size_t		ymm_size;	/* AVX: size of ymm save area */
2557af88ac7SKuriakose Kuruvilla 	size_t		ymm_offset;	/* AVX: offset for ymm save area */
2567af88ac7SKuriakose Kuruvilla };
2577af88ac7SKuriakose Kuruvilla 
2587af88ac7SKuriakose Kuruvilla 
2597af88ac7SKuriakose Kuruvilla /*
2607c478bd9Sstevel@tonic-gate  * These constants determine how many of the elements of the
2617c478bd9Sstevel@tonic-gate  * cpuid we cache in the cpuid_info data structure; the
2627c478bd9Sstevel@tonic-gate  * remaining elements are accessible via the cpuid instruction.
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate #define	NMAX_CPI_STD	6		/* eax = 0 .. 5 */
2668031591dSSrihari Venkatesan #define	NMAX_CPI_EXTD	0x1c		/* eax = 0x80000000 .. 0x8000001b */
2678031591dSSrihari Venkatesan 
2688031591dSSrihari Venkatesan /*
2698031591dSSrihari Venkatesan  * Some terminology needs to be explained:
2708031591dSSrihari Venkatesan  *  - Socket: Something that can be plugged into a motherboard.
2718031591dSSrihari Venkatesan  *  - Package: Same as socket
2728031591dSSrihari Venkatesan  *  - Chip: Same as socket. Note that AMD's documentation uses term "chip"
2738031591dSSrihari Venkatesan  *    differently: there, chip is the same as processor node (below)
2748031591dSSrihari Venkatesan  *  - Processor node: Some AMD processors have more than one
2758031591dSSrihari Venkatesan  *    "subprocessor" embedded in a package. These subprocessors (nodes)
2768031591dSSrihari Venkatesan  *    are fully-functional processors themselves with cores, caches,
2778031591dSSrihari Venkatesan  *    memory controllers, PCI configuration spaces. They are connected
2788031591dSSrihari Venkatesan  *    inside the package with Hypertransport links. On single-node
2798031591dSSrihari Venkatesan  *    processors, processor node is equivalent to chip/socket/package.
2808031591dSSrihari Venkatesan  */
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate struct cpuid_info {
2837c478bd9Sstevel@tonic-gate 	uint_t cpi_pass;		/* last pass completed */
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * standard function information
2867c478bd9Sstevel@tonic-gate 	 */
2877c478bd9Sstevel@tonic-gate 	uint_t cpi_maxeax;		/* fn 0: %eax */
2887c478bd9Sstevel@tonic-gate 	char cpi_vendorstr[13];		/* fn 0: %ebx:%ecx:%edx */
2897c478bd9Sstevel@tonic-gate 	uint_t cpi_vendor;		/* enum of cpi_vendorstr */
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	uint_t cpi_family;		/* fn 1: extended family */
2927c478bd9Sstevel@tonic-gate 	uint_t cpi_model;		/* fn 1: extended model */
2937c478bd9Sstevel@tonic-gate 	uint_t cpi_step;		/* fn 1: stepping */
2948031591dSSrihari Venkatesan 	chipid_t cpi_chipid;		/* fn 1: %ebx:  Intel: chip # */
2958031591dSSrihari Venkatesan 					/*		AMD: package/socket # */
2967c478bd9Sstevel@tonic-gate 	uint_t cpi_brandid;		/* fn 1: %ebx: brand ID */
2977c478bd9Sstevel@tonic-gate 	int cpi_clogid;			/* fn 1: %ebx: thread # */
2988949bcd6Sandrei 	uint_t cpi_ncpu_per_chip;	/* fn 1: %ebx: logical cpu count */
2997c478bd9Sstevel@tonic-gate 	uint8_t cpi_cacheinfo[16];	/* fn 2: intel-style cache desc */
3007c478bd9Sstevel@tonic-gate 	uint_t cpi_ncache;		/* fn 2: number of elements */
301d129bde2Sesaxe 	uint_t cpi_ncpu_shr_last_cache;	/* fn 4: %eax: ncpus sharing cache */
302d129bde2Sesaxe 	id_t cpi_last_lvl_cacheid;	/* fn 4: %eax: derived cache id */
303d129bde2Sesaxe 	uint_t cpi_std_4_size;		/* fn 4: number of fn 4 elements */
304d129bde2Sesaxe 	struct cpuid_regs **cpi_std_4;	/* fn 4: %ecx == 0 .. fn4_size */
3058949bcd6Sandrei 	struct cpuid_regs cpi_std[NMAX_CPI_STD];	/* 0 .. 5 */
3067c478bd9Sstevel@tonic-gate 	/*
3077c478bd9Sstevel@tonic-gate 	 * extended function information
3087c478bd9Sstevel@tonic-gate 	 */
3097c478bd9Sstevel@tonic-gate 	uint_t cpi_xmaxeax;		/* fn 0x80000000: %eax */
3107c478bd9Sstevel@tonic-gate 	char cpi_brandstr[49];		/* fn 0x8000000[234] */
3117c478bd9Sstevel@tonic-gate 	uint8_t cpi_pabits;		/* fn 0x80000006: %eax */
3127c478bd9Sstevel@tonic-gate 	uint8_t	cpi_vabits;		/* fn 0x80000006: %eax */
3138031591dSSrihari Venkatesan 	struct	cpuid_regs cpi_extd[NMAX_CPI_EXTD];	/* 0x800000XX */
3148031591dSSrihari Venkatesan 
31510569901Sgavinm 	id_t cpi_coreid;		/* same coreid => strands share core */
31610569901Sgavinm 	int cpi_pkgcoreid;		/* core number within single package */
3178949bcd6Sandrei 	uint_t cpi_ncore_per_chip;	/* AMD: fn 0x80000008: %ecx[7-0] */
3188949bcd6Sandrei 					/* Intel: fn 4: %eax[31-26] */
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * supported feature information
3217c478bd9Sstevel@tonic-gate 	 */
322ae115bc7Smrj 	uint32_t cpi_support[5];
3237c478bd9Sstevel@tonic-gate #define	STD_EDX_FEATURES	0
3247c478bd9Sstevel@tonic-gate #define	AMD_EDX_FEATURES	1
3257c478bd9Sstevel@tonic-gate #define	TM_EDX_FEATURES		2
3267c478bd9Sstevel@tonic-gate #define	STD_ECX_FEATURES	3
327ae115bc7Smrj #define	AMD_ECX_FEATURES	4
3288a40a695Sgavinm 	/*
3298a40a695Sgavinm 	 * Synthesized information, where known.
3308a40a695Sgavinm 	 */
3318a40a695Sgavinm 	uint32_t cpi_chiprev;		/* See X86_CHIPREV_* in x86_archext.h */
3328a40a695Sgavinm 	const char *cpi_chiprevstr;	/* May be NULL if chiprev unknown */
3338a40a695Sgavinm 	uint32_t cpi_socket;		/* Chip package/socket type */
334f98fbcecSbholler 
335f98fbcecSbholler 	struct mwait_info cpi_mwait;	/* fn 5: monitor/mwait info */
336b6917abeSmishra 	uint32_t cpi_apicid;
3378031591dSSrihari Venkatesan 	uint_t cpi_procnodeid;		/* AMD: nodeID on HT, Intel: chipid */
3388031591dSSrihari Venkatesan 	uint_t cpi_procnodes_per_pkg;	/* AMD: # of nodes in the package */
3398031591dSSrihari Venkatesan 					/* Intel: 1 */
3407af88ac7SKuriakose Kuruvilla 
3417af88ac7SKuriakose Kuruvilla 	struct xsave_info cpi_xsave;	/* fn D: xsave/xrestor info */
3427c478bd9Sstevel@tonic-gate };
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate static struct cpuid_info cpuid_info0;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /*
3487c478bd9Sstevel@tonic-gate  * These bit fields are defined by the Intel Application Note AP-485
3497c478bd9Sstevel@tonic-gate  * "Intel Processor Identification and the CPUID Instruction"
3507c478bd9Sstevel@tonic-gate  */
3517c478bd9Sstevel@tonic-gate #define	CPI_FAMILY_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 27, 20)
3527c478bd9Sstevel@tonic-gate #define	CPI_MODEL_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 19, 16)
3537c478bd9Sstevel@tonic-gate #define	CPI_TYPE(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 13, 12)
3547c478bd9Sstevel@tonic-gate #define	CPI_FAMILY(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 11, 8)
3557c478bd9Sstevel@tonic-gate #define	CPI_STEP(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 3, 0)
3567c478bd9Sstevel@tonic-gate #define	CPI_MODEL(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 7, 4)
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_EDX(cpi)		((cpi)->cpi_std[1].cp_edx)
3597c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_ECX(cpi)		((cpi)->cpi_std[1].cp_ecx)
3607c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_EDX(cpi)	((cpi)->cpi_extd[1].cp_edx)
3617c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_ECX(cpi)	((cpi)->cpi_extd[1].cp_ecx)
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate #define	CPI_BRANDID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 7, 0)
3647c478bd9Sstevel@tonic-gate #define	CPI_CHUNKS(cpi)		BITX((cpi)->cpi_std[1].cp_ebx, 15, 7)
3657c478bd9Sstevel@tonic-gate #define	CPI_CPU_COUNT(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 23, 16)
3667c478bd9Sstevel@tonic-gate #define	CPI_APIC_ID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 31, 24)
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate #define	CPI_MAXEAX_MAX		0x100		/* sanity control */
3697c478bd9Sstevel@tonic-gate #define	CPI_XMAXEAX_MAX		0x80000100
370d129bde2Sesaxe #define	CPI_FN4_ECX_MAX		0x20		/* sanity: max fn 4 levels */
371b6917abeSmishra #define	CPI_FNB_ECX_MAX		0x20		/* sanity: max fn B levels */
372d129bde2Sesaxe 
373d129bde2Sesaxe /*
374d129bde2Sesaxe  * Function 4 (Deterministic Cache Parameters) macros
375d129bde2Sesaxe  * Defined by Intel Application Note AP-485
376d129bde2Sesaxe  */
377d129bde2Sesaxe #define	CPI_NUM_CORES(regs)		BITX((regs)->cp_eax, 31, 26)
378d129bde2Sesaxe #define	CPI_NTHR_SHR_CACHE(regs)	BITX((regs)->cp_eax, 25, 14)
379d129bde2Sesaxe #define	CPI_FULL_ASSOC_CACHE(regs)	BITX((regs)->cp_eax, 9, 9)
380d129bde2Sesaxe #define	CPI_SELF_INIT_CACHE(regs)	BITX((regs)->cp_eax, 8, 8)
381d129bde2Sesaxe #define	CPI_CACHE_LVL(regs)		BITX((regs)->cp_eax, 7, 5)
382d129bde2Sesaxe #define	CPI_CACHE_TYPE(regs)		BITX((regs)->cp_eax, 4, 0)
383b6917abeSmishra #define	CPI_CPU_LEVEL_TYPE(regs)	BITX((regs)->cp_ecx, 15, 8)
384d129bde2Sesaxe 
385d129bde2Sesaxe #define	CPI_CACHE_WAYS(regs)		BITX((regs)->cp_ebx, 31, 22)
386d129bde2Sesaxe #define	CPI_CACHE_PARTS(regs)		BITX((regs)->cp_ebx, 21, 12)
387d129bde2Sesaxe #define	CPI_CACHE_COH_LN_SZ(regs)	BITX((regs)->cp_ebx, 11, 0)
388d129bde2Sesaxe 
389d129bde2Sesaxe #define	CPI_CACHE_SETS(regs)		BITX((regs)->cp_ecx, 31, 0)
390d129bde2Sesaxe 
391d129bde2Sesaxe #define	CPI_PREFCH_STRIDE(regs)		BITX((regs)->cp_edx, 9, 0)
392d129bde2Sesaxe 
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3955ff02082Sdmick  * A couple of shorthand macros to identify "later" P6-family chips
3965ff02082Sdmick  * like the Pentium M and Core.  First, the "older" P6-based stuff
3975ff02082Sdmick  * (loosely defined as "pre-Pentium-4"):
3985ff02082Sdmick  * P6, PII, Mobile PII, PII Xeon, PIII, Mobile PIII, PIII Xeon
3995ff02082Sdmick  */
4005ff02082Sdmick 
4015ff02082Sdmick #define	IS_LEGACY_P6(cpi) (			\
4025ff02082Sdmick 	cpi->cpi_family == 6 && 		\
4035ff02082Sdmick 		(cpi->cpi_model == 1 ||		\
4045ff02082Sdmick 		cpi->cpi_model == 3 ||		\
4055ff02082Sdmick 		cpi->cpi_model == 5 ||		\
4065ff02082Sdmick 		cpi->cpi_model == 6 ||		\
4075ff02082Sdmick 		cpi->cpi_model == 7 ||		\
4085ff02082Sdmick 		cpi->cpi_model == 8 ||		\
4095ff02082Sdmick 		cpi->cpi_model == 0xA ||	\
4105ff02082Sdmick 		cpi->cpi_model == 0xB)		\
4115ff02082Sdmick )
4125ff02082Sdmick 
4135ff02082Sdmick /* A "new F6" is everything with family 6 that's not the above */
4145ff02082Sdmick #define	IS_NEW_F6(cpi) ((cpi->cpi_family == 6) && !IS_LEGACY_P6(cpi))
4155ff02082Sdmick 
416bf91205bSksadhukh /* Extended family/model support */
417bf91205bSksadhukh #define	IS_EXTENDED_MODEL_INTEL(cpi) (cpi->cpi_family == 0x6 || \
418bf91205bSksadhukh 	cpi->cpi_family >= 0xf)
419bf91205bSksadhukh 
4205ff02082Sdmick /*
421f98fbcecSbholler  * Info for monitor/mwait idle loop.
422f98fbcecSbholler  *
423f98fbcecSbholler  * See cpuid section of "Intel 64 and IA-32 Architectures Software Developer's
424f98fbcecSbholler  * Manual Volume 2A: Instruction Set Reference, A-M" #25366-022US, November
425f98fbcecSbholler  * 2006.
426f98fbcecSbholler  * See MONITOR/MWAIT section of "AMD64 Architecture Programmer's Manual
427f98fbcecSbholler  * Documentation Updates" #33633, Rev 2.05, December 2006.
428f98fbcecSbholler  */
429f98fbcecSbholler #define	MWAIT_SUPPORT		(0x00000001)	/* mwait supported */
430f98fbcecSbholler #define	MWAIT_EXTENSIONS	(0x00000002)	/* extenstion supported */
431f98fbcecSbholler #define	MWAIT_ECX_INT_ENABLE	(0x00000004)	/* ecx 1 extension supported */
432f98fbcecSbholler #define	MWAIT_SUPPORTED(cpi)	((cpi)->cpi_std[1].cp_ecx & CPUID_INTC_ECX_MON)
433f98fbcecSbholler #define	MWAIT_INT_ENABLE(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x2)
434f98fbcecSbholler #define	MWAIT_EXTENSION(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x1)
435f98fbcecSbholler #define	MWAIT_SIZE_MIN(cpi)	BITX((cpi)->cpi_std[5].cp_eax, 15, 0)
436f98fbcecSbholler #define	MWAIT_SIZE_MAX(cpi)	BITX((cpi)->cpi_std[5].cp_ebx, 15, 0)
437f98fbcecSbholler /*
438f98fbcecSbholler  * Number of sub-cstates for a given c-state.
439f98fbcecSbholler  */
440f98fbcecSbholler #define	MWAIT_NUM_SUBC_STATES(cpi, c_state)			\
441f98fbcecSbholler 	BITX((cpi)->cpi_std[5].cp_edx, c_state + 3, c_state)
442f98fbcecSbholler 
4438a40a695Sgavinm /*
4447af88ac7SKuriakose Kuruvilla  * XSAVE leaf 0xD enumeration
4457af88ac7SKuriakose Kuruvilla  */
4467af88ac7SKuriakose Kuruvilla #define	CPUID_LEAFD_2_YMM_OFFSET	576
4477af88ac7SKuriakose Kuruvilla #define	CPUID_LEAFD_2_YMM_SIZE		256
4487af88ac7SKuriakose Kuruvilla 
4497af88ac7SKuriakose Kuruvilla /*
450e4b86885SCheng Sean Ye  * Functions we consune from cpuid_subr.c;  don't publish these in a header
451e4b86885SCheng Sean Ye  * file to try and keep people using the expected cpuid_* interfaces.
4528a40a695Sgavinm  */
453e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t);
45489e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t);
455e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t);
456e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t);
457e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *);
4588a40a695Sgavinm 
4598a40a695Sgavinm /*
460ae115bc7Smrj  * Apply up various platform-dependent restrictions where the
461ae115bc7Smrj  * underlying platform restrictions mean the CPU can be marked
462ae115bc7Smrj  * as less capable than its cpuid instruction would imply.
463ae115bc7Smrj  */
464843e1988Sjohnlev #if defined(__xpv)
465843e1988Sjohnlev static void
466843e1988Sjohnlev platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp)
467843e1988Sjohnlev {
468843e1988Sjohnlev 	switch (eax) {
469e4b86885SCheng Sean Ye 	case 1: {
470e4b86885SCheng Sean Ye 		uint32_t mcamask = DOMAIN_IS_INITDOMAIN(xen_info) ?
471e4b86885SCheng Sean Ye 		    0 : CPUID_INTC_EDX_MCA;
472843e1988Sjohnlev 		cp->cp_edx &=
473e4b86885SCheng Sean Ye 		    ~(mcamask |
474e4b86885SCheng Sean Ye 		    CPUID_INTC_EDX_PSE |
475843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
476843e1988Sjohnlev 		    CPUID_INTC_EDX_SEP | CPUID_INTC_EDX_MTRR |
477843e1988Sjohnlev 		    CPUID_INTC_EDX_PGE | CPUID_INTC_EDX_PAT |
478843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
479843e1988Sjohnlev 		    CPUID_INTC_EDX_PSE36 | CPUID_INTC_EDX_HTT);
480843e1988Sjohnlev 		break;
481e4b86885SCheng Sean Ye 	}
482ae115bc7Smrj 
483843e1988Sjohnlev 	case 0x80000001:
484843e1988Sjohnlev 		cp->cp_edx &=
485843e1988Sjohnlev 		    ~(CPUID_AMD_EDX_PSE |
486843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
487843e1988Sjohnlev 		    CPUID_AMD_EDX_MTRR | CPUID_AMD_EDX_PGE |
488843e1988Sjohnlev 		    CPUID_AMD_EDX_PAT | CPUID_AMD_EDX_PSE36 |
489843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
490843e1988Sjohnlev 		    CPUID_AMD_EDX_TSCP);
491843e1988Sjohnlev 		cp->cp_ecx &= ~CPUID_AMD_ECX_CMP_LGCY;
492843e1988Sjohnlev 		break;
493843e1988Sjohnlev 	default:
494843e1988Sjohnlev 		break;
495843e1988Sjohnlev 	}
496843e1988Sjohnlev 
497843e1988Sjohnlev 	switch (vendor) {
498843e1988Sjohnlev 	case X86_VENDOR_Intel:
499843e1988Sjohnlev 		switch (eax) {
500843e1988Sjohnlev 		case 4:
501843e1988Sjohnlev 			/*
502843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
503843e1988Sjohnlev 			 */
504843e1988Sjohnlev 			cp->cp_eax &= 0x03fffffff;
505843e1988Sjohnlev 			break;
506843e1988Sjohnlev 		default:
507843e1988Sjohnlev 			break;
508843e1988Sjohnlev 		}
509843e1988Sjohnlev 		break;
510843e1988Sjohnlev 	case X86_VENDOR_AMD:
511843e1988Sjohnlev 		switch (eax) {
5122ef50f01SJoe Bonasera 
5132ef50f01SJoe Bonasera 		case 0x80000001:
5142ef50f01SJoe Bonasera 			cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D;
5152ef50f01SJoe Bonasera 			break;
5162ef50f01SJoe Bonasera 
517843e1988Sjohnlev 		case 0x80000008:
518843e1988Sjohnlev 			/*
519843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
520843e1988Sjohnlev 			 */
521843e1988Sjohnlev 			cp->cp_ecx &= 0xffffff00;
522843e1988Sjohnlev 			break;
523843e1988Sjohnlev 		default:
524843e1988Sjohnlev 			break;
525843e1988Sjohnlev 		}
526843e1988Sjohnlev 		break;
527843e1988Sjohnlev 	default:
528843e1988Sjohnlev 		break;
529843e1988Sjohnlev 	}
530843e1988Sjohnlev }
531843e1988Sjohnlev #else
532ae115bc7Smrj #define	platform_cpuid_mangle(vendor, eax, cp)	/* nothing */
533843e1988Sjohnlev #endif
534ae115bc7Smrj 
535ae115bc7Smrj /*
5367c478bd9Sstevel@tonic-gate  *  Some undocumented ways of patching the results of the cpuid
5377c478bd9Sstevel@tonic-gate  *  instruction to permit running Solaris 10 on future cpus that
5387c478bd9Sstevel@tonic-gate  *  we don't currently support.  Could be set to non-zero values
5397c478bd9Sstevel@tonic-gate  *  via settings in eeprom.
5407c478bd9Sstevel@tonic-gate  */
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_include;
5437c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_exclude;
5447c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_include;
5457c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_exclude;
5467c478bd9Sstevel@tonic-gate 
547a3114836SGerry Liu /*
548a3114836SGerry Liu  * Allocate space for mcpu_cpi in the machcpu structure for all non-boot CPUs.
549a3114836SGerry Liu  */
550ae115bc7Smrj void
551ae115bc7Smrj cpuid_alloc_space(cpu_t *cpu)
552ae115bc7Smrj {
553ae115bc7Smrj 	/*
554ae115bc7Smrj 	 * By convention, cpu0 is the boot cpu, which is set up
555ae115bc7Smrj 	 * before memory allocation is available.  All other cpus get
556ae115bc7Smrj 	 * their cpuid_info struct allocated here.
557ae115bc7Smrj 	 */
558ae115bc7Smrj 	ASSERT(cpu->cpu_id != 0);
559a3114836SGerry Liu 	ASSERT(cpu->cpu_m.mcpu_cpi == NULL);
560ae115bc7Smrj 	cpu->cpu_m.mcpu_cpi =
561ae115bc7Smrj 	    kmem_zalloc(sizeof (*cpu->cpu_m.mcpu_cpi), KM_SLEEP);
562ae115bc7Smrj }
563ae115bc7Smrj 
564ae115bc7Smrj void
565ae115bc7Smrj cpuid_free_space(cpu_t *cpu)
566ae115bc7Smrj {
567d129bde2Sesaxe 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
568d129bde2Sesaxe 	int i;
569d129bde2Sesaxe 
570a3114836SGerry Liu 	ASSERT(cpi != NULL);
571a3114836SGerry Liu 	ASSERT(cpi != &cpuid_info0);
572d129bde2Sesaxe 
573d129bde2Sesaxe 	/*
574d129bde2Sesaxe 	 * Free up any function 4 related dynamic storage
575d129bde2Sesaxe 	 */
576d129bde2Sesaxe 	for (i = 1; i < cpi->cpi_std_4_size; i++)
577d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4[i], sizeof (struct cpuid_regs));
578d129bde2Sesaxe 	if (cpi->cpi_std_4_size > 0)
579d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4,
580d129bde2Sesaxe 		    cpi->cpi_std_4_size * sizeof (struct cpuid_regs *));
581d129bde2Sesaxe 
582a3114836SGerry Liu 	kmem_free(cpi, sizeof (*cpi));
583a3114836SGerry Liu 	cpu->cpu_m.mcpu_cpi = NULL;
584ae115bc7Smrj }
585ae115bc7Smrj 
586551bc2a6Smrj #if !defined(__xpv)
587551bc2a6Smrj 
588551bc2a6Smrj static void
589b9bfdccdSStuart Maybee determine_platform()
590551bc2a6Smrj {
591551bc2a6Smrj 	struct cpuid_regs cp;
592551bc2a6Smrj 	char *xen_str;
5936e5580c9SFrank Van Der Linden 	uint32_t xen_signature[4], base;
594551bc2a6Smrj 
595349b53ddSStuart Maybee 	platform_type = HW_NATIVE;
596349b53ddSStuart Maybee 
597349b53ddSStuart Maybee 	if (!enable_platform_detection)
598349b53ddSStuart Maybee 		return;
599349b53ddSStuart Maybee 
600551bc2a6Smrj 	/*
601551bc2a6Smrj 	 * In a fully virtualized domain, Xen's pseudo-cpuid function
6026e5580c9SFrank Van Der Linden 	 * returns a string representing the Xen signature in %ebx, %ecx,
6036e5580c9SFrank Van Der Linden 	 * and %edx. %eax contains the maximum supported cpuid function.
6046e5580c9SFrank Van Der Linden 	 * We need at least a (base + 2) leaf value to do what we want
6056e5580c9SFrank Van Der Linden 	 * to do. Try different base values, since the hypervisor might
6066e5580c9SFrank Van Der Linden 	 * use a different one depending on whether hyper-v emulation
6076e5580c9SFrank Van Der Linden 	 * is switched on by default or not.
608551bc2a6Smrj 	 */
6096e5580c9SFrank Van Der Linden 	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
6106e5580c9SFrank Van Der Linden 		cp.cp_eax = base;
611551bc2a6Smrj 		(void) __cpuid_insn(&cp);
612551bc2a6Smrj 		xen_signature[0] = cp.cp_ebx;
613551bc2a6Smrj 		xen_signature[1] = cp.cp_ecx;
614551bc2a6Smrj 		xen_signature[2] = cp.cp_edx;
615551bc2a6Smrj 		xen_signature[3] = 0;
616551bc2a6Smrj 		xen_str = (char *)xen_signature;
6176e5580c9SFrank Van Der Linden 		if (strcmp("XenVMMXenVMM", xen_str) == 0 &&
6186e5580c9SFrank Van Der Linden 		    cp.cp_eax >= (base + 2)) {
619b9bfdccdSStuart Maybee 			platform_type = HW_XEN_HVM;
6206e5580c9SFrank Van Der Linden 			return;
621551bc2a6Smrj 		}
622b9bfdccdSStuart Maybee 	}
623b9bfdccdSStuart Maybee 
6246e5580c9SFrank Van Der Linden 	if (vmware_platform()) /* running under vmware hypervisor? */
6256e5580c9SFrank Van Der Linden 		platform_type = HW_VMWARE;
6266e5580c9SFrank Van Der Linden }
6276e5580c9SFrank Van Der Linden 
628b9bfdccdSStuart Maybee int
629b9bfdccdSStuart Maybee get_hwenv(void)
630b9bfdccdSStuart Maybee {
631349b53ddSStuart Maybee 	if (platform_type == -1)
632349b53ddSStuart Maybee 		determine_platform();
633349b53ddSStuart Maybee 
634b9bfdccdSStuart Maybee 	return (platform_type);
635b9bfdccdSStuart Maybee }
636b9bfdccdSStuart Maybee 
637b9bfdccdSStuart Maybee int
638b9bfdccdSStuart Maybee is_controldom(void)
639b9bfdccdSStuart Maybee {
640b9bfdccdSStuart Maybee 	return (0);
641b9bfdccdSStuart Maybee }
642b9bfdccdSStuart Maybee 
643b9bfdccdSStuart Maybee #else
644b9bfdccdSStuart Maybee 
645b9bfdccdSStuart Maybee int
646b9bfdccdSStuart Maybee get_hwenv(void)
647b9bfdccdSStuart Maybee {
648b9bfdccdSStuart Maybee 	return (HW_XEN_PV);
649b9bfdccdSStuart Maybee }
650b9bfdccdSStuart Maybee 
651b9bfdccdSStuart Maybee int
652b9bfdccdSStuart Maybee is_controldom(void)
653b9bfdccdSStuart Maybee {
654b9bfdccdSStuart Maybee 	return (DOMAIN_IS_INITDOMAIN(xen_info));
655b9bfdccdSStuart Maybee }
656b9bfdccdSStuart Maybee 
657551bc2a6Smrj #endif	/* __xpv */
658551bc2a6Smrj 
6598031591dSSrihari Venkatesan static void
6607417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu_t *cpu, void *feature)
6618031591dSSrihari Venkatesan {
6628031591dSSrihari Venkatesan 	uint_t i;
6638031591dSSrihari Venkatesan 	uint_t chipid_shift = 0;
6648031591dSSrihari Venkatesan 	uint_t coreid_shift = 0;
6658031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
6668031591dSSrihari Venkatesan 
6678031591dSSrihari Venkatesan 	for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1)
6688031591dSSrihari Venkatesan 		chipid_shift++;
6698031591dSSrihari Venkatesan 
6708031591dSSrihari Venkatesan 	cpi->cpi_chipid = cpi->cpi_apicid >> chipid_shift;
6718031591dSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_apicid & ((1 << chipid_shift) - 1);
6728031591dSSrihari Venkatesan 
6737417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(feature, X86FSET_CMP)) {
6748031591dSSrihari Venkatesan 		/*
6758031591dSSrihari Venkatesan 		 * Multi-core (and possibly multi-threaded)
6768031591dSSrihari Venkatesan 		 * processors.
6778031591dSSrihari Venkatesan 		 */
6788031591dSSrihari Venkatesan 		uint_t ncpu_per_core;
6798031591dSSrihari Venkatesan 		if (cpi->cpi_ncore_per_chip == 1)
6808031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip;
6818031591dSSrihari Venkatesan 		else if (cpi->cpi_ncore_per_chip > 1)
6828031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip /
6838031591dSSrihari Venkatesan 			    cpi->cpi_ncore_per_chip;
6848031591dSSrihari Venkatesan 		/*
6858031591dSSrihari Venkatesan 		 * 8bit APIC IDs on dual core Pentiums
6868031591dSSrihari Venkatesan 		 * look like this:
6878031591dSSrihari Venkatesan 		 *
6888031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
6898031591dSSrihari Venkatesan 		 * | Physical Package ID   |  MC  |  HT  |
6908031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
6918031591dSSrihari Venkatesan 		 * <------- chipid -------->
6928031591dSSrihari Venkatesan 		 * <------- coreid --------------->
6938031591dSSrihari Venkatesan 		 *			   <--- clogid -->
6948031591dSSrihari Venkatesan 		 *			   <------>
6958031591dSSrihari Venkatesan 		 *			   pkgcoreid
6968031591dSSrihari Venkatesan 		 *
6978031591dSSrihari Venkatesan 		 * Where the number of bits necessary to
6988031591dSSrihari Venkatesan 		 * represent MC and HT fields together equals
6998031591dSSrihari Venkatesan 		 * to the minimum number of bits necessary to
7008031591dSSrihari Venkatesan 		 * store the value of cpi->cpi_ncpu_per_chip.
7018031591dSSrihari Venkatesan 		 * Of those bits, the MC part uses the number
7028031591dSSrihari Venkatesan 		 * of bits necessary to store the value of
7038031591dSSrihari Venkatesan 		 * cpi->cpi_ncore_per_chip.
7048031591dSSrihari Venkatesan 		 */
7058031591dSSrihari Venkatesan 		for (i = 1; i < ncpu_per_core; i <<= 1)
7068031591dSSrihari Venkatesan 			coreid_shift++;
7078031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_apicid >> coreid_shift;
7088031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
7097417cfdeSKuriakose Kuruvilla 	} else if (is_x86_feature(feature, X86FSET_HTT)) {
7108031591dSSrihari Venkatesan 		/*
7118031591dSSrihari Venkatesan 		 * Single-core multi-threaded processors.
7128031591dSSrihari Venkatesan 		 */
7138031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_chipid;
7148031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = 0;
7158031591dSSrihari Venkatesan 	}
7168031591dSSrihari Venkatesan 	cpi->cpi_procnodeid = cpi->cpi_chipid;
7178031591dSSrihari Venkatesan }
7188031591dSSrihari Venkatesan 
7198031591dSSrihari Venkatesan static void
7208031591dSSrihari Venkatesan cpuid_amd_getids(cpu_t *cpu)
7218031591dSSrihari Venkatesan {
7221fbe4a4fSSrihari Venkatesan 	int i, first_half, coreidsz;
7238031591dSSrihari Venkatesan 	uint32_t nb_caps_reg;
7248031591dSSrihari Venkatesan 	uint_t node2_1;
7258031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
7268031591dSSrihari Venkatesan 
7278031591dSSrihari Venkatesan 	/*
7288031591dSSrihari Venkatesan 	 * AMD CMP chips currently have a single thread per core.
7298031591dSSrihari Venkatesan 	 *
7308031591dSSrihari Venkatesan 	 * Since no two cpus share a core we must assign a distinct coreid
7318031591dSSrihari Venkatesan 	 * per cpu, and we do this by using the cpu_id.  This scheme does not,
7328031591dSSrihari Venkatesan 	 * however, guarantee that sibling cores of a chip will have sequential
7338031591dSSrihari Venkatesan 	 * coreids starting at a multiple of the number of cores per chip -
7348031591dSSrihari Venkatesan 	 * that is usually the case, but if the ACPI MADT table is presented
7358031591dSSrihari Venkatesan 	 * in a different order then we need to perform a few more gymnastics
7368031591dSSrihari Venkatesan 	 * for the pkgcoreid.
7378031591dSSrihari Venkatesan 	 *
7388031591dSSrihari Venkatesan 	 * All processors in the system have the same number of enabled
7398031591dSSrihari Venkatesan 	 * cores. Cores within a processor are always numbered sequentially
7408031591dSSrihari Venkatesan 	 * from 0 regardless of how many or which are disabled, and there
7418031591dSSrihari Venkatesan 	 * is no way for operating system to discover the real core id when some
7428031591dSSrihari Venkatesan 	 * are disabled.
7438031591dSSrihari Venkatesan 	 */
7448031591dSSrihari Venkatesan 
7458031591dSSrihari Venkatesan 	cpi->cpi_coreid = cpu->cpu_id;
7468031591dSSrihari Venkatesan 
7478031591dSSrihari Venkatesan 	if (cpi->cpi_xmaxeax >= 0x80000008) {
7488031591dSSrihari Venkatesan 
7498031591dSSrihari Venkatesan 		coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12);
7508031591dSSrihari Venkatesan 
7518031591dSSrihari Venkatesan 		/*
7528031591dSSrihari Venkatesan 		 * In AMD parlance chip is really a node while Solaris
7538031591dSSrihari Venkatesan 		 * sees chip as equivalent to socket/package.
7548031591dSSrihari Venkatesan 		 */
7558031591dSSrihari Venkatesan 		cpi->cpi_ncore_per_chip =
7568031591dSSrihari Venkatesan 		    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
7571fbe4a4fSSrihari Venkatesan 		if (coreidsz == 0) {
7588031591dSSrihari Venkatesan 			/* Use legacy method */
7591fbe4a4fSSrihari Venkatesan 			for (i = 1; i < cpi->cpi_ncore_per_chip; i <<= 1)
7601fbe4a4fSSrihari Venkatesan 				coreidsz++;
7611fbe4a4fSSrihari Venkatesan 			if (coreidsz == 0)
7621fbe4a4fSSrihari Venkatesan 				coreidsz = 1;
7631fbe4a4fSSrihari Venkatesan 		}
7648031591dSSrihari Venkatesan 	} else {
7658031591dSSrihari Venkatesan 		/* Assume single-core part */
7661fbe4a4fSSrihari Venkatesan 		cpi->cpi_ncore_per_chip = 1;
76772b70389SJakub Jermar 		coreidsz = 1;
7688031591dSSrihari Venkatesan 	}
7698031591dSSrihari Venkatesan 
7701fbe4a4fSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_pkgcoreid =
7711fbe4a4fSSrihari Venkatesan 	    cpi->cpi_apicid & ((1<<coreidsz) - 1);
7728031591dSSrihari Venkatesan 	cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip;
7738031591dSSrihari Venkatesan 
7748031591dSSrihari Venkatesan 	/* Get nodeID */
7758031591dSSrihari Venkatesan 	if (cpi->cpi_family == 0xf) {
7761fbe4a4fSSrihari Venkatesan 		cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
7778031591dSSrihari Venkatesan 		cpi->cpi_chipid = cpi->cpi_procnodeid;
7788031591dSSrihari Venkatesan 	} else if (cpi->cpi_family == 0x10) {
7798031591dSSrihari Venkatesan 		/*
7808031591dSSrihari Venkatesan 		 * See if we are a multi-node processor.
7818031591dSSrihari Venkatesan 		 * All processors in the system have the same number of nodes
7828031591dSSrihari Venkatesan 		 */
7838031591dSSrihari Venkatesan 		nb_caps_reg =  pci_getl_func(0, 24, 3, 0xe8);
7848031591dSSrihari Venkatesan 		if ((cpi->cpi_model < 8) || BITX(nb_caps_reg, 29, 29) == 0) {
7858031591dSSrihari Venkatesan 			/* Single-node */
7861fbe4a4fSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5,
7871fbe4a4fSSrihari Venkatesan 			    coreidsz);
7888031591dSSrihari Venkatesan 			cpi->cpi_chipid = cpi->cpi_procnodeid;
7898031591dSSrihari Venkatesan 		} else {
7908031591dSSrihari Venkatesan 
7918031591dSSrihari Venkatesan 			/*
7928031591dSSrihari Venkatesan 			 * Multi-node revision D (2 nodes per package
7938031591dSSrihari Venkatesan 			 * are supported)
7948031591dSSrihari Venkatesan 			 */
7958031591dSSrihari Venkatesan 			cpi->cpi_procnodes_per_pkg = 2;
7968031591dSSrihari Venkatesan 
7978031591dSSrihari Venkatesan 			first_half = (cpi->cpi_pkgcoreid <=
7988031591dSSrihari Venkatesan 			    (cpi->cpi_ncore_per_chip/2 - 1));
7998031591dSSrihari Venkatesan 
8008031591dSSrihari Venkatesan 			if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) {
8018031591dSSrihari Venkatesan 				/* We are BSP */
8028031591dSSrihari Venkatesan 				cpi->cpi_procnodeid = (first_half ? 0 : 1);
8038031591dSSrihari Venkatesan 				cpi->cpi_chipid = cpi->cpi_procnodeid >> 1;
8048031591dSSrihari Venkatesan 			} else {
8058031591dSSrihari Venkatesan 
8068031591dSSrihari Venkatesan 				/* We are AP */
8078031591dSSrihari Venkatesan 				/* NodeId[2:1] bits to use for reading F3xe8 */
8088031591dSSrihari Venkatesan 				node2_1 = BITX(cpi->cpi_apicid, 5, 4) << 1;
8098031591dSSrihari Venkatesan 
8108031591dSSrihari Venkatesan 				nb_caps_reg =
8118031591dSSrihari Venkatesan 				    pci_getl_func(0, 24 + node2_1, 3, 0xe8);
8128031591dSSrihari Venkatesan 
8138031591dSSrihari Venkatesan 				/*
8148031591dSSrihari Venkatesan 				 * Check IntNodeNum bit (31:30, but bit 31 is
8158031591dSSrihari Venkatesan 				 * always 0 on dual-node processors)
8168031591dSSrihari Venkatesan 				 */
8178031591dSSrihari Venkatesan 				if (BITX(nb_caps_reg, 30, 30) == 0)
8188031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
8198031591dSSrihari Venkatesan 					    !first_half;
8208031591dSSrihari Venkatesan 				else
8218031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
8228031591dSSrihari Venkatesan 					    first_half;
8238031591dSSrihari Venkatesan 
8248031591dSSrihari Venkatesan 				cpi->cpi_chipid = cpi->cpi_procnodeid >> 1;
8258031591dSSrihari Venkatesan 			}
8268031591dSSrihari Venkatesan 		}
8278031591dSSrihari Venkatesan 	} else if (cpi->cpi_family >= 0x11) {
8288031591dSSrihari Venkatesan 		cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
8298031591dSSrihari Venkatesan 		cpi->cpi_chipid = cpi->cpi_procnodeid;
8308031591dSSrihari Venkatesan 	} else {
8318031591dSSrihari Venkatesan 		cpi->cpi_procnodeid = 0;
8328031591dSSrihari Venkatesan 		cpi->cpi_chipid = cpi->cpi_procnodeid;
8338031591dSSrihari Venkatesan 	}
8348031591dSSrihari Venkatesan }
8358031591dSSrihari Venkatesan 
8367af88ac7SKuriakose Kuruvilla /*
8377af88ac7SKuriakose Kuruvilla  * Setup XFeature_Enabled_Mask register. Required by xsave feature.
8387af88ac7SKuriakose Kuruvilla  */
8397af88ac7SKuriakose Kuruvilla void
8407af88ac7SKuriakose Kuruvilla setup_xfem(void)
8417af88ac7SKuriakose Kuruvilla {
8427af88ac7SKuriakose Kuruvilla 	uint64_t flags = XFEATURE_LEGACY_FP;
8437af88ac7SKuriakose Kuruvilla 
8447af88ac7SKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
8457af88ac7SKuriakose Kuruvilla 
8467af88ac7SKuriakose Kuruvilla 	if (is_x86_feature(x86_featureset, X86FSET_SSE))
8477af88ac7SKuriakose Kuruvilla 		flags |= XFEATURE_SSE;
8487af88ac7SKuriakose Kuruvilla 
8497af88ac7SKuriakose Kuruvilla 	if (is_x86_feature(x86_featureset, X86FSET_AVX))
8507af88ac7SKuriakose Kuruvilla 		flags |= XFEATURE_AVX;
8517af88ac7SKuriakose Kuruvilla 
8527af88ac7SKuriakose Kuruvilla 	set_xcr(XFEATURE_ENABLED_MASK, flags);
8537af88ac7SKuriakose Kuruvilla 
8547af88ac7SKuriakose Kuruvilla 	xsave_bv_all = flags;
8557af88ac7SKuriakose Kuruvilla }
8567af88ac7SKuriakose Kuruvilla 
857*dfea898aSKuriakose Kuruvilla void
858*dfea898aSKuriakose Kuruvilla cpuid_pass1(cpu_t *cpu, uchar_t *featureset)
8597c478bd9Sstevel@tonic-gate {
8607c478bd9Sstevel@tonic-gate 	uint32_t mask_ecx, mask_edx;
8617c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
8628949bcd6Sandrei 	struct cpuid_regs *cp;
8637c478bd9Sstevel@tonic-gate 	int xcpuid;
864843e1988Sjohnlev #if !defined(__xpv)
8655b8a6efeSbholler 	extern int idle_cpu_prefer_mwait;
866843e1988Sjohnlev #endif
867ae115bc7Smrj 
86889e921d5SKuriakose Kuruvilla #if !defined(__xpv)
86989e921d5SKuriakose Kuruvilla 	determine_platform();
87089e921d5SKuriakose Kuruvilla #endif
8717c478bd9Sstevel@tonic-gate 	/*
872a3114836SGerry Liu 	 * Space statically allocated for BSP, ensure pointer is set
8737c478bd9Sstevel@tonic-gate 	 */
8747417cfdeSKuriakose Kuruvilla 	if (cpu->cpu_id == 0) {
8757417cfdeSKuriakose Kuruvilla 		if (cpu->cpu_m.mcpu_cpi == NULL)
876ae115bc7Smrj 			cpu->cpu_m.mcpu_cpi = &cpuid_info0;
8777417cfdeSKuriakose Kuruvilla 	}
8787417cfdeSKuriakose Kuruvilla 
8797417cfdeSKuriakose Kuruvilla 	add_x86_feature(featureset, X86FSET_CPUID);
8807417cfdeSKuriakose Kuruvilla 
881ae115bc7Smrj 	cpi = cpu->cpu_m.mcpu_cpi;
882ae115bc7Smrj 	ASSERT(cpi != NULL);
8837c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[0];
8848949bcd6Sandrei 	cp->cp_eax = 0;
8858949bcd6Sandrei 	cpi->cpi_maxeax = __cpuid_insn(cp);
8867c478bd9Sstevel@tonic-gate 	{
8877c478bd9Sstevel@tonic-gate 		uint32_t *iptr = (uint32_t *)cpi->cpi_vendorstr;
8887c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ebx;
8897c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_edx;
8907c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ecx;
8917c478bd9Sstevel@tonic-gate 		*(char *)&cpi->cpi_vendorstr[12] = '\0';
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 
894e4b86885SCheng Sean Ye 	cpi->cpi_vendor = _cpuid_vendorstr_to_vendorcode(cpi->cpi_vendorstr);
8957c478bd9Sstevel@tonic-gate 	x86_vendor = cpi->cpi_vendor; /* for compatibility */
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	/*
8987c478bd9Sstevel@tonic-gate 	 * Limit the range in case of weird hardware
8997c478bd9Sstevel@tonic-gate 	 */
9007c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax > CPI_MAXEAX_MAX)
9017c478bd9Sstevel@tonic-gate 		cpi->cpi_maxeax = CPI_MAXEAX_MAX;
9027c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
9037c478bd9Sstevel@tonic-gate 		goto pass1_done;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[1];
9068949bcd6Sandrei 	cp->cp_eax = 1;
9078949bcd6Sandrei 	(void) __cpuid_insn(cp);
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	/*
9107c478bd9Sstevel@tonic-gate 	 * Extract identifying constants for easy access.
9117c478bd9Sstevel@tonic-gate 	 */
9127c478bd9Sstevel@tonic-gate 	cpi->cpi_model = CPI_MODEL(cpi);
9137c478bd9Sstevel@tonic-gate 	cpi->cpi_family = CPI_FAMILY(cpi);
9147c478bd9Sstevel@tonic-gate 
9155ff02082Sdmick 	if (cpi->cpi_family == 0xf)
9167c478bd9Sstevel@tonic-gate 		cpi->cpi_family += CPI_FAMILY_XTD(cpi);
9175ff02082Sdmick 
91868c91426Sdmick 	/*
919875b116eSkchow 	 * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
92068c91426Sdmick 	 * Intel, and presumably everyone else, uses model == 0xf, as
92168c91426Sdmick 	 * one would expect (max value means possible overflow).  Sigh.
92268c91426Sdmick 	 */
92368c91426Sdmick 
92468c91426Sdmick 	switch (cpi->cpi_vendor) {
925bf91205bSksadhukh 	case X86_VENDOR_Intel:
926bf91205bSksadhukh 		if (IS_EXTENDED_MODEL_INTEL(cpi))
927bf91205bSksadhukh 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
928447af253Sksadhukh 		break;
92968c91426Sdmick 	case X86_VENDOR_AMD:
930875b116eSkchow 		if (CPI_FAMILY(cpi) == 0xf)
93168c91426Sdmick 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
93268c91426Sdmick 		break;
93368c91426Sdmick 	default:
9345ff02082Sdmick 		if (cpi->cpi_model == 0xf)
9357c478bd9Sstevel@tonic-gate 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
93668c91426Sdmick 		break;
93768c91426Sdmick 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	cpi->cpi_step = CPI_STEP(cpi);
9407c478bd9Sstevel@tonic-gate 	cpi->cpi_brandid = CPI_BRANDID(cpi);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	/*
9437c478bd9Sstevel@tonic-gate 	 * *default* assumptions:
9447c478bd9Sstevel@tonic-gate 	 * - believe %edx feature word
9457c478bd9Sstevel@tonic-gate 	 * - ignore %ecx feature word
9467c478bd9Sstevel@tonic-gate 	 * - 32-bit virtual and physical addressing
9477c478bd9Sstevel@tonic-gate 	 */
9487c478bd9Sstevel@tonic-gate 	mask_edx = 0xffffffff;
9497c478bd9Sstevel@tonic-gate 	mask_ecx = 0;
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	cpi->cpi_pabits = cpi->cpi_vabits = 32;
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
9547c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
9557c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
9567c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P5;
9575ff02082Sdmick 		else if (IS_LEGACY_P6(cpi)) {
9587c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P6;
9597c478bd9Sstevel@tonic-gate 			pentiumpro_bug4046376 = 1;
9607c478bd9Sstevel@tonic-gate 			pentiumpro_bug4064495 = 1;
9617c478bd9Sstevel@tonic-gate 			/*
9627c478bd9Sstevel@tonic-gate 			 * Clear the SEP bit when it was set erroneously
9637c478bd9Sstevel@tonic-gate 			 */
9647c478bd9Sstevel@tonic-gate 			if (cpi->cpi_model < 3 && cpi->cpi_step < 3)
9657c478bd9Sstevel@tonic-gate 				cp->cp_edx &= ~CPUID_INTC_EDX_SEP;
9665ff02082Sdmick 		} else if (IS_NEW_F6(cpi) || cpi->cpi_family == 0xf) {
9677c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P4;
9687c478bd9Sstevel@tonic-gate 			/*
9697c478bd9Sstevel@tonic-gate 			 * We don't currently depend on any of the %ecx
9707c478bd9Sstevel@tonic-gate 			 * features until Prescott, so we'll only check
9717c478bd9Sstevel@tonic-gate 			 * this from P4 onwards.  We might want to revisit
9727c478bd9Sstevel@tonic-gate 			 * that idea later.
9737c478bd9Sstevel@tonic-gate 			 */
9747c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
9757c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family > 0xf)
9767c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
9777c622d23Sbholler 		/*
9787c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
9797c622d23Sbholler 		 * to obtain the monitor linesize.
9807c622d23Sbholler 		 */
9817c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
9827c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
9837c478bd9Sstevel@tonic-gate 		break;
9847c478bd9Sstevel@tonic-gate 	case X86_VENDOR_IntelClone:
9857c478bd9Sstevel@tonic-gate 	default:
9867c478bd9Sstevel@tonic-gate 		break;
9877c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
9887c478bd9Sstevel@tonic-gate #if defined(OPTERON_ERRATUM_108)
9897c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 0xf && cpi->cpi_model == 0xe) {
9907c478bd9Sstevel@tonic-gate 			cp->cp_eax = (0xf0f & cp->cp_eax) | 0xc0;
9917c478bd9Sstevel@tonic-gate 			cpi->cpi_model = 0xc;
9927c478bd9Sstevel@tonic-gate 		} else
9937c478bd9Sstevel@tonic-gate #endif
9947c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5) {
9957c478bd9Sstevel@tonic-gate 			/*
9967c478bd9Sstevel@tonic-gate 			 * AMD K5 and K6
9977c478bd9Sstevel@tonic-gate 			 *
9987c478bd9Sstevel@tonic-gate 			 * These CPUs have an incomplete implementation
9997c478bd9Sstevel@tonic-gate 			 * of MCA/MCE which we mask away.
10007c478bd9Sstevel@tonic-gate 			 */
10018949bcd6Sandrei 			mask_edx &= ~(CPUID_INTC_EDX_MCE | CPUID_INTC_EDX_MCA);
10028949bcd6Sandrei 
10037c478bd9Sstevel@tonic-gate 			/*
10047c478bd9Sstevel@tonic-gate 			 * Model 0 uses the wrong (APIC) bit
10057c478bd9Sstevel@tonic-gate 			 * to indicate PGE.  Fix it here.
10067c478bd9Sstevel@tonic-gate 			 */
10078949bcd6Sandrei 			if (cpi->cpi_model == 0) {
10087c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x200) {
10097c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x200;
10107c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_INTC_EDX_PGE;
10117c478bd9Sstevel@tonic-gate 				}
10127c478bd9Sstevel@tonic-gate 			}
10138949bcd6Sandrei 
10148949bcd6Sandrei 			/*
10158949bcd6Sandrei 			 * Early models had problems w/ MMX; disable.
10168949bcd6Sandrei 			 */
10178949bcd6Sandrei 			if (cpi->cpi_model < 6)
10188949bcd6Sandrei 				mask_edx &= ~CPUID_INTC_EDX_MMX;
10198949bcd6Sandrei 		}
10208949bcd6Sandrei 
10218949bcd6Sandrei 		/*
10228949bcd6Sandrei 		 * For newer families, SSE3 and CX16, at least, are valid;
10238949bcd6Sandrei 		 * enable all
10248949bcd6Sandrei 		 */
10258949bcd6Sandrei 		if (cpi->cpi_family >= 0xf)
10268949bcd6Sandrei 			mask_ecx = 0xffffffff;
10277c622d23Sbholler 		/*
10287c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
10297c622d23Sbholler 		 * to obtain the monitor linesize.
10307c622d23Sbholler 		 */
10317c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
10327c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
10335b8a6efeSbholler 
1034843e1988Sjohnlev #if !defined(__xpv)
10355b8a6efeSbholler 		/*
10365b8a6efeSbholler 		 * Do not use MONITOR/MWAIT to halt in the idle loop on any AMD
10375b8a6efeSbholler 		 * processors.  AMD does not intend MWAIT to be used in the cpu
10385b8a6efeSbholler 		 * idle loop on current and future processors.  10h and future
10395b8a6efeSbholler 		 * AMD processors use more power in MWAIT than HLT.
10405b8a6efeSbholler 		 * Pre-family-10h Opterons do not have the MWAIT instruction.
10415b8a6efeSbholler 		 */
10425b8a6efeSbholler 		idle_cpu_prefer_mwait = 0;
1043843e1988Sjohnlev #endif
10445b8a6efeSbholler 
10457c478bd9Sstevel@tonic-gate 		break;
10467c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
10477c478bd9Sstevel@tonic-gate 		/*
10487c478bd9Sstevel@tonic-gate 		 * workaround the NT workaround in CMS 4.1
10497c478bd9Sstevel@tonic-gate 		 */
10507c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4 &&
10517c478bd9Sstevel@tonic-gate 		    (cpi->cpi_step == 2 || cpi->cpi_step == 3))
10527c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
10537c478bd9Sstevel@tonic-gate 		break;
10547c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
10557c478bd9Sstevel@tonic-gate 		/*
10567c478bd9Sstevel@tonic-gate 		 * workaround the NT workarounds again
10577c478bd9Sstevel@tonic-gate 		 */
10587c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 6)
10597c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
10607c478bd9Sstevel@tonic-gate 		break;
10617c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
10627c478bd9Sstevel@tonic-gate 		/*
10637c478bd9Sstevel@tonic-gate 		 * We rely heavily on the probing in locore
10647c478bd9Sstevel@tonic-gate 		 * to actually figure out what parts, if any,
10657c478bd9Sstevel@tonic-gate 		 * of the Cyrix cpuid instruction to believe.
10667c478bd9Sstevel@tonic-gate 		 */
10677c478bd9Sstevel@tonic-gate 		switch (x86_type) {
10687c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_486:
10697c478bd9Sstevel@tonic-gate 			mask_edx = 0;
10707c478bd9Sstevel@tonic-gate 			break;
10717c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86:
10727c478bd9Sstevel@tonic-gate 			mask_edx = 0;
10737c478bd9Sstevel@tonic-gate 			break;
10747c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86L:
10757c478bd9Sstevel@tonic-gate 			mask_edx =
10767c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
10777c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8;
10787c478bd9Sstevel@tonic-gate 			break;
10797c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86MX:
10807c478bd9Sstevel@tonic-gate 			mask_edx =
10817c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
10827c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
10837c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
10847c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
10857c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
10867c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
10877c478bd9Sstevel@tonic-gate 			break;
10887c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_GXm:
10897c478bd9Sstevel@tonic-gate 			mask_edx =
10907c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
10917c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
10927c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
10937c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
10947c478bd9Sstevel@tonic-gate 			break;
10957c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MediaGX:
10967c478bd9Sstevel@tonic-gate 			break;
10977c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MII:
10987c478bd9Sstevel@tonic-gate 		case X86_TYPE_VIA_CYRIX_III:
10997c478bd9Sstevel@tonic-gate 			mask_edx =
11007c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11017c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_TSC |
11027c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11037c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11047c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
11057c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11067c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11077c478bd9Sstevel@tonic-gate 			break;
11087c478bd9Sstevel@tonic-gate 		default:
11097c478bd9Sstevel@tonic-gate 			break;
11107c478bd9Sstevel@tonic-gate 		}
11117c478bd9Sstevel@tonic-gate 		break;
11127c478bd9Sstevel@tonic-gate 	}
11137c478bd9Sstevel@tonic-gate 
1114843e1988Sjohnlev #if defined(__xpv)
1115843e1988Sjohnlev 	/*
1116843e1988Sjohnlev 	 * Do not support MONITOR/MWAIT under a hypervisor
1117843e1988Sjohnlev 	 */
1118843e1988Sjohnlev 	mask_ecx &= ~CPUID_INTC_ECX_MON;
11197af88ac7SKuriakose Kuruvilla 	/*
11207af88ac7SKuriakose Kuruvilla 	 * Do not support XSAVE under a hypervisor for now
11217af88ac7SKuriakose Kuruvilla 	 */
11227af88ac7SKuriakose Kuruvilla 	xsave_force_disable = B_TRUE;
11237af88ac7SKuriakose Kuruvilla 
1124843e1988Sjohnlev #endif	/* __xpv */
1125843e1988Sjohnlev 
11267af88ac7SKuriakose Kuruvilla 	if (xsave_force_disable) {
11277af88ac7SKuriakose Kuruvilla 		mask_ecx &= ~CPUID_INTC_ECX_XSAVE;
11287af88ac7SKuriakose Kuruvilla 		mask_ecx &= ~CPUID_INTC_ECX_AVX;
11297af88ac7SKuriakose Kuruvilla 	}
11307af88ac7SKuriakose Kuruvilla 
11317c478bd9Sstevel@tonic-gate 	/*
11327c478bd9Sstevel@tonic-gate 	 * Now we've figured out the masks that determine
11337c478bd9Sstevel@tonic-gate 	 * which bits we choose to believe, apply the masks
11347c478bd9Sstevel@tonic-gate 	 * to the feature words, then map the kernel's view
11357c478bd9Sstevel@tonic-gate 	 * of these feature words into its feature word.
11367c478bd9Sstevel@tonic-gate 	 */
11377c478bd9Sstevel@tonic-gate 	cp->cp_edx &= mask_edx;
11387c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= mask_ecx;
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 	/*
1141ae115bc7Smrj 	 * apply any platform restrictions (we don't call this
1142ae115bc7Smrj 	 * immediately after __cpuid_insn here, because we need the
1143ae115bc7Smrj 	 * workarounds applied above first)
11447c478bd9Sstevel@tonic-gate 	 */
1145ae115bc7Smrj 	platform_cpuid_mangle(cpi->cpi_vendor, 1, cp);
11467c478bd9Sstevel@tonic-gate 
1147ae115bc7Smrj 	/*
1148ae115bc7Smrj 	 * fold in overrides from the "eeprom" mechanism
1149ae115bc7Smrj 	 */
11507c478bd9Sstevel@tonic-gate 	cp->cp_edx |= cpuid_feature_edx_include;
11517c478bd9Sstevel@tonic-gate 	cp->cp_edx &= ~cpuid_feature_edx_exclude;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	cp->cp_ecx |= cpuid_feature_ecx_include;
11547c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= ~cpuid_feature_ecx_exclude;
11557c478bd9Sstevel@tonic-gate 
11567417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PSE) {
11577417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_LARGEPAGE);
11587417cfdeSKuriakose Kuruvilla 	}
11597417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_TSC) {
11607417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_TSC);
11617417cfdeSKuriakose Kuruvilla 	}
11627417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MSR) {
11637417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MSR);
11647417cfdeSKuriakose Kuruvilla 	}
11657417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MTRR) {
11667417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MTRR);
11677417cfdeSKuriakose Kuruvilla 	}
11687417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PGE) {
11697417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PGE);
11707417cfdeSKuriakose Kuruvilla 	}
11717417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CMOV) {
11727417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMOV);
11737417cfdeSKuriakose Kuruvilla 	}
11747417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MMX) {
11757417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MMX);
11767417cfdeSKuriakose Kuruvilla 	}
11777c478bd9Sstevel@tonic-gate 	if ((cp->cp_edx & CPUID_INTC_EDX_MCE) != 0 &&
11787417cfdeSKuriakose Kuruvilla 	    (cp->cp_edx & CPUID_INTC_EDX_MCA) != 0) {
11797417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MCA);
11807417cfdeSKuriakose Kuruvilla 	}
11817417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAE) {
11827417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAE);
11837417cfdeSKuriakose Kuruvilla 	}
11847417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CX8) {
11857417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX8);
11867417cfdeSKuriakose Kuruvilla 	}
11877417cfdeSKuriakose Kuruvilla 	if (cp->cp_ecx & CPUID_INTC_ECX_CX16) {
11887417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX16);
11897417cfdeSKuriakose Kuruvilla 	}
11907417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAT) {
11917417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAT);
11927417cfdeSKuriakose Kuruvilla 	}
11937417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_SEP) {
11947417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_SEP);
11957417cfdeSKuriakose Kuruvilla 	}
11967c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_FXSR) {
11977c478bd9Sstevel@tonic-gate 		/*
11987c478bd9Sstevel@tonic-gate 		 * In our implementation, fxsave/fxrstor
11997c478bd9Sstevel@tonic-gate 		 * are prerequisites before we'll even
12007c478bd9Sstevel@tonic-gate 		 * try and do SSE things.
12017c478bd9Sstevel@tonic-gate 		 */
12027417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE) {
12037417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE);
12047417cfdeSKuriakose Kuruvilla 		}
12057417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE2) {
12067417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE2);
12077417cfdeSKuriakose Kuruvilla 		}
12087417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) {
12097417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE3);
12107417cfdeSKuriakose Kuruvilla 		}
1211d0f8ff6eSkk208521 		if (cpi->cpi_vendor == X86_VENDOR_Intel) {
12127417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) {
12137417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSSE3);
12147417cfdeSKuriakose Kuruvilla 			}
12157417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) {
12167417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4_1);
12177417cfdeSKuriakose Kuruvilla 			}
12187417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) {
12197417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4_2);
12207417cfdeSKuriakose Kuruvilla 			}
12217417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_AES) {
12227417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_AES);
12237417cfdeSKuriakose Kuruvilla 			}
12247417cfdeSKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) {
12257417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_PCLMULQDQ);
1226d0f8ff6eSkk208521 			}
12277af88ac7SKuriakose Kuruvilla 
12287af88ac7SKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) {
12297af88ac7SKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_XSAVE);
12307af88ac7SKuriakose Kuruvilla 				/* We only test AVX when there is XSAVE */
12317af88ac7SKuriakose Kuruvilla 				if (cp->cp_ecx & CPUID_INTC_ECX_AVX) {
12327af88ac7SKuriakose Kuruvilla 					add_x86_feature(featureset,
12337af88ac7SKuriakose Kuruvilla 					    X86FSET_AVX);
12347af88ac7SKuriakose Kuruvilla 				}
12357af88ac7SKuriakose Kuruvilla 			}
12367c478bd9Sstevel@tonic-gate 		}
12377417cfdeSKuriakose Kuruvilla 	}
12387417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_DE) {
12397417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_DE);
12407417cfdeSKuriakose Kuruvilla 	}
12411d1a3942SBill Holler #if !defined(__xpv)
1242f98fbcecSbholler 	if (cp->cp_ecx & CPUID_INTC_ECX_MON) {
12431d1a3942SBill Holler 
12441d1a3942SBill Holler 		/*
12451d1a3942SBill Holler 		 * We require the CLFLUSH instruction for erratum workaround
12461d1a3942SBill Holler 		 * to use MONITOR/MWAIT.
12471d1a3942SBill Holler 		 */
12481d1a3942SBill Holler 		if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
1249f98fbcecSbholler 			cpi->cpi_mwait.support |= MWAIT_SUPPORT;
12507417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_MWAIT);
12511d1a3942SBill Holler 		} else {
12521d1a3942SBill Holler 			extern int idle_cpu_assert_cflush_monitor;
12531d1a3942SBill Holler 
12541d1a3942SBill Holler 			/*
12551d1a3942SBill Holler 			 * All processors we are aware of which have
12561d1a3942SBill Holler 			 * MONITOR/MWAIT also have CLFLUSH.
12571d1a3942SBill Holler 			 */
12581d1a3942SBill Holler 			if (idle_cpu_assert_cflush_monitor) {
12591d1a3942SBill Holler 				ASSERT((cp->cp_ecx & CPUID_INTC_ECX_MON) &&
12601d1a3942SBill Holler 				    (cp->cp_edx & CPUID_INTC_EDX_CLFSH));
1261f98fbcecSbholler 			}
12621d1a3942SBill Holler 		}
12631d1a3942SBill Holler 	}
12641d1a3942SBill Holler #endif	/* __xpv */
12657c478bd9Sstevel@tonic-gate 
126686c1f4dcSVikram Hegde 	/*
126786c1f4dcSVikram Hegde 	 * Only need it first time, rest of the cpus would follow suite.
126886c1f4dcSVikram Hegde 	 * we only capture this for the bootcpu.
126986c1f4dcSVikram Hegde 	 */
127086c1f4dcSVikram Hegde 	if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
12717417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CLFSH);
127286c1f4dcSVikram Hegde 		x86_clflush_size = (BITX(cp->cp_ebx, 15, 8) * 8);
127386c1f4dcSVikram Hegde 	}
12747417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_PAE))
12757c478bd9Sstevel@tonic-gate 		cpi->cpi_pabits = 36;
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 	/*
12787c478bd9Sstevel@tonic-gate 	 * Hyperthreading configuration is slightly tricky on Intel
12797c478bd9Sstevel@tonic-gate 	 * and pure clones, and even trickier on AMD.
12807c478bd9Sstevel@tonic-gate 	 *
12817c478bd9Sstevel@tonic-gate 	 * (AMD chose to set the HTT bit on their CMP processors,
12827c478bd9Sstevel@tonic-gate 	 * even though they're not actually hyperthreaded.  Thus it
12837c478bd9Sstevel@tonic-gate 	 * takes a bit more work to figure out what's really going
1284ae115bc7Smrj 	 * on ... see the handling of the CMP_LGCY bit below)
12857c478bd9Sstevel@tonic-gate 	 */
12867c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_HTT) {
12877c478bd9Sstevel@tonic-gate 		cpi->cpi_ncpu_per_chip = CPI_CPU_COUNT(cpi);
12887c478bd9Sstevel@tonic-gate 		if (cpi->cpi_ncpu_per_chip > 1)
12897417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_HTT);
12908949bcd6Sandrei 	} else {
12918949bcd6Sandrei 		cpi->cpi_ncpu_per_chip = 1;
12927c478bd9Sstevel@tonic-gate 	}
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	/*
12957c478bd9Sstevel@tonic-gate 	 * Work on the "extended" feature information, doing
12967c478bd9Sstevel@tonic-gate 	 * some basic initialization for cpuid_pass2()
12977c478bd9Sstevel@tonic-gate 	 */
12987c478bd9Sstevel@tonic-gate 	xcpuid = 0;
12997c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
13007c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
13015ff02082Sdmick 		if (IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf)
13027c478bd9Sstevel@tonic-gate 			xcpuid++;
13037c478bd9Sstevel@tonic-gate 		break;
13047c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
13057c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
13067c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
13077c478bd9Sstevel@tonic-gate 			xcpuid++;
13087c478bd9Sstevel@tonic-gate 		break;
13097c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
13107c478bd9Sstevel@tonic-gate 		/*
13117c478bd9Sstevel@tonic-gate 		 * Only these Cyrix CPUs are -known- to support
13127c478bd9Sstevel@tonic-gate 		 * extended cpuid operations.
13137c478bd9Sstevel@tonic-gate 		 */
13147c478bd9Sstevel@tonic-gate 		if (x86_type == X86_TYPE_VIA_CYRIX_III ||
13157c478bd9Sstevel@tonic-gate 		    x86_type == X86_TYPE_CYRIX_GXm)
13167c478bd9Sstevel@tonic-gate 			xcpuid++;
13177c478bd9Sstevel@tonic-gate 		break;
13187c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
13197c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
13207c478bd9Sstevel@tonic-gate 	default:
13217c478bd9Sstevel@tonic-gate 		xcpuid++;
13227c478bd9Sstevel@tonic-gate 		break;
13237c478bd9Sstevel@tonic-gate 	}
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	if (xcpuid) {
13267c478bd9Sstevel@tonic-gate 		cp = &cpi->cpi_extd[0];
13278949bcd6Sandrei 		cp->cp_eax = 0x80000000;
13288949bcd6Sandrei 		cpi->cpi_xmaxeax = __cpuid_insn(cp);
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax & 0x80000000) {
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax > CPI_XMAXEAX_MAX)
13347c478bd9Sstevel@tonic-gate 			cpi->cpi_xmaxeax = CPI_XMAXEAX_MAX;
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
13377c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
13387c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
13397c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000001)
13407c478bd9Sstevel@tonic-gate 				break;
13417c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[1];
13428949bcd6Sandrei 			cp->cp_eax = 0x80000001;
13438949bcd6Sandrei 			(void) __cpuid_insn(cp);
1344ae115bc7Smrj 
13457c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
13467c478bd9Sstevel@tonic-gate 			    cpi->cpi_family == 5 &&
13477c478bd9Sstevel@tonic-gate 			    cpi->cpi_model == 6 &&
13487c478bd9Sstevel@tonic-gate 			    cpi->cpi_step == 6) {
13497c478bd9Sstevel@tonic-gate 				/*
13507c478bd9Sstevel@tonic-gate 				 * K6 model 6 uses bit 10 to indicate SYSC
13517c478bd9Sstevel@tonic-gate 				 * Later models use bit 11. Fix it here.
13527c478bd9Sstevel@tonic-gate 				 */
13537c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x400) {
13547c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x400;
13557c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_AMD_EDX_SYSC;
13567c478bd9Sstevel@tonic-gate 				}
13577c478bd9Sstevel@tonic-gate 			}
13587c478bd9Sstevel@tonic-gate 
1359ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000001, cp);
1360ae115bc7Smrj 
13617c478bd9Sstevel@tonic-gate 			/*
13627c478bd9Sstevel@tonic-gate 			 * Compute the additions to the kernel's feature word.
13637c478bd9Sstevel@tonic-gate 			 */
13647417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_NX) {
13657417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_NX);
13667417cfdeSKuriakose Kuruvilla 			}
13677c478bd9Sstevel@tonic-gate 
136819397407SSherry Moore 			/*
136919397407SSherry Moore 			 * Regardless whether or not we boot 64-bit,
137019397407SSherry Moore 			 * we should have a way to identify whether
137119397407SSherry Moore 			 * the CPU is capable of running 64-bit.
137219397407SSherry Moore 			 */
13737417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_LM) {
13747417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_64);
13757417cfdeSKuriakose Kuruvilla 			}
137619397407SSherry Moore 
137702bc52beSkchow #if defined(__amd64)
137802bc52beSkchow 			/* 1 GB large page - enable only for 64 bit kernel */
13797417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_1GPG) {
13807417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_1GPG);
13817417cfdeSKuriakose Kuruvilla 			}
138202bc52beSkchow #endif
138302bc52beSkchow 
1384f8801251Skk208521 			if ((cpi->cpi_vendor == X86_VENDOR_AMD) &&
1385f8801251Skk208521 			    (cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_FXSR) &&
13867417cfdeSKuriakose Kuruvilla 			    (cp->cp_ecx & CPUID_AMD_ECX_SSE4A)) {
13877417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4A);
13887417cfdeSKuriakose Kuruvilla 			}
1389f8801251Skk208521 
13907c478bd9Sstevel@tonic-gate 			/*
1391ae115bc7Smrj 			 * If both the HTT and CMP_LGCY bits are set,
13928949bcd6Sandrei 			 * then we're not actually HyperThreaded.  Read
13938949bcd6Sandrei 			 * "AMD CPUID Specification" for more details.
13947c478bd9Sstevel@tonic-gate 			 */
13957c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
13967417cfdeSKuriakose Kuruvilla 			    is_x86_feature(featureset, X86FSET_HTT) &&
1397ae115bc7Smrj 			    (cp->cp_ecx & CPUID_AMD_ECX_CMP_LGCY)) {
13987417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_HTT);
13997417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_CMP);
14008949bcd6Sandrei 			}
1401ae115bc7Smrj #if defined(__amd64)
14027c478bd9Sstevel@tonic-gate 			/*
14037c478bd9Sstevel@tonic-gate 			 * It's really tricky to support syscall/sysret in
14047c478bd9Sstevel@tonic-gate 			 * the i386 kernel; we rely on sysenter/sysexit
14057c478bd9Sstevel@tonic-gate 			 * instead.  In the amd64 kernel, things are -way-
14067c478bd9Sstevel@tonic-gate 			 * better.
14077c478bd9Sstevel@tonic-gate 			 */
14087417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_SYSC) {
14097417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_ASYSC);
14107417cfdeSKuriakose Kuruvilla 			}
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 			/*
14137c478bd9Sstevel@tonic-gate 			 * While we're thinking about system calls, note
14147c478bd9Sstevel@tonic-gate 			 * that AMD processors don't support sysenter
14157c478bd9Sstevel@tonic-gate 			 * in long mode at all, so don't try to program them.
14167c478bd9Sstevel@tonic-gate 			 */
14177417cfdeSKuriakose Kuruvilla 			if (x86_vendor == X86_VENDOR_AMD) {
14187417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_SEP);
14197417cfdeSKuriakose Kuruvilla 			}
14207c478bd9Sstevel@tonic-gate #endif
14217417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_TSCP) {
14227417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_TSCP);
14237417cfdeSKuriakose Kuruvilla 			}
14247c478bd9Sstevel@tonic-gate 			break;
14257c478bd9Sstevel@tonic-gate 		default:
14267c478bd9Sstevel@tonic-gate 			break;
14277c478bd9Sstevel@tonic-gate 		}
14287c478bd9Sstevel@tonic-gate 
14298949bcd6Sandrei 		/*
14308949bcd6Sandrei 		 * Get CPUID data about processor cores and hyperthreads.
14318949bcd6Sandrei 		 */
14327c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
14337c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
14348949bcd6Sandrei 			if (cpi->cpi_maxeax >= 4) {
14358949bcd6Sandrei 				cp = &cpi->cpi_std[4];
14368949bcd6Sandrei 				cp->cp_eax = 4;
14378949bcd6Sandrei 				cp->cp_ecx = 0;
14388949bcd6Sandrei 				(void) __cpuid_insn(cp);
1439ae115bc7Smrj 				platform_cpuid_mangle(cpi->cpi_vendor, 4, cp);
14408949bcd6Sandrei 			}
14418949bcd6Sandrei 			/*FALLTHROUGH*/
14427c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
14437c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000008)
14447c478bd9Sstevel@tonic-gate 				break;
14457c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[8];
14468949bcd6Sandrei 			cp->cp_eax = 0x80000008;
14478949bcd6Sandrei 			(void) __cpuid_insn(cp);
1448ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000008, cp);
1449ae115bc7Smrj 
14507c478bd9Sstevel@tonic-gate 			/*
14517c478bd9Sstevel@tonic-gate 			 * Virtual and physical address limits from
14527c478bd9Sstevel@tonic-gate 			 * cpuid override previously guessed values.
14537c478bd9Sstevel@tonic-gate 			 */
14547c478bd9Sstevel@tonic-gate 			cpi->cpi_pabits = BITX(cp->cp_eax, 7, 0);
14557c478bd9Sstevel@tonic-gate 			cpi->cpi_vabits = BITX(cp->cp_eax, 15, 8);
14567c478bd9Sstevel@tonic-gate 			break;
14577c478bd9Sstevel@tonic-gate 		default:
14587c478bd9Sstevel@tonic-gate 			break;
14597c478bd9Sstevel@tonic-gate 		}
14608949bcd6Sandrei 
1461d129bde2Sesaxe 		/*
1462d129bde2Sesaxe 		 * Derive the number of cores per chip
1463d129bde2Sesaxe 		 */
14648949bcd6Sandrei 		switch (cpi->cpi_vendor) {
14658949bcd6Sandrei 		case X86_VENDOR_Intel:
14668949bcd6Sandrei 			if (cpi->cpi_maxeax < 4) {
14678949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
14688949bcd6Sandrei 				break;
14698949bcd6Sandrei 			} else {
14708949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
14718949bcd6Sandrei 				    BITX((cpi)->cpi_std[4].cp_eax, 31, 26) + 1;
14728949bcd6Sandrei 			}
14738949bcd6Sandrei 			break;
14748949bcd6Sandrei 		case X86_VENDOR_AMD:
14758949bcd6Sandrei 			if (cpi->cpi_xmaxeax < 0x80000008) {
14768949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
14778949bcd6Sandrei 				break;
14788949bcd6Sandrei 			} else {
147910569901Sgavinm 				/*
148010569901Sgavinm 				 * On family 0xf cpuid fn 2 ECX[7:0] "NC" is
148110569901Sgavinm 				 * 1 less than the number of physical cores on
148210569901Sgavinm 				 * the chip.  In family 0x10 this value can
148310569901Sgavinm 				 * be affected by "downcoring" - it reflects
148410569901Sgavinm 				 * 1 less than the number of cores actually
148510569901Sgavinm 				 * enabled on this node.
148610569901Sgavinm 				 */
14878949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
14888949bcd6Sandrei 				    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
14898949bcd6Sandrei 			}
14908949bcd6Sandrei 			break;
14918949bcd6Sandrei 		default:
14928949bcd6Sandrei 			cpi->cpi_ncore_per_chip = 1;
14938949bcd6Sandrei 			break;
14947c478bd9Sstevel@tonic-gate 		}
14950e751525SEric Saxe 
14960e751525SEric Saxe 		/*
14970e751525SEric Saxe 		 * Get CPUID data about TSC Invariance in Deep C-State.
14980e751525SEric Saxe 		 */
14990e751525SEric Saxe 		switch (cpi->cpi_vendor) {
15000e751525SEric Saxe 		case X86_VENDOR_Intel:
15010e751525SEric Saxe 			if (cpi->cpi_maxeax >= 7) {
15020e751525SEric Saxe 				cp = &cpi->cpi_extd[7];
15030e751525SEric Saxe 				cp->cp_eax = 0x80000007;
15040e751525SEric Saxe 				cp->cp_ecx = 0;
15050e751525SEric Saxe 				(void) __cpuid_insn(cp);
15060e751525SEric Saxe 			}
15070e751525SEric Saxe 			break;
15080e751525SEric Saxe 		default:
15090e751525SEric Saxe 			break;
15100e751525SEric Saxe 		}
1511fa2e767eSgavinm 	} else {
1512fa2e767eSgavinm 		cpi->cpi_ncore_per_chip = 1;
15138949bcd6Sandrei 	}
15148949bcd6Sandrei 
15158949bcd6Sandrei 	/*
15168949bcd6Sandrei 	 * If more than one core, then this processor is CMP.
15178949bcd6Sandrei 	 */
15187417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncore_per_chip > 1) {
15197417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMP);
15207417cfdeSKuriakose Kuruvilla 	}
1521ae115bc7Smrj 
15228949bcd6Sandrei 	/*
15238949bcd6Sandrei 	 * If the number of cores is the same as the number
15248949bcd6Sandrei 	 * of CPUs, then we cannot have HyperThreading.
15258949bcd6Sandrei 	 */
15267417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncpu_per_chip == cpi->cpi_ncore_per_chip) {
15277417cfdeSKuriakose Kuruvilla 		remove_x86_feature(featureset, X86FSET_HTT);
15287417cfdeSKuriakose Kuruvilla 	}
15298949bcd6Sandrei 
15308031591dSSrihari Venkatesan 	cpi->cpi_apicid = CPI_APIC_ID(cpi);
15318031591dSSrihari Venkatesan 	cpi->cpi_procnodes_per_pkg = 1;
15327417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE &&
15337417cfdeSKuriakose Kuruvilla 	    is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) {
15348949bcd6Sandrei 		/*
15358949bcd6Sandrei 		 * Single-core single-threaded processors.
15368949bcd6Sandrei 		 */
15377c478bd9Sstevel@tonic-gate 		cpi->cpi_chipid = -1;
15387c478bd9Sstevel@tonic-gate 		cpi->cpi_clogid = 0;
15398949bcd6Sandrei 		cpi->cpi_coreid = cpu->cpu_id;
154010569901Sgavinm 		cpi->cpi_pkgcoreid = 0;
15418031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_AMD)
15428031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 3, 0);
15438031591dSSrihari Venkatesan 		else
15448031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
15457c478bd9Sstevel@tonic-gate 	} else if (cpi->cpi_ncpu_per_chip > 1) {
15468031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_Intel)
15477417cfdeSKuriakose Kuruvilla 			cpuid_intel_getids(cpu, featureset);
15488031591dSSrihari Venkatesan 		else if (cpi->cpi_vendor == X86_VENDOR_AMD)
15498031591dSSrihari Venkatesan 			cpuid_amd_getids(cpu);
15508031591dSSrihari Venkatesan 		else {
15518949bcd6Sandrei 			/*
15528949bcd6Sandrei 			 * All other processors are currently
15538949bcd6Sandrei 			 * assumed to have single cores.
15548949bcd6Sandrei 			 */
15558949bcd6Sandrei 			cpi->cpi_coreid = cpi->cpi_chipid;
155610569901Sgavinm 			cpi->cpi_pkgcoreid = 0;
15578031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
15588949bcd6Sandrei 		}
15597c478bd9Sstevel@tonic-gate 	}
15607c478bd9Sstevel@tonic-gate 
15618a40a695Sgavinm 	/*
15628a40a695Sgavinm 	 * Synthesize chip "revision" and socket type
15638a40a695Sgavinm 	 */
1564e4b86885SCheng Sean Ye 	cpi->cpi_chiprev = _cpuid_chiprev(cpi->cpi_vendor, cpi->cpi_family,
1565e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
1566e4b86885SCheng Sean Ye 	cpi->cpi_chiprevstr = _cpuid_chiprevstr(cpi->cpi_vendor,
1567e4b86885SCheng Sean Ye 	    cpi->cpi_family, cpi->cpi_model, cpi->cpi_step);
1568e4b86885SCheng Sean Ye 	cpi->cpi_socket = _cpuid_skt(cpi->cpi_vendor, cpi->cpi_family,
1569e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
15708a40a695Sgavinm 
15717c478bd9Sstevel@tonic-gate pass1_done:
15727c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 1;
15737c478bd9Sstevel@tonic-gate }
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate /*
15767c478bd9Sstevel@tonic-gate  * Make copies of the cpuid table entries we depend on, in
15777c478bd9Sstevel@tonic-gate  * part for ease of parsing now, in part so that we have only
15787c478bd9Sstevel@tonic-gate  * one place to correct any of it, in part for ease of
15797c478bd9Sstevel@tonic-gate  * later export to userland, and in part so we can look at
15807c478bd9Sstevel@tonic-gate  * this stuff in a crash dump.
15817c478bd9Sstevel@tonic-gate  */
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15847c478bd9Sstevel@tonic-gate void
15857c478bd9Sstevel@tonic-gate cpuid_pass2(cpu_t *cpu)
15867c478bd9Sstevel@tonic-gate {
15877c478bd9Sstevel@tonic-gate 	uint_t n, nmax;
15887c478bd9Sstevel@tonic-gate 	int i;
15898949bcd6Sandrei 	struct cpuid_regs *cp;
15907c478bd9Sstevel@tonic-gate 	uint8_t *dp;
15917c478bd9Sstevel@tonic-gate 	uint32_t *iptr;
15927c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 1);
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
15977c478bd9Sstevel@tonic-gate 		goto pass2_done;
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_maxeax + 1) > NMAX_CPI_STD)
16007c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_STD;
16017c478bd9Sstevel@tonic-gate 	/*
16027c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
16037c478bd9Sstevel@tonic-gate 	 */
16047c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_std[2]; n < nmax; n++, cp++) {
16058949bcd6Sandrei 		cp->cp_eax = n;
1606d129bde2Sesaxe 
1607d129bde2Sesaxe 		/*
1608d129bde2Sesaxe 		 * CPUID function 4 expects %ecx to be initialized
1609d129bde2Sesaxe 		 * with an index which indicates which cache to return
1610d129bde2Sesaxe 		 * information about. The OS is expected to call function 4
1611d129bde2Sesaxe 		 * with %ecx set to 0, 1, 2, ... until it returns with
1612d129bde2Sesaxe 		 * EAX[4:0] set to 0, which indicates there are no more
1613d129bde2Sesaxe 		 * caches.
1614d129bde2Sesaxe 		 *
1615d129bde2Sesaxe 		 * Here, populate cpi_std[4] with the information returned by
1616d129bde2Sesaxe 		 * function 4 when %ecx == 0, and do the rest in cpuid_pass3()
1617d129bde2Sesaxe 		 * when dynamic memory allocation becomes available.
1618d129bde2Sesaxe 		 *
1619d129bde2Sesaxe 		 * Note: we need to explicitly initialize %ecx here, since
1620d129bde2Sesaxe 		 * function 4 may have been previously invoked.
1621d129bde2Sesaxe 		 */
1622d129bde2Sesaxe 		if (n == 4)
1623d129bde2Sesaxe 			cp->cp_ecx = 0;
1624d129bde2Sesaxe 
16258949bcd6Sandrei 		(void) __cpuid_insn(cp);
1626ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, n, cp);
16277c478bd9Sstevel@tonic-gate 		switch (n) {
16287c478bd9Sstevel@tonic-gate 		case 2:
16297c478bd9Sstevel@tonic-gate 			/*
16307c478bd9Sstevel@tonic-gate 			 * "the lower 8 bits of the %eax register
16317c478bd9Sstevel@tonic-gate 			 * contain a value that identifies the number
16327c478bd9Sstevel@tonic-gate 			 * of times the cpuid [instruction] has to be
16337c478bd9Sstevel@tonic-gate 			 * executed to obtain a complete image of the
16347c478bd9Sstevel@tonic-gate 			 * processor's caching systems."
16357c478bd9Sstevel@tonic-gate 			 *
16367c478bd9Sstevel@tonic-gate 			 * How *do* they make this stuff up?
16377c478bd9Sstevel@tonic-gate 			 */
16387c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache = sizeof (*cp) *
16397c478bd9Sstevel@tonic-gate 			    BITX(cp->cp_eax, 7, 0);
16407c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache == 0)
16417c478bd9Sstevel@tonic-gate 				break;
16427c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache--;	/* skip count byte */
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 			/*
16457c478bd9Sstevel@tonic-gate 			 * Well, for now, rather than attempt to implement
16467c478bd9Sstevel@tonic-gate 			 * this slightly dubious algorithm, we just look
16477c478bd9Sstevel@tonic-gate 			 * at the first 15 ..
16487c478bd9Sstevel@tonic-gate 			 */
16497c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache > (sizeof (*cp) - 1))
16507c478bd9Sstevel@tonic-gate 				cpi->cpi_ncache = sizeof (*cp) - 1;
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 			dp = cpi->cpi_cacheinfo;
16537c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_eax, 31, 31) == 0) {
16547c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_eax;
165563d3f7dfSkk208521 				for (i = 1; i < 4; i++)
16567c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16577c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16587c478bd9Sstevel@tonic-gate 			}
16597c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ebx, 31, 31) == 0) {
16607c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ebx;
16617c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
16627c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16637c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16647c478bd9Sstevel@tonic-gate 			}
16657c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ecx, 31, 31) == 0) {
16667c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ecx;
16677c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
16687c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16697c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16707c478bd9Sstevel@tonic-gate 			}
16717c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_edx, 31, 31) == 0) {
16727c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_edx;
16737c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
16747c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
16757c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
16767c478bd9Sstevel@tonic-gate 			}
16777c478bd9Sstevel@tonic-gate 			break;
1678f98fbcecSbholler 
16797c478bd9Sstevel@tonic-gate 		case 3:	/* Processor serial number, if PSN supported */
1680f98fbcecSbholler 			break;
1681f98fbcecSbholler 
16827c478bd9Sstevel@tonic-gate 		case 4:	/* Deterministic cache parameters */
1683f98fbcecSbholler 			break;
1684f98fbcecSbholler 
16857c478bd9Sstevel@tonic-gate 		case 5:	/* Monitor/Mwait parameters */
16865b8a6efeSbholler 		{
16875b8a6efeSbholler 			size_t mwait_size;
1688f98fbcecSbholler 
1689f98fbcecSbholler 			/*
1690f98fbcecSbholler 			 * check cpi_mwait.support which was set in cpuid_pass1
1691f98fbcecSbholler 			 */
1692f98fbcecSbholler 			if (!(cpi->cpi_mwait.support & MWAIT_SUPPORT))
1693f98fbcecSbholler 				break;
1694f98fbcecSbholler 
16955b8a6efeSbholler 			/*
16965b8a6efeSbholler 			 * Protect ourself from insane mwait line size.
16975b8a6efeSbholler 			 * Workaround for incomplete hardware emulator(s).
16985b8a6efeSbholler 			 */
16995b8a6efeSbholler 			mwait_size = (size_t)MWAIT_SIZE_MAX(cpi);
17005b8a6efeSbholler 			if (mwait_size < sizeof (uint32_t) ||
17015b8a6efeSbholler 			    !ISP2(mwait_size)) {
17025b8a6efeSbholler #if DEBUG
17035b8a6efeSbholler 				cmn_err(CE_NOTE, "Cannot handle cpu %d mwait "
17045d8efbbcSSaurabh Misra 				    "size %ld", cpu->cpu_id, (long)mwait_size);
17055b8a6efeSbholler #endif
17065b8a6efeSbholler 				break;
17075b8a6efeSbholler 			}
17085b8a6efeSbholler 
1709f98fbcecSbholler 			cpi->cpi_mwait.mon_min = (size_t)MWAIT_SIZE_MIN(cpi);
17105b8a6efeSbholler 			cpi->cpi_mwait.mon_max = mwait_size;
1711f98fbcecSbholler 			if (MWAIT_EXTENSION(cpi)) {
1712f98fbcecSbholler 				cpi->cpi_mwait.support |= MWAIT_EXTENSIONS;
1713f98fbcecSbholler 				if (MWAIT_INT_ENABLE(cpi))
1714f98fbcecSbholler 					cpi->cpi_mwait.support |=
1715f98fbcecSbholler 					    MWAIT_ECX_INT_ENABLE;
1716f98fbcecSbholler 			}
1717f98fbcecSbholler 			break;
17185b8a6efeSbholler 		}
17197c478bd9Sstevel@tonic-gate 		default:
17207c478bd9Sstevel@tonic-gate 			break;
17217c478bd9Sstevel@tonic-gate 		}
17227c478bd9Sstevel@tonic-gate 	}
17237c478bd9Sstevel@tonic-gate 
1724b6917abeSmishra 	if (cpi->cpi_maxeax >= 0xB && cpi->cpi_vendor == X86_VENDOR_Intel) {
17255d8efbbcSSaurabh Misra 		struct cpuid_regs regs;
17265d8efbbcSSaurabh Misra 
17275d8efbbcSSaurabh Misra 		cp = &regs;
1728b6917abeSmishra 		cp->cp_eax = 0xB;
17295d8efbbcSSaurabh Misra 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
1730b6917abeSmishra 
1731b6917abeSmishra 		(void) __cpuid_insn(cp);
1732b6917abeSmishra 
1733b6917abeSmishra 		/*
1734b6917abeSmishra 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
1735b6917abeSmishra 		 * indicates that the extended topology enumeration leaf is
1736b6917abeSmishra 		 * available.
1737b6917abeSmishra 		 */
1738b6917abeSmishra 		if (cp->cp_ebx) {
1739b6917abeSmishra 			uint32_t x2apic_id;
1740b6917abeSmishra 			uint_t coreid_shift = 0;
1741b6917abeSmishra 			uint_t ncpu_per_core = 1;
1742b6917abeSmishra 			uint_t chipid_shift = 0;
1743b6917abeSmishra 			uint_t ncpu_per_chip = 1;
1744b6917abeSmishra 			uint_t i;
1745b6917abeSmishra 			uint_t level;
1746b6917abeSmishra 
1747b6917abeSmishra 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
1748b6917abeSmishra 				cp->cp_eax = 0xB;
1749b6917abeSmishra 				cp->cp_ecx = i;
1750b6917abeSmishra 
1751b6917abeSmishra 				(void) __cpuid_insn(cp);
1752b6917abeSmishra 				level = CPI_CPU_LEVEL_TYPE(cp);
1753b6917abeSmishra 
1754b6917abeSmishra 				if (level == 1) {
1755b6917abeSmishra 					x2apic_id = cp->cp_edx;
1756b6917abeSmishra 					coreid_shift = BITX(cp->cp_eax, 4, 0);
1757b6917abeSmishra 					ncpu_per_core = BITX(cp->cp_ebx, 15, 0);
1758b6917abeSmishra 				} else if (level == 2) {
1759b6917abeSmishra 					x2apic_id = cp->cp_edx;
1760b6917abeSmishra 					chipid_shift = BITX(cp->cp_eax, 4, 0);
1761b6917abeSmishra 					ncpu_per_chip = BITX(cp->cp_ebx, 15, 0);
1762b6917abeSmishra 				}
1763b6917abeSmishra 			}
1764b6917abeSmishra 
1765b6917abeSmishra 			cpi->cpi_apicid = x2apic_id;
1766b6917abeSmishra 			cpi->cpi_ncpu_per_chip = ncpu_per_chip;
1767b6917abeSmishra 			cpi->cpi_ncore_per_chip = ncpu_per_chip /
1768b6917abeSmishra 			    ncpu_per_core;
1769b6917abeSmishra 			cpi->cpi_chipid = x2apic_id >> chipid_shift;
1770b6917abeSmishra 			cpi->cpi_clogid = x2apic_id & ((1 << chipid_shift) - 1);
1771b6917abeSmishra 			cpi->cpi_coreid = x2apic_id >> coreid_shift;
1772b6917abeSmishra 			cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
1773b6917abeSmishra 		}
17745d8efbbcSSaurabh Misra 
17755d8efbbcSSaurabh Misra 		/* Make cp NULL so that we don't stumble on others */
17765d8efbbcSSaurabh Misra 		cp = NULL;
1777b6917abeSmishra 	}
1778b6917abeSmishra 
17797af88ac7SKuriakose Kuruvilla 	/*
17807af88ac7SKuriakose Kuruvilla 	 * XSAVE enumeration
17817af88ac7SKuriakose Kuruvilla 	 */
17827af88ac7SKuriakose Kuruvilla 	if (cpi->cpi_maxeax >= 0xD && cpi->cpi_vendor == X86_VENDOR_Intel) {
17837af88ac7SKuriakose Kuruvilla 		struct cpuid_regs regs;
17847af88ac7SKuriakose Kuruvilla 		boolean_t cpuid_d_valid = B_TRUE;
17857af88ac7SKuriakose Kuruvilla 
17867af88ac7SKuriakose Kuruvilla 		cp = &regs;
17877af88ac7SKuriakose Kuruvilla 		cp->cp_eax = 0xD;
17887af88ac7SKuriakose Kuruvilla 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
17897af88ac7SKuriakose Kuruvilla 
17907af88ac7SKuriakose Kuruvilla 		(void) __cpuid_insn(cp);
17917af88ac7SKuriakose Kuruvilla 
17927af88ac7SKuriakose Kuruvilla 		/*
17937af88ac7SKuriakose Kuruvilla 		 * Sanity checks for debug
17947af88ac7SKuriakose Kuruvilla 		 */
17957af88ac7SKuriakose Kuruvilla 		if ((cp->cp_eax & XFEATURE_LEGACY_FP) == 0 ||
17967af88ac7SKuriakose Kuruvilla 		    (cp->cp_eax & XFEATURE_SSE) == 0) {
17977af88ac7SKuriakose Kuruvilla 			cpuid_d_valid = B_FALSE;
17987af88ac7SKuriakose Kuruvilla 		}
17997af88ac7SKuriakose Kuruvilla 
18007af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_hw_features_low = cp->cp_eax;
18017af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_hw_features_high = cp->cp_edx;
18027af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_max_size = cp->cp_ecx;
18037af88ac7SKuriakose Kuruvilla 
18047af88ac7SKuriakose Kuruvilla 		/*
18057af88ac7SKuriakose Kuruvilla 		 * If the hw supports AVX, get the size and offset in the save
18067af88ac7SKuriakose Kuruvilla 		 * area for the ymm state.
18077af88ac7SKuriakose Kuruvilla 		 */
18087af88ac7SKuriakose Kuruvilla 		if (cpi->cpi_xsave.xsav_hw_features_low & XFEATURE_AVX) {
18097af88ac7SKuriakose Kuruvilla 			cp->cp_eax = 0xD;
18107af88ac7SKuriakose Kuruvilla 			cp->cp_ecx = 2;
18117af88ac7SKuriakose Kuruvilla 			cp->cp_edx = cp->cp_ebx = 0;
18127af88ac7SKuriakose Kuruvilla 
18137af88ac7SKuriakose Kuruvilla 			(void) __cpuid_insn(cp);
18147af88ac7SKuriakose Kuruvilla 
18157af88ac7SKuriakose Kuruvilla 			if (cp->cp_ebx != CPUID_LEAFD_2_YMM_OFFSET ||
18167af88ac7SKuriakose Kuruvilla 			    cp->cp_eax != CPUID_LEAFD_2_YMM_SIZE) {
18177af88ac7SKuriakose Kuruvilla 				cpuid_d_valid = B_FALSE;
18187af88ac7SKuriakose Kuruvilla 			}
18197af88ac7SKuriakose Kuruvilla 
18207af88ac7SKuriakose Kuruvilla 			cpi->cpi_xsave.ymm_size = cp->cp_eax;
18217af88ac7SKuriakose Kuruvilla 			cpi->cpi_xsave.ymm_offset = cp->cp_ebx;
18227af88ac7SKuriakose Kuruvilla 		}
18237af88ac7SKuriakose Kuruvilla 
18247af88ac7SKuriakose Kuruvilla 		if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) {
18257af88ac7SKuriakose Kuruvilla 			xsave_state_size = 0;
18267af88ac7SKuriakose Kuruvilla 		} else if (cpuid_d_valid) {
18277af88ac7SKuriakose Kuruvilla 			xsave_state_size = cpi->cpi_xsave.xsav_max_size;
18287af88ac7SKuriakose Kuruvilla 		} else {
18297af88ac7SKuriakose Kuruvilla 			/* Broken CPUID 0xD, probably in HVM */
18307af88ac7SKuriakose Kuruvilla 			cmn_err(CE_WARN, "cpu%d: CPUID.0xD returns invalid "
18317af88ac7SKuriakose Kuruvilla 			    "value: hw_low = %d, hw_high = %d, xsave_size = %d"
18327af88ac7SKuriakose Kuruvilla 			    ", ymm_size = %d, ymm_offset = %d\n",
18337af88ac7SKuriakose Kuruvilla 			    cpu->cpu_id, cpi->cpi_xsave.xsav_hw_features_low,
18347af88ac7SKuriakose Kuruvilla 			    cpi->cpi_xsave.xsav_hw_features_high,
18357af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.xsav_max_size,
18367af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.ymm_size,
18377af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.ymm_offset);
18387af88ac7SKuriakose Kuruvilla 
18397af88ac7SKuriakose Kuruvilla 			if (xsave_state_size != 0) {
18407af88ac7SKuriakose Kuruvilla 				/*
18417af88ac7SKuriakose Kuruvilla 				 * This must be a non-boot CPU. We cannot
18427af88ac7SKuriakose Kuruvilla 				 * continue, because boot cpu has already
18437af88ac7SKuriakose Kuruvilla 				 * enabled XSAVE.
18447af88ac7SKuriakose Kuruvilla 				 */
18457af88ac7SKuriakose Kuruvilla 				ASSERT(cpu->cpu_id != 0);
18467af88ac7SKuriakose Kuruvilla 				cmn_err(CE_PANIC, "cpu%d: we have already "
18477af88ac7SKuriakose Kuruvilla 				    "enabled XSAVE on boot cpu, cannot "
18487af88ac7SKuriakose Kuruvilla 				    "continue.", cpu->cpu_id);
18497af88ac7SKuriakose Kuruvilla 			} else {
18507af88ac7SKuriakose Kuruvilla 				/*
18517af88ac7SKuriakose Kuruvilla 				 * Must be from boot CPU, OK to disable XSAVE.
18527af88ac7SKuriakose Kuruvilla 				 */
18537af88ac7SKuriakose Kuruvilla 				ASSERT(cpu->cpu_id == 0);
18547af88ac7SKuriakose Kuruvilla 				remove_x86_feature(x86_featureset,
18557af88ac7SKuriakose Kuruvilla 				    X86FSET_XSAVE);
18567af88ac7SKuriakose Kuruvilla 				remove_x86_feature(x86_featureset, X86FSET_AVX);
18577af88ac7SKuriakose Kuruvilla 				CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_XSAVE;
18587af88ac7SKuriakose Kuruvilla 				CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_AVX;
18597af88ac7SKuriakose Kuruvilla 				xsave_force_disable = B_TRUE;
18607af88ac7SKuriakose Kuruvilla 			}
18617af88ac7SKuriakose Kuruvilla 		}
18627af88ac7SKuriakose Kuruvilla 	}
18637af88ac7SKuriakose Kuruvilla 
18647af88ac7SKuriakose Kuruvilla 
18657c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0)
18667c478bd9Sstevel@tonic-gate 		goto pass2_done;
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_xmaxeax - 0x80000000 + 1) > NMAX_CPI_EXTD)
18697c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_EXTD;
18707c478bd9Sstevel@tonic-gate 	/*
18717c478bd9Sstevel@tonic-gate 	 * Copy the extended properties, fixing them as we go.
18727c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
18737c478bd9Sstevel@tonic-gate 	 */
18747c478bd9Sstevel@tonic-gate 	iptr = (void *)cpi->cpi_brandstr;
18757c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_extd[2]; n < nmax; cp++, n++) {
18768949bcd6Sandrei 		cp->cp_eax = 0x80000000 + n;
18778949bcd6Sandrei 		(void) __cpuid_insn(cp);
1878ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, 0x80000000 + n, cp);
18797c478bd9Sstevel@tonic-gate 		switch (n) {
18807c478bd9Sstevel@tonic-gate 		case 2:
18817c478bd9Sstevel@tonic-gate 		case 3:
18827c478bd9Sstevel@tonic-gate 		case 4:
18837c478bd9Sstevel@tonic-gate 			/*
18847c478bd9Sstevel@tonic-gate 			 * Extract the brand string
18857c478bd9Sstevel@tonic-gate 			 */
18867c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_eax;
18877c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ebx;
18887c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ecx;
18897c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_edx;
18907c478bd9Sstevel@tonic-gate 			break;
18917c478bd9Sstevel@tonic-gate 		case 5:
18927c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
18937c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
18947c478bd9Sstevel@tonic-gate 				/*
18957c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
18967c478bd9Sstevel@tonic-gate 				 * parts to report the sizes of the
18977c478bd9Sstevel@tonic-gate 				 * TLB for large pages. Before then,
18987c478bd9Sstevel@tonic-gate 				 * we don't trust the data.
18997c478bd9Sstevel@tonic-gate 				 */
19007c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
19017c478bd9Sstevel@tonic-gate 				    (cpi->cpi_family == 6 &&
19027c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1))
19037c478bd9Sstevel@tonic-gate 					cp->cp_eax = 0;
19047c478bd9Sstevel@tonic-gate 				break;
19057c478bd9Sstevel@tonic-gate 			default:
19067c478bd9Sstevel@tonic-gate 				break;
19077c478bd9Sstevel@tonic-gate 			}
19087c478bd9Sstevel@tonic-gate 			break;
19097c478bd9Sstevel@tonic-gate 		case 6:
19107c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
19117c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
19127c478bd9Sstevel@tonic-gate 				/*
19137c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
19147c478bd9Sstevel@tonic-gate 				 * AMD parts with L2 TLB's.
19157c478bd9Sstevel@tonic-gate 				 * Before then, don't trust the data.
19167c478bd9Sstevel@tonic-gate 				 */
19177c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
19187c478bd9Sstevel@tonic-gate 				    cpi->cpi_family == 6 &&
19197c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1)
19207c478bd9Sstevel@tonic-gate 					cp->cp_eax = cp->cp_ebx = 0;
19217c478bd9Sstevel@tonic-gate 				/*
19227c478bd9Sstevel@tonic-gate 				 * AMD Duron rev A0 reports L2
19237c478bd9Sstevel@tonic-gate 				 * cache size incorrectly as 1K
19247c478bd9Sstevel@tonic-gate 				 * when it is really 64K
19257c478bd9Sstevel@tonic-gate 				 */
19267c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family == 6 &&
19277c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 3 &&
19287c478bd9Sstevel@tonic-gate 				    cpi->cpi_step == 0) {
19297c478bd9Sstevel@tonic-gate 					cp->cp_ecx &= 0xffff;
19307c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 0x400000;
19317c478bd9Sstevel@tonic-gate 				}
19327c478bd9Sstevel@tonic-gate 				break;
19337c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Cyrix:	/* VIA C3 */
19347c478bd9Sstevel@tonic-gate 				/*
19357c478bd9Sstevel@tonic-gate 				 * VIA C3 processors are a bit messed
19367c478bd9Sstevel@tonic-gate 				 * up w.r.t. encoding cache sizes in %ecx
19377c478bd9Sstevel@tonic-gate 				 */
19387c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family != 6)
19397c478bd9Sstevel@tonic-gate 					break;
19407c478bd9Sstevel@tonic-gate 				/*
19417c478bd9Sstevel@tonic-gate 				 * model 7 and 8 were incorrectly encoded
19427c478bd9Sstevel@tonic-gate 				 *
19437c478bd9Sstevel@tonic-gate 				 * xxx is model 8 really broken?
19447c478bd9Sstevel@tonic-gate 				 */
19457c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 7 ||
19467c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 8)
19477c478bd9Sstevel@tonic-gate 					cp->cp_ecx =
19487c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 31, 24) << 16 |
19497c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 23, 16) << 12 |
19507c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 15, 8) << 8 |
19517c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 7, 0);
19527c478bd9Sstevel@tonic-gate 				/*
19537c478bd9Sstevel@tonic-gate 				 * model 9 stepping 1 has wrong associativity
19547c478bd9Sstevel@tonic-gate 				 */
19557c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 9 && cpi->cpi_step == 1)
19567c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 8 << 12;
19577c478bd9Sstevel@tonic-gate 				break;
19587c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Intel:
19597c478bd9Sstevel@tonic-gate 				/*
19607c478bd9Sstevel@tonic-gate 				 * Extended L2 Cache features function.
19617c478bd9Sstevel@tonic-gate 				 * First appeared on Prescott.
19627c478bd9Sstevel@tonic-gate 				 */
19637c478bd9Sstevel@tonic-gate 			default:
19647c478bd9Sstevel@tonic-gate 				break;
19657c478bd9Sstevel@tonic-gate 			}
19667c478bd9Sstevel@tonic-gate 			break;
19677c478bd9Sstevel@tonic-gate 		default:
19687c478bd9Sstevel@tonic-gate 			break;
19697c478bd9Sstevel@tonic-gate 		}
19707c478bd9Sstevel@tonic-gate 	}
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate pass2_done:
19737c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 2;
19747c478bd9Sstevel@tonic-gate }
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate static const char *
19777c478bd9Sstevel@tonic-gate intel_cpubrand(const struct cpuid_info *cpi)
19787c478bd9Sstevel@tonic-gate {
19797c478bd9Sstevel@tonic-gate 	int i;
19807c478bd9Sstevel@tonic-gate 
19817417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
19827c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
19837c478bd9Sstevel@tonic-gate 		return ("i486");
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
19867c478bd9Sstevel@tonic-gate 	case 5:
19877c478bd9Sstevel@tonic-gate 		return ("Intel Pentium(r)");
19887c478bd9Sstevel@tonic-gate 	case 6:
19897c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
19907c478bd9Sstevel@tonic-gate 			uint_t celeron, xeon;
19918949bcd6Sandrei 			const struct cpuid_regs *cp;
19927c478bd9Sstevel@tonic-gate 		case 0:
19937c478bd9Sstevel@tonic-gate 		case 1:
19947c478bd9Sstevel@tonic-gate 		case 2:
19957c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) Pro");
19967c478bd9Sstevel@tonic-gate 		case 3:
19977c478bd9Sstevel@tonic-gate 		case 4:
19987c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) II");
19997c478bd9Sstevel@tonic-gate 		case 6:
20007c478bd9Sstevel@tonic-gate 			return ("Intel Celeron(r)");
20017c478bd9Sstevel@tonic-gate 		case 5:
20027c478bd9Sstevel@tonic-gate 		case 7:
20037c478bd9Sstevel@tonic-gate 			celeron = xeon = 0;
20047c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_std[2];	/* cache info */
20057c478bd9Sstevel@tonic-gate 
200663d3f7dfSkk208521 			for (i = 1; i < 4; i++) {
20077c478bd9Sstevel@tonic-gate 				uint_t tmp;
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_eax >> (8 * i)) & 0xff;
20107c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
20117c478bd9Sstevel@tonic-gate 					celeron++;
20127c478bd9Sstevel@tonic-gate 				if (tmp >= 0x44 && tmp <= 0x45)
20137c478bd9Sstevel@tonic-gate 					xeon++;
20147c478bd9Sstevel@tonic-gate 			}
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 			for (i = 0; i < 2; i++) {
20177c478bd9Sstevel@tonic-gate 				uint_t tmp;
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ebx >> (8 * i)) & 0xff;
20207c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
20217c478bd9Sstevel@tonic-gate 					celeron++;
20227c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
20237c478bd9Sstevel@tonic-gate 					xeon++;
20247c478bd9Sstevel@tonic-gate 			}
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
20277c478bd9Sstevel@tonic-gate 				uint_t tmp;
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ecx >> (8 * i)) & 0xff;
20307c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
20317c478bd9Sstevel@tonic-gate 					celeron++;
20327c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
20337c478bd9Sstevel@tonic-gate 					xeon++;
20347c478bd9Sstevel@tonic-gate 			}
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
20377c478bd9Sstevel@tonic-gate 				uint_t tmp;
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_edx >> (8 * i)) & 0xff;
20407c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
20417c478bd9Sstevel@tonic-gate 					celeron++;
20427c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
20437c478bd9Sstevel@tonic-gate 					xeon++;
20447c478bd9Sstevel@tonic-gate 			}
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate 			if (celeron)
20477c478bd9Sstevel@tonic-gate 				return ("Intel Celeron(r)");
20487c478bd9Sstevel@tonic-gate 			if (xeon)
20497c478bd9Sstevel@tonic-gate 				return (cpi->cpi_model == 5 ?
20507c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) II Xeon(tm)" :
20517c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) III Xeon(tm)");
20527c478bd9Sstevel@tonic-gate 			return (cpi->cpi_model == 5 ?
20537c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) II or Pentium(r) II Xeon(tm)" :
20547c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) III or Pentium(r) III Xeon(tm)");
20557c478bd9Sstevel@tonic-gate 		default:
20567c478bd9Sstevel@tonic-gate 			break;
20577c478bd9Sstevel@tonic-gate 		}
20587c478bd9Sstevel@tonic-gate 	default:
20597c478bd9Sstevel@tonic-gate 		break;
20607c478bd9Sstevel@tonic-gate 	}
20617c478bd9Sstevel@tonic-gate 
20625ff02082Sdmick 	/* BrandID is present if the field is nonzero */
20635ff02082Sdmick 	if (cpi->cpi_brandid != 0) {
20647c478bd9Sstevel@tonic-gate 		static const struct {
20657c478bd9Sstevel@tonic-gate 			uint_t bt_bid;
20667c478bd9Sstevel@tonic-gate 			const char *bt_str;
20677c478bd9Sstevel@tonic-gate 		} brand_tbl[] = {
20687c478bd9Sstevel@tonic-gate 			{ 0x1,	"Intel(r) Celeron(r)" },
20697c478bd9Sstevel@tonic-gate 			{ 0x2,	"Intel(r) Pentium(r) III" },
20707c478bd9Sstevel@tonic-gate 			{ 0x3,	"Intel(r) Pentium(r) III Xeon(tm)" },
20717c478bd9Sstevel@tonic-gate 			{ 0x4,	"Intel(r) Pentium(r) III" },
20727c478bd9Sstevel@tonic-gate 			{ 0x6,	"Mobile Intel(r) Pentium(r) III" },
20737c478bd9Sstevel@tonic-gate 			{ 0x7,	"Mobile Intel(r) Celeron(r)" },
20747c478bd9Sstevel@tonic-gate 			{ 0x8,	"Intel(r) Pentium(r) 4" },
20757c478bd9Sstevel@tonic-gate 			{ 0x9,	"Intel(r) Pentium(r) 4" },
20767c478bd9Sstevel@tonic-gate 			{ 0xa,	"Intel(r) Celeron(r)" },
20777c478bd9Sstevel@tonic-gate 			{ 0xb,	"Intel(r) Xeon(tm)" },
20787c478bd9Sstevel@tonic-gate 			{ 0xc,	"Intel(r) Xeon(tm) MP" },
20797c478bd9Sstevel@tonic-gate 			{ 0xe,	"Mobile Intel(r) Pentium(r) 4" },
20805ff02082Sdmick 			{ 0xf,	"Mobile Intel(r) Celeron(r)" },
20815ff02082Sdmick 			{ 0x11, "Mobile Genuine Intel(r)" },
20825ff02082Sdmick 			{ 0x12, "Intel(r) Celeron(r) M" },
20835ff02082Sdmick 			{ 0x13, "Mobile Intel(r) Celeron(r)" },
20845ff02082Sdmick 			{ 0x14, "Intel(r) Celeron(r)" },
20855ff02082Sdmick 			{ 0x15, "Mobile Genuine Intel(r)" },
20865ff02082Sdmick 			{ 0x16,	"Intel(r) Pentium(r) M" },
20875ff02082Sdmick 			{ 0x17, "Mobile Intel(r) Celeron(r)" }
20887c478bd9Sstevel@tonic-gate 		};
20897c478bd9Sstevel@tonic-gate 		uint_t btblmax = sizeof (brand_tbl) / sizeof (brand_tbl[0]);
20907c478bd9Sstevel@tonic-gate 		uint_t sgn;
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate 		sgn = (cpi->cpi_family << 8) |
20937c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model << 4) | cpi->cpi_step;
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 		for (i = 0; i < btblmax; i++)
20967c478bd9Sstevel@tonic-gate 			if (brand_tbl[i].bt_bid == cpi->cpi_brandid)
20977c478bd9Sstevel@tonic-gate 				break;
20987c478bd9Sstevel@tonic-gate 		if (i < btblmax) {
20997c478bd9Sstevel@tonic-gate 			if (sgn == 0x6b1 && cpi->cpi_brandid == 3)
21007c478bd9Sstevel@tonic-gate 				return ("Intel(r) Celeron(r)");
21017c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xb)
21027c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm) MP");
21037c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xe)
21047c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm)");
21057c478bd9Sstevel@tonic-gate 			return (brand_tbl[i].bt_str);
21067c478bd9Sstevel@tonic-gate 		}
21077c478bd9Sstevel@tonic-gate 	}
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 	return (NULL);
21107c478bd9Sstevel@tonic-gate }
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate static const char *
21137c478bd9Sstevel@tonic-gate amd_cpubrand(const struct cpuid_info *cpi)
21147c478bd9Sstevel@tonic-gate {
21157417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
21167c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
21177c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
21207c478bd9Sstevel@tonic-gate 	case 5:
21217c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
21227c478bd9Sstevel@tonic-gate 		case 0:
21237c478bd9Sstevel@tonic-gate 		case 1:
21247c478bd9Sstevel@tonic-gate 		case 2:
21257c478bd9Sstevel@tonic-gate 		case 3:
21267c478bd9Sstevel@tonic-gate 		case 4:
21277c478bd9Sstevel@tonic-gate 		case 5:
21287c478bd9Sstevel@tonic-gate 			return ("AMD-K5(r)");
21297c478bd9Sstevel@tonic-gate 		case 6:
21307c478bd9Sstevel@tonic-gate 		case 7:
21317c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)");
21327c478bd9Sstevel@tonic-gate 		case 8:
21337c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-2");
21347c478bd9Sstevel@tonic-gate 		case 9:
21357c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-III");
21367c478bd9Sstevel@tonic-gate 		default:
21377c478bd9Sstevel@tonic-gate 			return ("AMD (family 5)");
21387c478bd9Sstevel@tonic-gate 		}
21397c478bd9Sstevel@tonic-gate 	case 6:
21407c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
21417c478bd9Sstevel@tonic-gate 		case 1:
21427c478bd9Sstevel@tonic-gate 			return ("AMD-K7(tm)");
21437c478bd9Sstevel@tonic-gate 		case 0:
21447c478bd9Sstevel@tonic-gate 		case 2:
21457c478bd9Sstevel@tonic-gate 		case 4:
21467c478bd9Sstevel@tonic-gate 			return ("AMD Athlon(tm)");
21477c478bd9Sstevel@tonic-gate 		case 3:
21487c478bd9Sstevel@tonic-gate 		case 7:
21497c478bd9Sstevel@tonic-gate 			return ("AMD Duron(tm)");
21507c478bd9Sstevel@tonic-gate 		case 6:
21517c478bd9Sstevel@tonic-gate 		case 8:
21527c478bd9Sstevel@tonic-gate 		case 10:
21537c478bd9Sstevel@tonic-gate 			/*
21547c478bd9Sstevel@tonic-gate 			 * Use the L2 cache size to distinguish
21557c478bd9Sstevel@tonic-gate 			 */
21567c478bd9Sstevel@tonic-gate 			return ((cpi->cpi_extd[6].cp_ecx >> 16) >= 256 ?
21577c478bd9Sstevel@tonic-gate 			    "AMD Athlon(tm)" : "AMD Duron(tm)");
21587c478bd9Sstevel@tonic-gate 		default:
21597c478bd9Sstevel@tonic-gate 			return ("AMD (family 6)");
21607c478bd9Sstevel@tonic-gate 		}
21617c478bd9Sstevel@tonic-gate 	default:
21627c478bd9Sstevel@tonic-gate 		break;
21637c478bd9Sstevel@tonic-gate 	}
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	if (cpi->cpi_family == 0xf && cpi->cpi_model == 5 &&
21667c478bd9Sstevel@tonic-gate 	    cpi->cpi_brandid != 0) {
21677c478bd9Sstevel@tonic-gate 		switch (BITX(cpi->cpi_brandid, 7, 5)) {
21687c478bd9Sstevel@tonic-gate 		case 3:
21697c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) UP 1xx");
21707c478bd9Sstevel@tonic-gate 		case 4:
21717c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) DP 2xx");
21727c478bd9Sstevel@tonic-gate 		case 5:
21737c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) MP 8xx");
21747c478bd9Sstevel@tonic-gate 		default:
21757c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm)");
21767c478bd9Sstevel@tonic-gate 		}
21777c478bd9Sstevel@tonic-gate 	}
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	return (NULL);
21807c478bd9Sstevel@tonic-gate }
21817c478bd9Sstevel@tonic-gate 
21827c478bd9Sstevel@tonic-gate static const char *
21837c478bd9Sstevel@tonic-gate cyrix_cpubrand(struct cpuid_info *cpi, uint_t type)
21847c478bd9Sstevel@tonic-gate {
21857417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
21867c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5 ||
21877c478bd9Sstevel@tonic-gate 	    type == X86_TYPE_CYRIX_486)
21887c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 	switch (type) {
21917c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86:
21927c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86");
21937c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86L:
21947c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86L");
21957c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86MX:
21967c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86MX");
21977c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_GXm:
21987c478bd9Sstevel@tonic-gate 		return ("Cyrix GXm");
21997c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MediaGX:
22007c478bd9Sstevel@tonic-gate 		return ("Cyrix MediaGX");
22017c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MII:
22027c478bd9Sstevel@tonic-gate 		return ("Cyrix M2");
22037c478bd9Sstevel@tonic-gate 	case X86_TYPE_VIA_CYRIX_III:
22047c478bd9Sstevel@tonic-gate 		return ("VIA Cyrix M3");
22057c478bd9Sstevel@tonic-gate 	default:
22067c478bd9Sstevel@tonic-gate 		/*
22077c478bd9Sstevel@tonic-gate 		 * Have another wild guess ..
22087c478bd9Sstevel@tonic-gate 		 */
22097c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 4 && cpi->cpi_model == 9)
22107c478bd9Sstevel@tonic-gate 			return ("Cyrix 5x86");
22117c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_family == 5) {
22127c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
22137c478bd9Sstevel@tonic-gate 			case 2:
22147c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86");	/* Cyrix M1 */
22157c478bd9Sstevel@tonic-gate 			case 4:
22167c478bd9Sstevel@tonic-gate 				return ("Cyrix MediaGX");
22177c478bd9Sstevel@tonic-gate 			default:
22187c478bd9Sstevel@tonic-gate 				break;
22197c478bd9Sstevel@tonic-gate 			}
22207c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family == 6) {
22217c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
22227c478bd9Sstevel@tonic-gate 			case 0:
22237c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86MX"); /* Cyrix M2? */
22247c478bd9Sstevel@tonic-gate 			case 5:
22257c478bd9Sstevel@tonic-gate 			case 6:
22267c478bd9Sstevel@tonic-gate 			case 7:
22277c478bd9Sstevel@tonic-gate 			case 8:
22287c478bd9Sstevel@tonic-gate 			case 9:
22297c478bd9Sstevel@tonic-gate 				return ("VIA C3");
22307c478bd9Sstevel@tonic-gate 			default:
22317c478bd9Sstevel@tonic-gate 				break;
22327c478bd9Sstevel@tonic-gate 			}
22337c478bd9Sstevel@tonic-gate 		}
22347c478bd9Sstevel@tonic-gate 		break;
22357c478bd9Sstevel@tonic-gate 	}
22367c478bd9Sstevel@tonic-gate 	return (NULL);
22377c478bd9Sstevel@tonic-gate }
22387c478bd9Sstevel@tonic-gate 
22397c478bd9Sstevel@tonic-gate /*
22407c478bd9Sstevel@tonic-gate  * This only gets called in the case that the CPU extended
22417c478bd9Sstevel@tonic-gate  * feature brand string (0x80000002, 0x80000003, 0x80000004)
22427c478bd9Sstevel@tonic-gate  * aren't available, or contain null bytes for some reason.
22437c478bd9Sstevel@tonic-gate  */
22447c478bd9Sstevel@tonic-gate static void
22457c478bd9Sstevel@tonic-gate fabricate_brandstr(struct cpuid_info *cpi)
22467c478bd9Sstevel@tonic-gate {
22477c478bd9Sstevel@tonic-gate 	const char *brand = NULL;
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
22507c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
22517c478bd9Sstevel@tonic-gate 		brand = intel_cpubrand(cpi);
22527c478bd9Sstevel@tonic-gate 		break;
22537c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
22547c478bd9Sstevel@tonic-gate 		brand = amd_cpubrand(cpi);
22557c478bd9Sstevel@tonic-gate 		break;
22567c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
22577c478bd9Sstevel@tonic-gate 		brand = cyrix_cpubrand(cpi, x86_type);
22587c478bd9Sstevel@tonic-gate 		break;
22597c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NexGen:
22607c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
22617c478bd9Sstevel@tonic-gate 			brand = "NexGen Nx586";
22627c478bd9Sstevel@tonic-gate 		break;
22637c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
22647c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
22657c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
22667c478bd9Sstevel@tonic-gate 			case 4:
22677c478bd9Sstevel@tonic-gate 				brand = "Centaur C6";
22687c478bd9Sstevel@tonic-gate 				break;
22697c478bd9Sstevel@tonic-gate 			case 8:
22707c478bd9Sstevel@tonic-gate 				brand = "Centaur C2";
22717c478bd9Sstevel@tonic-gate 				break;
22727c478bd9Sstevel@tonic-gate 			case 9:
22737c478bd9Sstevel@tonic-gate 				brand = "Centaur C3";
22747c478bd9Sstevel@tonic-gate 				break;
22757c478bd9Sstevel@tonic-gate 			default:
22767c478bd9Sstevel@tonic-gate 				break;
22777c478bd9Sstevel@tonic-gate 			}
22787c478bd9Sstevel@tonic-gate 		break;
22797c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Rise:
22807c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 &&
22817c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model == 0 || cpi->cpi_model == 2))
22827c478bd9Sstevel@tonic-gate 			brand = "Rise mP6";
22837c478bd9Sstevel@tonic-gate 		break;
22847c478bd9Sstevel@tonic-gate 	case X86_VENDOR_SiS:
22857c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
22867c478bd9Sstevel@tonic-gate 			brand = "SiS 55x";
22877c478bd9Sstevel@tonic-gate 		break;
22887c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
22897c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4)
22907c478bd9Sstevel@tonic-gate 			brand = "Transmeta Crusoe TM3x00 or TM5x00";
22917c478bd9Sstevel@tonic-gate 		break;
22927c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NSC:
22937c478bd9Sstevel@tonic-gate 	case X86_VENDOR_UMC:
22947c478bd9Sstevel@tonic-gate 	default:
22957c478bd9Sstevel@tonic-gate 		break;
22967c478bd9Sstevel@tonic-gate 	}
22977c478bd9Sstevel@tonic-gate 	if (brand) {
22987c478bd9Sstevel@tonic-gate 		(void) strcpy((char *)cpi->cpi_brandstr, brand);
22997c478bd9Sstevel@tonic-gate 		return;
23007c478bd9Sstevel@tonic-gate 	}
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	/*
23037c478bd9Sstevel@tonic-gate 	 * If all else fails ...
23047c478bd9Sstevel@tonic-gate 	 */
23057c478bd9Sstevel@tonic-gate 	(void) snprintf(cpi->cpi_brandstr, sizeof (cpi->cpi_brandstr),
23067c478bd9Sstevel@tonic-gate 	    "%s %d.%d.%d", cpi->cpi_vendorstr, cpi->cpi_family,
23077c478bd9Sstevel@tonic-gate 	    cpi->cpi_model, cpi->cpi_step);
23087c478bd9Sstevel@tonic-gate }
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate /*
23117c478bd9Sstevel@tonic-gate  * This routine is called just after kernel memory allocation
23127c478bd9Sstevel@tonic-gate  * becomes available on cpu0, and as part of mp_startup() on
23137c478bd9Sstevel@tonic-gate  * the other cpus.
23147c478bd9Sstevel@tonic-gate  *
2315d129bde2Sesaxe  * Fixup the brand string, and collect any information from cpuid
2316d129bde2Sesaxe  * that requires dynamicically allocated storage to represent.
23177c478bd9Sstevel@tonic-gate  */
23187c478bd9Sstevel@tonic-gate /*ARGSUSED*/
23197c478bd9Sstevel@tonic-gate void
23207c478bd9Sstevel@tonic-gate cpuid_pass3(cpu_t *cpu)
23217c478bd9Sstevel@tonic-gate {
2322d129bde2Sesaxe 	int	i, max, shft, level, size;
2323d129bde2Sesaxe 	struct cpuid_regs regs;
2324d129bde2Sesaxe 	struct cpuid_regs *cp;
23257c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 2);
23287c478bd9Sstevel@tonic-gate 
2329d129bde2Sesaxe 	/*
2330d129bde2Sesaxe 	 * Function 4: Deterministic cache parameters
2331d129bde2Sesaxe 	 *
2332d129bde2Sesaxe 	 * Take this opportunity to detect the number of threads
2333d129bde2Sesaxe 	 * sharing the last level cache, and construct a corresponding
2334d129bde2Sesaxe 	 * cache id. The respective cpuid_info members are initialized
2335d129bde2Sesaxe 	 * to the default case of "no last level cache sharing".
2336d129bde2Sesaxe 	 */
2337d129bde2Sesaxe 	cpi->cpi_ncpu_shr_last_cache = 1;
2338d129bde2Sesaxe 	cpi->cpi_last_lvl_cacheid = cpu->cpu_id;
2339d129bde2Sesaxe 
2340d129bde2Sesaxe 	if (cpi->cpi_maxeax >= 4 && cpi->cpi_vendor == X86_VENDOR_Intel) {
2341d129bde2Sesaxe 
2342d129bde2Sesaxe 		/*
2343d129bde2Sesaxe 		 * Find the # of elements (size) returned by fn 4, and along
2344d129bde2Sesaxe 		 * the way detect last level cache sharing details.
2345d129bde2Sesaxe 		 */
2346d129bde2Sesaxe 		bzero(&regs, sizeof (regs));
2347d129bde2Sesaxe 		cp = &regs;
2348d129bde2Sesaxe 		for (i = 0, max = 0; i < CPI_FN4_ECX_MAX; i++) {
2349d129bde2Sesaxe 			cp->cp_eax = 4;
2350d129bde2Sesaxe 			cp->cp_ecx = i;
2351d129bde2Sesaxe 
2352d129bde2Sesaxe 			(void) __cpuid_insn(cp);
2353d129bde2Sesaxe 
2354d129bde2Sesaxe 			if (CPI_CACHE_TYPE(cp) == 0)
2355d129bde2Sesaxe 				break;
2356d129bde2Sesaxe 			level = CPI_CACHE_LVL(cp);
2357d129bde2Sesaxe 			if (level > max) {
2358d129bde2Sesaxe 				max = level;
2359d129bde2Sesaxe 				cpi->cpi_ncpu_shr_last_cache =
2360d129bde2Sesaxe 				    CPI_NTHR_SHR_CACHE(cp) + 1;
2361d129bde2Sesaxe 			}
2362d129bde2Sesaxe 		}
2363d129bde2Sesaxe 		cpi->cpi_std_4_size = size = i;
2364d129bde2Sesaxe 
2365d129bde2Sesaxe 		/*
2366d129bde2Sesaxe 		 * Allocate the cpi_std_4 array. The first element
2367d129bde2Sesaxe 		 * references the regs for fn 4, %ecx == 0, which
2368d129bde2Sesaxe 		 * cpuid_pass2() stashed in cpi->cpi_std[4].
2369d129bde2Sesaxe 		 */
2370d129bde2Sesaxe 		if (size > 0) {
2371d129bde2Sesaxe 			cpi->cpi_std_4 =
2372d129bde2Sesaxe 			    kmem_alloc(size * sizeof (cp), KM_SLEEP);
2373d129bde2Sesaxe 			cpi->cpi_std_4[0] = &cpi->cpi_std[4];
2374d129bde2Sesaxe 
2375d129bde2Sesaxe 			/*
2376d129bde2Sesaxe 			 * Allocate storage to hold the additional regs
2377d129bde2Sesaxe 			 * for function 4, %ecx == 1 .. cpi_std_4_size.
2378d129bde2Sesaxe 			 *
2379d129bde2Sesaxe 			 * The regs for fn 4, %ecx == 0 has already
2380d129bde2Sesaxe 			 * been allocated as indicated above.
2381d129bde2Sesaxe 			 */
2382d129bde2Sesaxe 			for (i = 1; i < size; i++) {
2383d129bde2Sesaxe 				cp = cpi->cpi_std_4[i] =
2384d129bde2Sesaxe 				    kmem_zalloc(sizeof (regs), KM_SLEEP);
2385d129bde2Sesaxe 				cp->cp_eax = 4;
2386d129bde2Sesaxe 				cp->cp_ecx = i;
2387d129bde2Sesaxe 
2388d129bde2Sesaxe 				(void) __cpuid_insn(cp);
2389d129bde2Sesaxe 			}
2390d129bde2Sesaxe 		}
2391d129bde2Sesaxe 		/*
2392d129bde2Sesaxe 		 * Determine the number of bits needed to represent
2393d129bde2Sesaxe 		 * the number of CPUs sharing the last level cache.
2394d129bde2Sesaxe 		 *
2395d129bde2Sesaxe 		 * Shift off that number of bits from the APIC id to
2396d129bde2Sesaxe 		 * derive the cache id.
2397d129bde2Sesaxe 		 */
2398d129bde2Sesaxe 		shft = 0;
2399d129bde2Sesaxe 		for (i = 1; i < cpi->cpi_ncpu_shr_last_cache; i <<= 1)
2400d129bde2Sesaxe 			shft++;
2401b6917abeSmishra 		cpi->cpi_last_lvl_cacheid = cpi->cpi_apicid >> shft;
2402d129bde2Sesaxe 	}
2403d129bde2Sesaxe 
2404d129bde2Sesaxe 	/*
2405d129bde2Sesaxe 	 * Now fixup the brand string
2406d129bde2Sesaxe 	 */
24077c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0) {
24087c478bd9Sstevel@tonic-gate 		fabricate_brandstr(cpi);
2409d129bde2Sesaxe 	} else {
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 		/*
24127c478bd9Sstevel@tonic-gate 		 * If we successfully extracted a brand string from the cpuid
24137c478bd9Sstevel@tonic-gate 		 * instruction, clean it up by removing leading spaces and
24147c478bd9Sstevel@tonic-gate 		 * similar junk.
24157c478bd9Sstevel@tonic-gate 		 */
24167c478bd9Sstevel@tonic-gate 		if (cpi->cpi_brandstr[0]) {
24177c478bd9Sstevel@tonic-gate 			size_t maxlen = sizeof (cpi->cpi_brandstr);
24187c478bd9Sstevel@tonic-gate 			char *src, *dst;
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate 			dst = src = (char *)cpi->cpi_brandstr;
24217c478bd9Sstevel@tonic-gate 			src[maxlen - 1] = '\0';
24227c478bd9Sstevel@tonic-gate 			/*
24237c478bd9Sstevel@tonic-gate 			 * strip leading spaces
24247c478bd9Sstevel@tonic-gate 			 */
24257c478bd9Sstevel@tonic-gate 			while (*src == ' ')
24267c478bd9Sstevel@tonic-gate 				src++;
24277c478bd9Sstevel@tonic-gate 			/*
24287c478bd9Sstevel@tonic-gate 			 * Remove any 'Genuine' or "Authentic" prefixes
24297c478bd9Sstevel@tonic-gate 			 */
24307c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Genuine ", 8) == 0)
24317c478bd9Sstevel@tonic-gate 				src += 8;
24327c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Authentic ", 10) == 0)
24337c478bd9Sstevel@tonic-gate 				src += 10;
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate 			/*
24367c478bd9Sstevel@tonic-gate 			 * Now do an in-place copy.
24377c478bd9Sstevel@tonic-gate 			 * Map (R) to (r) and (TM) to (tm).
24387c478bd9Sstevel@tonic-gate 			 * The era of teletypes is long gone, and there's
24397c478bd9Sstevel@tonic-gate 			 * -really- no need to shout.
24407c478bd9Sstevel@tonic-gate 			 */
24417c478bd9Sstevel@tonic-gate 			while (*src != '\0') {
24427c478bd9Sstevel@tonic-gate 				if (src[0] == '(') {
24437c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "R)", 2) == 0) {
24447c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(r)", 3);
24457c478bd9Sstevel@tonic-gate 						src += 3;
24467c478bd9Sstevel@tonic-gate 						dst += 3;
24477c478bd9Sstevel@tonic-gate 						continue;
24487c478bd9Sstevel@tonic-gate 					}
24497c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "TM)", 3) == 0) {
24507c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(tm)", 4);
24517c478bd9Sstevel@tonic-gate 						src += 4;
24527c478bd9Sstevel@tonic-gate 						dst += 4;
24537c478bd9Sstevel@tonic-gate 						continue;
24547c478bd9Sstevel@tonic-gate 					}
24557c478bd9Sstevel@tonic-gate 				}
24567c478bd9Sstevel@tonic-gate 				*dst++ = *src++;
24577c478bd9Sstevel@tonic-gate 			}
24587c478bd9Sstevel@tonic-gate 			*dst = '\0';
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate 			/*
24617c478bd9Sstevel@tonic-gate 			 * Finally, remove any trailing spaces
24627c478bd9Sstevel@tonic-gate 			 */
24637c478bd9Sstevel@tonic-gate 			while (--dst > cpi->cpi_brandstr)
24647c478bd9Sstevel@tonic-gate 				if (*dst == ' ')
24657c478bd9Sstevel@tonic-gate 					*dst = '\0';
24667c478bd9Sstevel@tonic-gate 				else
24677c478bd9Sstevel@tonic-gate 					break;
24687c478bd9Sstevel@tonic-gate 		} else
24697c478bd9Sstevel@tonic-gate 			fabricate_brandstr(cpi);
2470d129bde2Sesaxe 	}
24717c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 3;
24727c478bd9Sstevel@tonic-gate }
24737c478bd9Sstevel@tonic-gate 
24747c478bd9Sstevel@tonic-gate /*
24757c478bd9Sstevel@tonic-gate  * This routine is called out of bind_hwcap() much later in the life
24767c478bd9Sstevel@tonic-gate  * of the kernel (post_startup()).  The job of this routine is to resolve
24777c478bd9Sstevel@tonic-gate  * the hardware feature support and kernel support for those features into
24787c478bd9Sstevel@tonic-gate  * what we're actually going to tell applications via the aux vector.
24797c478bd9Sstevel@tonic-gate  */
24807c478bd9Sstevel@tonic-gate uint_t
24817c478bd9Sstevel@tonic-gate cpuid_pass4(cpu_t *cpu)
24827c478bd9Sstevel@tonic-gate {
24837c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
24847c478bd9Sstevel@tonic-gate 	uint_t hwcap_flags = 0;
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
24877c478bd9Sstevel@tonic-gate 		cpu = CPU;
24887c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 3);
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax >= 1) {
24937c478bd9Sstevel@tonic-gate 		uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES];
24947c478bd9Sstevel@tonic-gate 		uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES];
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_EDX(cpi);
24977c478bd9Sstevel@tonic-gate 		*ecx = CPI_FEATURES_ECX(cpi);
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 		/*
25007c478bd9Sstevel@tonic-gate 		 * [these require explicit kernel support]
25017c478bd9Sstevel@tonic-gate 		 */
25027417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SEP))
25037c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SEP;
25047c478bd9Sstevel@tonic-gate 
25057417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE))
25067c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE);
25077417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE2))
25087c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SSE2;
25097c478bd9Sstevel@tonic-gate 
25107417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_HTT))
25117c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_HTT;
25127c478bd9Sstevel@tonic-gate 
25137417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE3))
25147c478bd9Sstevel@tonic-gate 			*ecx &= ~CPUID_INTC_ECX_SSE3;
25157c478bd9Sstevel@tonic-gate 
2516d0f8ff6eSkk208521 		if (cpi->cpi_vendor == X86_VENDOR_Intel) {
25177417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSSE3))
2518d0f8ff6eSkk208521 				*ecx &= ~CPUID_INTC_ECX_SSSE3;
25197417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1))
2520d0f8ff6eSkk208521 				*ecx &= ~CPUID_INTC_ECX_SSE4_1;
25217417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2))
2522d0f8ff6eSkk208521 				*ecx &= ~CPUID_INTC_ECX_SSE4_2;
25237417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_AES))
2524a50a8b93SKuriakose Kuruvilla 				*ecx &= ~CPUID_INTC_ECX_AES;
25257417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ))
25267417cfdeSKuriakose Kuruvilla 				*ecx &= ~CPUID_INTC_ECX_PCLMULQDQ;
25277af88ac7SKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_XSAVE))
25287af88ac7SKuriakose Kuruvilla 				*ecx &= ~(CPUID_INTC_ECX_XSAVE |
25297af88ac7SKuriakose Kuruvilla 				    CPUID_INTC_ECX_OSXSAVE);
25307af88ac7SKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_AVX))
25317af88ac7SKuriakose Kuruvilla 				*ecx &= ~CPUID_INTC_ECX_AVX;
2532d0f8ff6eSkk208521 		}
2533d0f8ff6eSkk208521 
25347c478bd9Sstevel@tonic-gate 		/*
25357c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond x87 fp context]
25367c478bd9Sstevel@tonic-gate 		 */
25377c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
25387c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FPU | CPUID_INTC_EDX_MMX);
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 		/*
25417c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to things that we
25427c478bd9Sstevel@tonic-gate 		 * think userland will care about.
25437c478bd9Sstevel@tonic-gate 		 */
25447c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SEP)
25457c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SEP;
25467c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE)
25477c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FXSR | AV_386_SSE;
25487c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE2)
25497c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE2;
25507c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_SSE3)
25517c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE3;
2552d0f8ff6eSkk208521 		if (cpi->cpi_vendor == X86_VENDOR_Intel) {
2553d0f8ff6eSkk208521 			if (*ecx & CPUID_INTC_ECX_SSSE3)
2554d0f8ff6eSkk208521 				hwcap_flags |= AV_386_SSSE3;
2555d0f8ff6eSkk208521 			if (*ecx & CPUID_INTC_ECX_SSE4_1)
2556d0f8ff6eSkk208521 				hwcap_flags |= AV_386_SSE4_1;
2557d0f8ff6eSkk208521 			if (*ecx & CPUID_INTC_ECX_SSE4_2)
2558d0f8ff6eSkk208521 				hwcap_flags |= AV_386_SSE4_2;
25595087e485SKrishnendu Sadhukhan - Sun Microsystems 			if (*ecx & CPUID_INTC_ECX_MOVBE)
25605087e485SKrishnendu Sadhukhan - Sun Microsystems 				hwcap_flags |= AV_386_MOVBE;
2561a50a8b93SKuriakose Kuruvilla 			if (*ecx & CPUID_INTC_ECX_AES)
2562a50a8b93SKuriakose Kuruvilla 				hwcap_flags |= AV_386_AES;
2563a50a8b93SKuriakose Kuruvilla 			if (*ecx & CPUID_INTC_ECX_PCLMULQDQ)
2564a50a8b93SKuriakose Kuruvilla 				hwcap_flags |= AV_386_PCLMULQDQ;
25657af88ac7SKuriakose Kuruvilla 			if ((*ecx & CPUID_INTC_ECX_XSAVE) &&
25667af88ac7SKuriakose Kuruvilla 			    (*ecx & CPUID_INTC_ECX_OSXSAVE))
25677af88ac7SKuriakose Kuruvilla 				hwcap_flags |= AV_386_XSAVE;
2568d0f8ff6eSkk208521 		}
2569f8801251Skk208521 		if (*ecx & CPUID_INTC_ECX_POPCNT)
2570f8801251Skk208521 			hwcap_flags |= AV_386_POPCNT;
25717c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_FPU)
25727c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FPU;
25737c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_MMX)
25747c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_MMX;
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_TSC)
25777c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_TSC;
25787c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CX8)
25797c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX8;
25807c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CMOV)
25817c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CMOV;
25827c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_CX16)
25837c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX16;
25847c478bd9Sstevel@tonic-gate 	}
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000001)
25877c478bd9Sstevel@tonic-gate 		goto pass4_done;
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
25908949bcd6Sandrei 		struct cpuid_regs cp;
2591ae115bc7Smrj 		uint32_t *edx, *ecx;
25927c478bd9Sstevel@tonic-gate 
2593ae115bc7Smrj 	case X86_VENDOR_Intel:
2594ae115bc7Smrj 		/*
2595ae115bc7Smrj 		 * Seems like Intel duplicated what we necessary
2596ae115bc7Smrj 		 * here to make the initial crop of 64-bit OS's work.
2597ae115bc7Smrj 		 * Hopefully, those are the only "extended" bits
2598ae115bc7Smrj 		 * they'll add.
2599ae115bc7Smrj 		 */
2600ae115bc7Smrj 		/*FALLTHROUGH*/
2601ae115bc7Smrj 
26027c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
26037c478bd9Sstevel@tonic-gate 		edx = &cpi->cpi_support[AMD_EDX_FEATURES];
2604ae115bc7Smrj 		ecx = &cpi->cpi_support[AMD_ECX_FEATURES];
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_XTD_EDX(cpi);
2607ae115bc7Smrj 		*ecx = CPI_FEATURES_XTD_ECX(cpi);
2608ae115bc7Smrj 
2609ae115bc7Smrj 		/*
2610ae115bc7Smrj 		 * [these features require explicit kernel support]
2611ae115bc7Smrj 		 */
2612ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2613ae115bc7Smrj 		case X86_VENDOR_Intel:
26147417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2615d36ea5d8Ssudheer 				*edx &= ~CPUID_AMD_EDX_TSCP;
2616ae115bc7Smrj 			break;
2617ae115bc7Smrj 
2618ae115bc7Smrj 		case X86_VENDOR_AMD:
26197417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2620ae115bc7Smrj 				*edx &= ~CPUID_AMD_EDX_TSCP;
26217417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4A))
2622f8801251Skk208521 				*ecx &= ~CPUID_AMD_ECX_SSE4A;
2623ae115bc7Smrj 			break;
2624ae115bc7Smrj 
2625ae115bc7Smrj 		default:
2626ae115bc7Smrj 			break;
2627ae115bc7Smrj 		}
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate 		/*
26307c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond
26317c478bd9Sstevel@tonic-gate 		 * x87 fp context and exception handlers]
26327c478bd9Sstevel@tonic-gate 		 */
26337c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
26347c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_AMD_EDX_MMXamd |
26357c478bd9Sstevel@tonic-gate 			    CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx);
26367c478bd9Sstevel@tonic-gate 
26377417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_NX))
26387c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_AMD_EDX_NX;
2639ae115bc7Smrj #if !defined(__amd64)
26407c478bd9Sstevel@tonic-gate 		*edx &= ~CPUID_AMD_EDX_LM;
26417c478bd9Sstevel@tonic-gate #endif
26427c478bd9Sstevel@tonic-gate 		/*
26437c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to
26447c478bd9Sstevel@tonic-gate 		 * things that we think userland will care about.
26457c478bd9Sstevel@tonic-gate 		 */
2646ae115bc7Smrj #if defined(__amd64)
26477c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_SYSC)
26487c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_SYSC;
2649ae115bc7Smrj #endif
26507c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_MMXamd)
26517c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_MMX;
26527c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNow)
26537c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNow;
26547c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNowx)
26557c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNowx;
2656ae115bc7Smrj 
2657ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2658ae115bc7Smrj 		case X86_VENDOR_AMD:
2659ae115bc7Smrj 			if (*edx & CPUID_AMD_EDX_TSCP)
2660ae115bc7Smrj 				hwcap_flags |= AV_386_TSCP;
2661ae115bc7Smrj 			if (*ecx & CPUID_AMD_ECX_AHF64)
2662ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2663f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_SSE4A)
2664f8801251Skk208521 				hwcap_flags |= AV_386_AMD_SSE4A;
2665f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_LZCNT)
2666f8801251Skk208521 				hwcap_flags |= AV_386_AMD_LZCNT;
2667ae115bc7Smrj 			break;
2668ae115bc7Smrj 
2669ae115bc7Smrj 		case X86_VENDOR_Intel:
2670d36ea5d8Ssudheer 			if (*edx & CPUID_AMD_EDX_TSCP)
2671d36ea5d8Ssudheer 				hwcap_flags |= AV_386_TSCP;
2672ae115bc7Smrj 			/*
2673ae115bc7Smrj 			 * Aarrgh.
2674ae115bc7Smrj 			 * Intel uses a different bit in the same word.
2675ae115bc7Smrj 			 */
2676ae115bc7Smrj 			if (*ecx & CPUID_INTC_ECX_AHF64)
2677ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2678ae115bc7Smrj 			break;
2679ae115bc7Smrj 
2680ae115bc7Smrj 		default:
2681ae115bc7Smrj 			break;
2682ae115bc7Smrj 		}
26837c478bd9Sstevel@tonic-gate 		break;
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
26868949bcd6Sandrei 		cp.cp_eax = 0x80860001;
26878949bcd6Sandrei 		(void) __cpuid_insn(&cp);
26888949bcd6Sandrei 		cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx;
26897c478bd9Sstevel@tonic-gate 		break;
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate 	default:
26927c478bd9Sstevel@tonic-gate 		break;
26937c478bd9Sstevel@tonic-gate 	}
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate pass4_done:
26967c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 4;
26977c478bd9Sstevel@tonic-gate 	return (hwcap_flags);
26987c478bd9Sstevel@tonic-gate }
26997c478bd9Sstevel@tonic-gate 
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate /*
27027c478bd9Sstevel@tonic-gate  * Simulate the cpuid instruction using the data we previously
27037c478bd9Sstevel@tonic-gate  * captured about this CPU.  We try our best to return the truth
27047c478bd9Sstevel@tonic-gate  * about the hardware, independently of kernel support.
27057c478bd9Sstevel@tonic-gate  */
27067c478bd9Sstevel@tonic-gate uint32_t
27078949bcd6Sandrei cpuid_insn(cpu_t *cpu, struct cpuid_regs *cp)
27087c478bd9Sstevel@tonic-gate {
27097c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
27108949bcd6Sandrei 	struct cpuid_regs *xcp;
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
27137c478bd9Sstevel@tonic-gate 		cpu = CPU;
27147c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
27157c478bd9Sstevel@tonic-gate 
27167c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
27177c478bd9Sstevel@tonic-gate 
27187c478bd9Sstevel@tonic-gate 	/*
27197c478bd9Sstevel@tonic-gate 	 * CPUID data is cached in two separate places: cpi_std for standard
27207c478bd9Sstevel@tonic-gate 	 * CPUID functions, and cpi_extd for extended CPUID functions.
27217c478bd9Sstevel@tonic-gate 	 */
27228949bcd6Sandrei 	if (cp->cp_eax <= cpi->cpi_maxeax && cp->cp_eax < NMAX_CPI_STD)
27238949bcd6Sandrei 		xcp = &cpi->cpi_std[cp->cp_eax];
27248949bcd6Sandrei 	else if (cp->cp_eax >= 0x80000000 && cp->cp_eax <= cpi->cpi_xmaxeax &&
27258949bcd6Sandrei 	    cp->cp_eax < 0x80000000 + NMAX_CPI_EXTD)
27268949bcd6Sandrei 		xcp = &cpi->cpi_extd[cp->cp_eax - 0x80000000];
27277c478bd9Sstevel@tonic-gate 	else
27287c478bd9Sstevel@tonic-gate 		/*
27297c478bd9Sstevel@tonic-gate 		 * The caller is asking for data from an input parameter which
27307c478bd9Sstevel@tonic-gate 		 * the kernel has not cached.  In this case we go fetch from
27317c478bd9Sstevel@tonic-gate 		 * the hardware and return the data directly to the user.
27327c478bd9Sstevel@tonic-gate 		 */
27338949bcd6Sandrei 		return (__cpuid_insn(cp));
27348949bcd6Sandrei 
27358949bcd6Sandrei 	cp->cp_eax = xcp->cp_eax;
27368949bcd6Sandrei 	cp->cp_ebx = xcp->cp_ebx;
27378949bcd6Sandrei 	cp->cp_ecx = xcp->cp_ecx;
27388949bcd6Sandrei 	cp->cp_edx = xcp->cp_edx;
27397c478bd9Sstevel@tonic-gate 	return (cp->cp_eax);
27407c478bd9Sstevel@tonic-gate }
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate int
27437c478bd9Sstevel@tonic-gate cpuid_checkpass(cpu_t *cpu, int pass)
27447c478bd9Sstevel@tonic-gate {
27457c478bd9Sstevel@tonic-gate 	return (cpu != NULL && cpu->cpu_m.mcpu_cpi != NULL &&
27467c478bd9Sstevel@tonic-gate 	    cpu->cpu_m.mcpu_cpi->cpi_pass >= pass);
27477c478bd9Sstevel@tonic-gate }
27487c478bd9Sstevel@tonic-gate 
27497c478bd9Sstevel@tonic-gate int
27507c478bd9Sstevel@tonic-gate cpuid_getbrandstr(cpu_t *cpu, char *s, size_t n)
27517c478bd9Sstevel@tonic-gate {
27527c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
27537c478bd9Sstevel@tonic-gate 
27547c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, "%s", cpu->cpu_m.mcpu_cpi->cpi_brandstr));
27557c478bd9Sstevel@tonic-gate }
27567c478bd9Sstevel@tonic-gate 
27577c478bd9Sstevel@tonic-gate int
27588949bcd6Sandrei cpuid_is_cmt(cpu_t *cpu)
27597c478bd9Sstevel@tonic-gate {
27607c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
27617c478bd9Sstevel@tonic-gate 		cpu = CPU;
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_chipid >= 0);
27667c478bd9Sstevel@tonic-gate }
27677c478bd9Sstevel@tonic-gate 
27687c478bd9Sstevel@tonic-gate /*
27697c478bd9Sstevel@tonic-gate  * AMD and Intel both implement the 64-bit variant of the syscall
27707c478bd9Sstevel@tonic-gate  * instruction (syscallq), so if there's -any- support for syscall,
27717c478bd9Sstevel@tonic-gate  * cpuid currently says "yes, we support this".
27727c478bd9Sstevel@tonic-gate  *
27737c478bd9Sstevel@tonic-gate  * However, Intel decided to -not- implement the 32-bit variant of the
27747c478bd9Sstevel@tonic-gate  * syscall instruction, so we provide a predicate to allow our caller
27757c478bd9Sstevel@tonic-gate  * to test that subtlety here.
2776843e1988Sjohnlev  *
2777843e1988Sjohnlev  * XXPV	Currently, 32-bit syscall instructions don't work via the hypervisor,
2778843e1988Sjohnlev  *	even in the case where the hardware would in fact support it.
27797c478bd9Sstevel@tonic-gate  */
27807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27817c478bd9Sstevel@tonic-gate int
27827c478bd9Sstevel@tonic-gate cpuid_syscall32_insn(cpu_t *cpu)
27837c478bd9Sstevel@tonic-gate {
27847c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass((cpu == NULL ? CPU : cpu), 1));
27857c478bd9Sstevel@tonic-gate 
2786843e1988Sjohnlev #if !defined(__xpv)
2787ae115bc7Smrj 	if (cpu == NULL)
2788ae115bc7Smrj 		cpu = CPU;
2789ae115bc7Smrj 
2790ae115bc7Smrj 	/*CSTYLED*/
2791ae115bc7Smrj 	{
2792ae115bc7Smrj 		struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
2793ae115bc7Smrj 
2794ae115bc7Smrj 		if (cpi->cpi_vendor == X86_VENDOR_AMD &&
2795ae115bc7Smrj 		    cpi->cpi_xmaxeax >= 0x80000001 &&
2796ae115bc7Smrj 		    (CPI_FEATURES_XTD_EDX(cpi) & CPUID_AMD_EDX_SYSC))
2797ae115bc7Smrj 			return (1);
2798ae115bc7Smrj 	}
2799843e1988Sjohnlev #endif
28007c478bd9Sstevel@tonic-gate 	return (0);
28017c478bd9Sstevel@tonic-gate }
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate int
28047c478bd9Sstevel@tonic-gate cpuid_getidstr(cpu_t *cpu, char *s, size_t n)
28057c478bd9Sstevel@tonic-gate {
28067c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
28077c478bd9Sstevel@tonic-gate 
28087c478bd9Sstevel@tonic-gate 	static const char fmt[] =
2809ecfa43a5Sdmick 	    "x86 (%s %X family %d model %d step %d clock %d MHz)";
28107c478bd9Sstevel@tonic-gate 	static const char fmt_ht[] =
2811ecfa43a5Sdmick 	    "x86 (chipid 0x%x %s %X family %d model %d step %d clock %d MHz)";
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28147c478bd9Sstevel@tonic-gate 
28158949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
28167c478bd9Sstevel@tonic-gate 		return (snprintf(s, n, fmt_ht, cpi->cpi_chipid,
2817ecfa43a5Sdmick 		    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
2818ecfa43a5Sdmick 		    cpi->cpi_family, cpi->cpi_model,
28197c478bd9Sstevel@tonic-gate 		    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
28207c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, fmt,
2821ecfa43a5Sdmick 	    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
2822ecfa43a5Sdmick 	    cpi->cpi_family, cpi->cpi_model,
28237c478bd9Sstevel@tonic-gate 	    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
28247c478bd9Sstevel@tonic-gate }
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate const char *
28277c478bd9Sstevel@tonic-gate cpuid_getvendorstr(cpu_t *cpu)
28287c478bd9Sstevel@tonic-gate {
28297c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28307c478bd9Sstevel@tonic-gate 	return ((const char *)cpu->cpu_m.mcpu_cpi->cpi_vendorstr);
28317c478bd9Sstevel@tonic-gate }
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate uint_t
28347c478bd9Sstevel@tonic-gate cpuid_getvendor(cpu_t *cpu)
28357c478bd9Sstevel@tonic-gate {
28367c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28377c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_vendor);
28387c478bd9Sstevel@tonic-gate }
28397c478bd9Sstevel@tonic-gate 
28407c478bd9Sstevel@tonic-gate uint_t
28417c478bd9Sstevel@tonic-gate cpuid_getfamily(cpu_t *cpu)
28427c478bd9Sstevel@tonic-gate {
28437c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28447c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_family);
28457c478bd9Sstevel@tonic-gate }
28467c478bd9Sstevel@tonic-gate 
28477c478bd9Sstevel@tonic-gate uint_t
28487c478bd9Sstevel@tonic-gate cpuid_getmodel(cpu_t *cpu)
28497c478bd9Sstevel@tonic-gate {
28507c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28517c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_model);
28527c478bd9Sstevel@tonic-gate }
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate uint_t
28557c478bd9Sstevel@tonic-gate cpuid_get_ncpu_per_chip(cpu_t *cpu)
28567c478bd9Sstevel@tonic-gate {
28577c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28587c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_per_chip);
28597c478bd9Sstevel@tonic-gate }
28607c478bd9Sstevel@tonic-gate 
28617c478bd9Sstevel@tonic-gate uint_t
28628949bcd6Sandrei cpuid_get_ncore_per_chip(cpu_t *cpu)
28638949bcd6Sandrei {
28648949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
28658949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_ncore_per_chip);
28668949bcd6Sandrei }
28678949bcd6Sandrei 
28688949bcd6Sandrei uint_t
2869d129bde2Sesaxe cpuid_get_ncpu_sharing_last_cache(cpu_t *cpu)
2870d129bde2Sesaxe {
2871d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
2872d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_shr_last_cache);
2873d129bde2Sesaxe }
2874d129bde2Sesaxe 
2875d129bde2Sesaxe id_t
2876d129bde2Sesaxe cpuid_get_last_lvl_cacheid(cpu_t *cpu)
2877d129bde2Sesaxe {
2878d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
2879d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
2880d129bde2Sesaxe }
2881d129bde2Sesaxe 
2882d129bde2Sesaxe uint_t
28837c478bd9Sstevel@tonic-gate cpuid_getstep(cpu_t *cpu)
28847c478bd9Sstevel@tonic-gate {
28857c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28867c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_step);
28877c478bd9Sstevel@tonic-gate }
28887c478bd9Sstevel@tonic-gate 
28892449e17fSsherrym uint_t
28902449e17fSsherrym cpuid_getsig(struct cpu *cpu)
28912449e17fSsherrym {
28922449e17fSsherrym 	ASSERT(cpuid_checkpass(cpu, 1));
28932449e17fSsherrym 	return (cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_eax);
28942449e17fSsherrym }
28952449e17fSsherrym 
28968a40a695Sgavinm uint32_t
28978a40a695Sgavinm cpuid_getchiprev(struct cpu *cpu)
28988a40a695Sgavinm {
28998a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
29008a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprev);
29018a40a695Sgavinm }
29028a40a695Sgavinm 
29038a40a695Sgavinm const char *
29048a40a695Sgavinm cpuid_getchiprevstr(struct cpu *cpu)
29058a40a695Sgavinm {
29068a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
29078a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprevstr);
29088a40a695Sgavinm }
29098a40a695Sgavinm 
29108a40a695Sgavinm uint32_t
29118a40a695Sgavinm cpuid_getsockettype(struct cpu *cpu)
29128a40a695Sgavinm {
29138a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
29148a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_socket);
29158a40a695Sgavinm }
29168a40a695Sgavinm 
291789e921d5SKuriakose Kuruvilla const char *
291889e921d5SKuriakose Kuruvilla cpuid_getsocketstr(cpu_t *cpu)
291989e921d5SKuriakose Kuruvilla {
292089e921d5SKuriakose Kuruvilla 	static const char *socketstr = NULL;
292189e921d5SKuriakose Kuruvilla 	struct cpuid_info *cpi;
292289e921d5SKuriakose Kuruvilla 
292389e921d5SKuriakose Kuruvilla 	ASSERT(cpuid_checkpass(cpu, 1));
292489e921d5SKuriakose Kuruvilla 	cpi = cpu->cpu_m.mcpu_cpi;
292589e921d5SKuriakose Kuruvilla 
292689e921d5SKuriakose Kuruvilla 	/* Assume that socket types are the same across the system */
292789e921d5SKuriakose Kuruvilla 	if (socketstr == NULL)
292889e921d5SKuriakose Kuruvilla 		socketstr = _cpuid_sktstr(cpi->cpi_vendor, cpi->cpi_family,
292989e921d5SKuriakose Kuruvilla 		    cpi->cpi_model, cpi->cpi_step);
293089e921d5SKuriakose Kuruvilla 
293189e921d5SKuriakose Kuruvilla 
293289e921d5SKuriakose Kuruvilla 	return (socketstr);
293389e921d5SKuriakose Kuruvilla }
293489e921d5SKuriakose Kuruvilla 
2935fb2f18f8Sesaxe int
2936fb2f18f8Sesaxe cpuid_get_chipid(cpu_t *cpu)
29377c478bd9Sstevel@tonic-gate {
29387c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29397c478bd9Sstevel@tonic-gate 
29408949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
29417c478bd9Sstevel@tonic-gate 		return (cpu->cpu_m.mcpu_cpi->cpi_chipid);
29427c478bd9Sstevel@tonic-gate 	return (cpu->cpu_id);
29437c478bd9Sstevel@tonic-gate }
29447c478bd9Sstevel@tonic-gate 
29458949bcd6Sandrei id_t
2946fb2f18f8Sesaxe cpuid_get_coreid(cpu_t *cpu)
29478949bcd6Sandrei {
29488949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
29498949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_coreid);
29508949bcd6Sandrei }
29518949bcd6Sandrei 
29527c478bd9Sstevel@tonic-gate int
295310569901Sgavinm cpuid_get_pkgcoreid(cpu_t *cpu)
295410569901Sgavinm {
295510569901Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
295610569901Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_pkgcoreid);
295710569901Sgavinm }
295810569901Sgavinm 
295910569901Sgavinm int
2960fb2f18f8Sesaxe cpuid_get_clogid(cpu_t *cpu)
29617c478bd9Sstevel@tonic-gate {
29627c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29637c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_clogid);
29647c478bd9Sstevel@tonic-gate }
29657c478bd9Sstevel@tonic-gate 
2966b885580bSAlexander Kolbasov int
2967b885580bSAlexander Kolbasov cpuid_get_cacheid(cpu_t *cpu)
2968b885580bSAlexander Kolbasov {
2969b885580bSAlexander Kolbasov 	ASSERT(cpuid_checkpass(cpu, 1));
2970b885580bSAlexander Kolbasov 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
2971b885580bSAlexander Kolbasov }
2972b885580bSAlexander Kolbasov 
29738031591dSSrihari Venkatesan uint_t
29748031591dSSrihari Venkatesan cpuid_get_procnodeid(cpu_t *cpu)
29758031591dSSrihari Venkatesan {
29768031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
29778031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodeid);
29788031591dSSrihari Venkatesan }
29798031591dSSrihari Venkatesan 
29808031591dSSrihari Venkatesan uint_t
29818031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg(cpu_t *cpu)
29828031591dSSrihari Venkatesan {
29838031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
29848031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg);
29858031591dSSrihari Venkatesan }
29868031591dSSrihari Venkatesan 
29872ef50f01SJoe Bonasera /*ARGSUSED*/
29882ef50f01SJoe Bonasera int
29892ef50f01SJoe Bonasera cpuid_have_cr8access(cpu_t *cpu)
29902ef50f01SJoe Bonasera {
29912ef50f01SJoe Bonasera #if defined(__amd64)
29922ef50f01SJoe Bonasera 	return (1);
29932ef50f01SJoe Bonasera #else
29942ef50f01SJoe Bonasera 	struct cpuid_info *cpi;
29952ef50f01SJoe Bonasera 
29962ef50f01SJoe Bonasera 	ASSERT(cpu != NULL);
29972ef50f01SJoe Bonasera 	cpi = cpu->cpu_m.mcpu_cpi;
29982ef50f01SJoe Bonasera 	if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 &&
29992ef50f01SJoe Bonasera 	    (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0)
30002ef50f01SJoe Bonasera 		return (1);
30012ef50f01SJoe Bonasera 	return (0);
30022ef50f01SJoe Bonasera #endif
30032ef50f01SJoe Bonasera }
30042ef50f01SJoe Bonasera 
3005fa96bd91SMichael Corcoran uint32_t
3006fa96bd91SMichael Corcoran cpuid_get_apicid(cpu_t *cpu)
3007fa96bd91SMichael Corcoran {
3008fa96bd91SMichael Corcoran 	ASSERT(cpuid_checkpass(cpu, 1));
3009fa96bd91SMichael Corcoran 	if (cpu->cpu_m.mcpu_cpi->cpi_maxeax < 1) {
3010fa96bd91SMichael Corcoran 		return (UINT32_MAX);
3011fa96bd91SMichael Corcoran 	} else {
3012fa96bd91SMichael Corcoran 		return (cpu->cpu_m.mcpu_cpi->cpi_apicid);
3013fa96bd91SMichael Corcoran 	}
3014fa96bd91SMichael Corcoran }
3015fa96bd91SMichael Corcoran 
30167c478bd9Sstevel@tonic-gate void
30177c478bd9Sstevel@tonic-gate cpuid_get_addrsize(cpu_t *cpu, uint_t *pabits, uint_t *vabits)
30187c478bd9Sstevel@tonic-gate {
30197c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
30227c478bd9Sstevel@tonic-gate 		cpu = CPU;
30237c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
30247c478bd9Sstevel@tonic-gate 
30257c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate 	if (pabits)
30287c478bd9Sstevel@tonic-gate 		*pabits = cpi->cpi_pabits;
30297c478bd9Sstevel@tonic-gate 	if (vabits)
30307c478bd9Sstevel@tonic-gate 		*vabits = cpi->cpi_vabits;
30317c478bd9Sstevel@tonic-gate }
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate /*
30347c478bd9Sstevel@tonic-gate  * Returns the number of data TLB entries for a corresponding
30357c478bd9Sstevel@tonic-gate  * pagesize.  If it can't be computed, or isn't known, the
30367c478bd9Sstevel@tonic-gate  * routine returns zero.  If you ask about an architecturally
30377c478bd9Sstevel@tonic-gate  * impossible pagesize, the routine will panic (so that the
30387c478bd9Sstevel@tonic-gate  * hat implementor knows that things are inconsistent.)
30397c478bd9Sstevel@tonic-gate  */
30407c478bd9Sstevel@tonic-gate uint_t
30417c478bd9Sstevel@tonic-gate cpuid_get_dtlb_nent(cpu_t *cpu, size_t pagesize)
30427c478bd9Sstevel@tonic-gate {
30437c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
30447c478bd9Sstevel@tonic-gate 	uint_t dtlb_nent = 0;
30457c478bd9Sstevel@tonic-gate 
30467c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
30477c478bd9Sstevel@tonic-gate 		cpu = CPU;
30487c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
30497c478bd9Sstevel@tonic-gate 
30507c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30517c478bd9Sstevel@tonic-gate 
30527c478bd9Sstevel@tonic-gate 	/*
30537c478bd9Sstevel@tonic-gate 	 * Check the L2 TLB info
30547c478bd9Sstevel@tonic-gate 	 */
30557c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000006) {
30568949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[6];
30577c478bd9Sstevel@tonic-gate 
30587c478bd9Sstevel@tonic-gate 		switch (pagesize) {
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate 		case 4 * 1024:
30617c478bd9Sstevel@tonic-gate 			/*
30627c478bd9Sstevel@tonic-gate 			 * All zero in the top 16 bits of the register
30637c478bd9Sstevel@tonic-gate 			 * indicates a unified TLB. Size is in low 16 bits.
30647c478bd9Sstevel@tonic-gate 			 */
30657c478bd9Sstevel@tonic-gate 			if ((cp->cp_ebx & 0xffff0000) == 0)
30667c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_ebx & 0x0000ffff;
30677c478bd9Sstevel@tonic-gate 			else
30687c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_ebx, 27, 16);
30697c478bd9Sstevel@tonic-gate 			break;
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
30727c478bd9Sstevel@tonic-gate 			if ((cp->cp_eax & 0xffff0000) == 0)
30737c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_eax & 0x0000ffff;
30747c478bd9Sstevel@tonic-gate 			else
30757c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_eax, 27, 16);
30767c478bd9Sstevel@tonic-gate 			break;
30777c478bd9Sstevel@tonic-gate 
30787c478bd9Sstevel@tonic-gate 		default:
30797c478bd9Sstevel@tonic-gate 			panic("unknown L2 pagesize");
30807c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
30817c478bd9Sstevel@tonic-gate 		}
30827c478bd9Sstevel@tonic-gate 	}
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate 	if (dtlb_nent != 0)
30857c478bd9Sstevel@tonic-gate 		return (dtlb_nent);
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate 	/*
30887c478bd9Sstevel@tonic-gate 	 * No L2 TLB support for this size, try L1.
30897c478bd9Sstevel@tonic-gate 	 */
30907c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000005) {
30918949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[5];
30927c478bd9Sstevel@tonic-gate 
30937c478bd9Sstevel@tonic-gate 		switch (pagesize) {
30947c478bd9Sstevel@tonic-gate 		case 4 * 1024:
30957c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_ebx, 23, 16);
30967c478bd9Sstevel@tonic-gate 			break;
30977c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
30987c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_eax, 23, 16);
30997c478bd9Sstevel@tonic-gate 			break;
31007c478bd9Sstevel@tonic-gate 		default:
31017c478bd9Sstevel@tonic-gate 			panic("unknown L1 d-TLB pagesize");
31027c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
31037c478bd9Sstevel@tonic-gate 		}
31047c478bd9Sstevel@tonic-gate 	}
31057c478bd9Sstevel@tonic-gate 
31067c478bd9Sstevel@tonic-gate 	return (dtlb_nent);
31077c478bd9Sstevel@tonic-gate }
31087c478bd9Sstevel@tonic-gate 
31097c478bd9Sstevel@tonic-gate /*
31107c478bd9Sstevel@tonic-gate  * Return 0 if the erratum is not present or not applicable, positive
31117c478bd9Sstevel@tonic-gate  * if it is, and negative if the status of the erratum is unknown.
31127c478bd9Sstevel@tonic-gate  *
31137c478bd9Sstevel@tonic-gate  * See "Revision Guide for AMD Athlon(tm) 64 and AMD Opteron(tm)
31142201b277Skucharsk  * Processors" #25759, Rev 3.57, August 2005
31157c478bd9Sstevel@tonic-gate  */
31167c478bd9Sstevel@tonic-gate int
31177c478bd9Sstevel@tonic-gate cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum)
31187c478bd9Sstevel@tonic-gate {
31197c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
31208949bcd6Sandrei 	uint_t eax;
31217c478bd9Sstevel@tonic-gate 
3122ea99987eSsethg 	/*
3123ea99987eSsethg 	 * Bail out if this CPU isn't an AMD CPU, or if it's
3124ea99987eSsethg 	 * a legacy (32-bit) AMD CPU.
3125ea99987eSsethg 	 */
3126ea99987eSsethg 	if (cpi->cpi_vendor != X86_VENDOR_AMD ||
3127875b116eSkchow 	    cpi->cpi_family == 4 || cpi->cpi_family == 5 ||
3128875b116eSkchow 	    cpi->cpi_family == 6)
31298a40a695Sgavinm 
31307c478bd9Sstevel@tonic-gate 		return (0);
31317c478bd9Sstevel@tonic-gate 
31327c478bd9Sstevel@tonic-gate 	eax = cpi->cpi_std[1].cp_eax;
31337c478bd9Sstevel@tonic-gate 
31347c478bd9Sstevel@tonic-gate #define	SH_B0(eax)	(eax == 0xf40 || eax == 0xf50)
31357c478bd9Sstevel@tonic-gate #define	SH_B3(eax) 	(eax == 0xf51)
3136ee88d2b9Skchow #define	B(eax)		(SH_B0(eax) || SH_B3(eax))
31377c478bd9Sstevel@tonic-gate 
31387c478bd9Sstevel@tonic-gate #define	SH_C0(eax)	(eax == 0xf48 || eax == 0xf58)
31397c478bd9Sstevel@tonic-gate 
31407c478bd9Sstevel@tonic-gate #define	SH_CG(eax)	(eax == 0xf4a || eax == 0xf5a || eax == 0xf7a)
31417c478bd9Sstevel@tonic-gate #define	DH_CG(eax)	(eax == 0xfc0 || eax == 0xfe0 || eax == 0xff0)
31427c478bd9Sstevel@tonic-gate #define	CH_CG(eax)	(eax == 0xf82 || eax == 0xfb2)
3143ee88d2b9Skchow #define	CG(eax)		(SH_CG(eax) || DH_CG(eax) || CH_CG(eax))
31447c478bd9Sstevel@tonic-gate 
31457c478bd9Sstevel@tonic-gate #define	SH_D0(eax)	(eax == 0x10f40 || eax == 0x10f50 || eax == 0x10f70)
31467c478bd9Sstevel@tonic-gate #define	DH_D0(eax)	(eax == 0x10fc0 || eax == 0x10ff0)
31477c478bd9Sstevel@tonic-gate #define	CH_D0(eax)	(eax == 0x10f80 || eax == 0x10fb0)
3148ee88d2b9Skchow #define	D0(eax)		(SH_D0(eax) || DH_D0(eax) || CH_D0(eax))
31497c478bd9Sstevel@tonic-gate 
31507c478bd9Sstevel@tonic-gate #define	SH_E0(eax)	(eax == 0x20f50 || eax == 0x20f40 || eax == 0x20f70)
31517c478bd9Sstevel@tonic-gate #define	JH_E1(eax)	(eax == 0x20f10)	/* JH8_E0 had 0x20f30 */
31527c478bd9Sstevel@tonic-gate #define	DH_E3(eax)	(eax == 0x20fc0 || eax == 0x20ff0)
31537c478bd9Sstevel@tonic-gate #define	SH_E4(eax)	(eax == 0x20f51 || eax == 0x20f71)
31547c478bd9Sstevel@tonic-gate #define	BH_E4(eax)	(eax == 0x20fb1)
31557c478bd9Sstevel@tonic-gate #define	SH_E5(eax)	(eax == 0x20f42)
31567c478bd9Sstevel@tonic-gate #define	DH_E6(eax)	(eax == 0x20ff2 || eax == 0x20fc2)
31577c478bd9Sstevel@tonic-gate #define	JH_E6(eax)	(eax == 0x20f12 || eax == 0x20f32)
3158ee88d2b9Skchow #define	EX(eax)		(SH_E0(eax) || JH_E1(eax) || DH_E3(eax) || \
3159ee88d2b9Skchow 			    SH_E4(eax) || BH_E4(eax) || SH_E5(eax) || \
3160ee88d2b9Skchow 			    DH_E6(eax) || JH_E6(eax))
31617c478bd9Sstevel@tonic-gate 
3162512cf780Skchow #define	DR_AX(eax)	(eax == 0x100f00 || eax == 0x100f01 || eax == 0x100f02)
3163512cf780Skchow #define	DR_B0(eax)	(eax == 0x100f20)
3164512cf780Skchow #define	DR_B1(eax)	(eax == 0x100f21)
3165512cf780Skchow #define	DR_BA(eax)	(eax == 0x100f2a)
3166512cf780Skchow #define	DR_B2(eax)	(eax == 0x100f22)
3167512cf780Skchow #define	DR_B3(eax)	(eax == 0x100f23)
3168512cf780Skchow #define	RB_C0(eax)	(eax == 0x100f40)
3169512cf780Skchow 
31707c478bd9Sstevel@tonic-gate 	switch (erratum) {
31717c478bd9Sstevel@tonic-gate 	case 1:
3172875b116eSkchow 		return (cpi->cpi_family < 0x10);
31737c478bd9Sstevel@tonic-gate 	case 51:	/* what does the asterisk mean? */
31747c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
31757c478bd9Sstevel@tonic-gate 	case 52:
31767c478bd9Sstevel@tonic-gate 		return (B(eax));
31777c478bd9Sstevel@tonic-gate 	case 57:
3178512cf780Skchow 		return (cpi->cpi_family <= 0x11);
31797c478bd9Sstevel@tonic-gate 	case 58:
31807c478bd9Sstevel@tonic-gate 		return (B(eax));
31817c478bd9Sstevel@tonic-gate 	case 60:
3182512cf780Skchow 		return (cpi->cpi_family <= 0x11);
31837c478bd9Sstevel@tonic-gate 	case 61:
31847c478bd9Sstevel@tonic-gate 	case 62:
31857c478bd9Sstevel@tonic-gate 	case 63:
31867c478bd9Sstevel@tonic-gate 	case 64:
31877c478bd9Sstevel@tonic-gate 	case 65:
31887c478bd9Sstevel@tonic-gate 	case 66:
31897c478bd9Sstevel@tonic-gate 	case 68:
31907c478bd9Sstevel@tonic-gate 	case 69:
31917c478bd9Sstevel@tonic-gate 	case 70:
31927c478bd9Sstevel@tonic-gate 	case 71:
31937c478bd9Sstevel@tonic-gate 		return (B(eax));
31947c478bd9Sstevel@tonic-gate 	case 72:
31957c478bd9Sstevel@tonic-gate 		return (SH_B0(eax));
31967c478bd9Sstevel@tonic-gate 	case 74:
31977c478bd9Sstevel@tonic-gate 		return (B(eax));
31987c478bd9Sstevel@tonic-gate 	case 75:
3199875b116eSkchow 		return (cpi->cpi_family < 0x10);
32007c478bd9Sstevel@tonic-gate 	case 76:
32017c478bd9Sstevel@tonic-gate 		return (B(eax));
32027c478bd9Sstevel@tonic-gate 	case 77:
3203512cf780Skchow 		return (cpi->cpi_family <= 0x11);
32047c478bd9Sstevel@tonic-gate 	case 78:
32057c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32067c478bd9Sstevel@tonic-gate 	case 79:
32077c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
32087c478bd9Sstevel@tonic-gate 	case 80:
32097c478bd9Sstevel@tonic-gate 	case 81:
32107c478bd9Sstevel@tonic-gate 	case 82:
32117c478bd9Sstevel@tonic-gate 		return (B(eax));
32127c478bd9Sstevel@tonic-gate 	case 83:
32137c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
32147c478bd9Sstevel@tonic-gate 	case 85:
3215875b116eSkchow 		return (cpi->cpi_family < 0x10);
32167c478bd9Sstevel@tonic-gate 	case 86:
32177c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
32187c478bd9Sstevel@tonic-gate 	case 88:
32197c478bd9Sstevel@tonic-gate #if !defined(__amd64)
32207c478bd9Sstevel@tonic-gate 		return (0);
32217c478bd9Sstevel@tonic-gate #else
32227c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32237c478bd9Sstevel@tonic-gate #endif
32247c478bd9Sstevel@tonic-gate 	case 89:
3225875b116eSkchow 		return (cpi->cpi_family < 0x10);
32267c478bd9Sstevel@tonic-gate 	case 90:
32277c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
32287c478bd9Sstevel@tonic-gate 	case 91:
32297c478bd9Sstevel@tonic-gate 	case 92:
32307c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32317c478bd9Sstevel@tonic-gate 	case 93:
32327c478bd9Sstevel@tonic-gate 		return (SH_C0(eax));
32337c478bd9Sstevel@tonic-gate 	case 94:
32347c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
32357c478bd9Sstevel@tonic-gate 	case 95:
32367c478bd9Sstevel@tonic-gate #if !defined(__amd64)
32377c478bd9Sstevel@tonic-gate 		return (0);
32387c478bd9Sstevel@tonic-gate #else
32397c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32407c478bd9Sstevel@tonic-gate #endif
32417c478bd9Sstevel@tonic-gate 	case 96:
32427c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
32437c478bd9Sstevel@tonic-gate 	case 97:
32447c478bd9Sstevel@tonic-gate 	case 98:
32457c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
32467c478bd9Sstevel@tonic-gate 	case 99:
32477c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
32487c478bd9Sstevel@tonic-gate 	case 100:
32497c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
32507c478bd9Sstevel@tonic-gate 	case 101:
32517c478bd9Sstevel@tonic-gate 	case 103:
32527c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
32537c478bd9Sstevel@tonic-gate 	case 104:
32547c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
32557c478bd9Sstevel@tonic-gate 	case 105:
32567c478bd9Sstevel@tonic-gate 	case 106:
32577c478bd9Sstevel@tonic-gate 	case 107:
32587c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
32597c478bd9Sstevel@tonic-gate 	case 108:
32607c478bd9Sstevel@tonic-gate 		return (DH_CG(eax));
32617c478bd9Sstevel@tonic-gate 	case 109:
32627c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
32637c478bd9Sstevel@tonic-gate 	case 110:
32647c478bd9Sstevel@tonic-gate 		return (D0(eax) || EX(eax));
32657c478bd9Sstevel@tonic-gate 	case 111:
32667c478bd9Sstevel@tonic-gate 		return (CG(eax));
32677c478bd9Sstevel@tonic-gate 	case 112:
32687c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
32697c478bd9Sstevel@tonic-gate 	case 113:
32707c478bd9Sstevel@tonic-gate 		return (eax == 0x20fc0);
32717c478bd9Sstevel@tonic-gate 	case 114:
32727c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
32737c478bd9Sstevel@tonic-gate 	case 115:
32747c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax));
32757c478bd9Sstevel@tonic-gate 	case 116:
32767c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
32777c478bd9Sstevel@tonic-gate 	case 117:
32787c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
32797c478bd9Sstevel@tonic-gate 	case 118:
32807c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || SH_E4(eax) || BH_E4(eax) ||
32817c478bd9Sstevel@tonic-gate 		    JH_E6(eax));
32827c478bd9Sstevel@tonic-gate 	case 121:
32837c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
32847c478bd9Sstevel@tonic-gate 	case 122:
3285512cf780Skchow 		return (cpi->cpi_family < 0x10 || cpi->cpi_family == 0x11);
32867c478bd9Sstevel@tonic-gate 	case 123:
32877c478bd9Sstevel@tonic-gate 		return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax));
32882201b277Skucharsk 	case 131:
3289875b116eSkchow 		return (cpi->cpi_family < 0x10);
3290ef50d8c0Sesaxe 	case 6336786:
3291ef50d8c0Sesaxe 		/*
3292ef50d8c0Sesaxe 		 * Test for AdvPowerMgmtInfo.TscPStateInvariant
3293875b116eSkchow 		 * if this is a K8 family or newer processor
3294ef50d8c0Sesaxe 		 */
3295ef50d8c0Sesaxe 		if (CPI_FAMILY(cpi) == 0xf) {
32968949bcd6Sandrei 			struct cpuid_regs regs;
32978949bcd6Sandrei 			regs.cp_eax = 0x80000007;
32988949bcd6Sandrei 			(void) __cpuid_insn(&regs);
32998949bcd6Sandrei 			return (!(regs.cp_edx & 0x100));
3300ef50d8c0Sesaxe 		}
3301ef50d8c0Sesaxe 		return (0);
3302ee88d2b9Skchow 	case 6323525:
3303ee88d2b9Skchow 		return (((((eax >> 12) & 0xff00) + (eax & 0xf00)) |
3304ee88d2b9Skchow 		    (((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0))) < 0xf40);
3305ee88d2b9Skchow 
3306512cf780Skchow 	case 6671130:
3307512cf780Skchow 		/*
3308512cf780Skchow 		 * check for processors (pre-Shanghai) that do not provide
3309512cf780Skchow 		 * optimal management of 1gb ptes in its tlb.
3310512cf780Skchow 		 */
3311512cf780Skchow 		return (cpi->cpi_family == 0x10 && cpi->cpi_model < 4);
3312512cf780Skchow 
3313512cf780Skchow 	case 298:
3314512cf780Skchow 		return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) ||
3315512cf780Skchow 		    DR_B2(eax) || RB_C0(eax));
3316512cf780Skchow 
3317512cf780Skchow 	default:
3318512cf780Skchow 		return (-1);
3319512cf780Skchow 
3320512cf780Skchow 	}
3321512cf780Skchow }
3322512cf780Skchow 
3323512cf780Skchow /*
3324512cf780Skchow  * Determine if specified erratum is present via OSVW (OS Visible Workaround).
3325512cf780Skchow  * Return 1 if erratum is present, 0 if not present and -1 if indeterminate.
3326512cf780Skchow  */
3327512cf780Skchow int
3328512cf780Skchow osvw_opteron_erratum(cpu_t *cpu, uint_t erratum)
3329512cf780Skchow {
3330512cf780Skchow 	struct cpuid_info	*cpi;
3331512cf780Skchow 	uint_t			osvwid;
3332512cf780Skchow 	static int		osvwfeature = -1;
3333512cf780Skchow 	uint64_t		osvwlength;
3334512cf780Skchow 
3335512cf780Skchow 
3336512cf780Skchow 	cpi = cpu->cpu_m.mcpu_cpi;
3337512cf780Skchow 
3338512cf780Skchow 	/* confirm OSVW supported */
3339512cf780Skchow 	if (osvwfeature == -1) {
3340512cf780Skchow 		osvwfeature = cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW;
3341512cf780Skchow 	} else {
3342512cf780Skchow 		/* assert that osvw feature setting is consistent on all cpus */
3343512cf780Skchow 		ASSERT(osvwfeature ==
3344512cf780Skchow 		    (cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW));
3345512cf780Skchow 	}
3346512cf780Skchow 	if (!osvwfeature)
3347512cf780Skchow 		return (-1);
3348512cf780Skchow 
3349512cf780Skchow 	osvwlength = rdmsr(MSR_AMD_OSVW_ID_LEN) & OSVW_ID_LEN_MASK;
3350512cf780Skchow 
3351512cf780Skchow 	switch (erratum) {
3352512cf780Skchow 	case 298:	/* osvwid is 0 */
3353512cf780Skchow 		osvwid = 0;
3354512cf780Skchow 		if (osvwlength <= (uint64_t)osvwid) {
3355512cf780Skchow 			/* osvwid 0 is unknown */
3356512cf780Skchow 			return (-1);
3357512cf780Skchow 		}
3358512cf780Skchow 
3359512cf780Skchow 		/*
3360512cf780Skchow 		 * Check the OSVW STATUS MSR to determine the state
3361512cf780Skchow 		 * of the erratum where:
3362512cf780Skchow 		 *   0 - fixed by HW
3363512cf780Skchow 		 *   1 - BIOS has applied the workaround when BIOS
3364512cf780Skchow 		 *   workaround is available. (Or for other errata,
3365512cf780Skchow 		 *   OS workaround is required.)
3366512cf780Skchow 		 * For a value of 1, caller will confirm that the
3367512cf780Skchow 		 * erratum 298 workaround has indeed been applied by BIOS.
3368512cf780Skchow 		 *
3369512cf780Skchow 		 * A 1 may be set in cpus that have a HW fix
3370512cf780Skchow 		 * in a mixed cpu system. Regarding erratum 298:
3371512cf780Skchow 		 *   In a multiprocessor platform, the workaround above
3372512cf780Skchow 		 *   should be applied to all processors regardless of
3373512cf780Skchow 		 *   silicon revision when an affected processor is
3374512cf780Skchow 		 *   present.
3375512cf780Skchow 		 */
3376512cf780Skchow 
3377512cf780Skchow 		return (rdmsr(MSR_AMD_OSVW_STATUS +
3378512cf780Skchow 		    (osvwid / OSVW_ID_CNT_PER_MSR)) &
3379512cf780Skchow 		    (1ULL << (osvwid % OSVW_ID_CNT_PER_MSR)));
3380512cf780Skchow 
33817c478bd9Sstevel@tonic-gate 	default:
33827c478bd9Sstevel@tonic-gate 		return (-1);
33837c478bd9Sstevel@tonic-gate 	}
33847c478bd9Sstevel@tonic-gate }
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate static const char assoc_str[] = "associativity";
33877c478bd9Sstevel@tonic-gate static const char line_str[] = "line-size";
33887c478bd9Sstevel@tonic-gate static const char size_str[] = "size";
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate static void
33917c478bd9Sstevel@tonic-gate add_cache_prop(dev_info_t *devi, const char *label, const char *type,
33927c478bd9Sstevel@tonic-gate     uint32_t val)
33937c478bd9Sstevel@tonic-gate {
33947c478bd9Sstevel@tonic-gate 	char buf[128];
33957c478bd9Sstevel@tonic-gate 
33967c478bd9Sstevel@tonic-gate 	/*
33977c478bd9Sstevel@tonic-gate 	 * ndi_prop_update_int() is used because it is desirable for
33987c478bd9Sstevel@tonic-gate 	 * DDI_PROP_HW_DEF and DDI_PROP_DONTSLEEP to be set.
33997c478bd9Sstevel@tonic-gate 	 */
34007c478bd9Sstevel@tonic-gate 	if (snprintf(buf, sizeof (buf), "%s-%s", label, type) < sizeof (buf))
34017c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, buf, val);
34027c478bd9Sstevel@tonic-gate }
34037c478bd9Sstevel@tonic-gate 
34047c478bd9Sstevel@tonic-gate /*
34057c478bd9Sstevel@tonic-gate  * Intel-style cache/tlb description
34067c478bd9Sstevel@tonic-gate  *
34077c478bd9Sstevel@tonic-gate  * Standard cpuid level 2 gives a randomly ordered
34087c478bd9Sstevel@tonic-gate  * selection of tags that index into a table that describes
34097c478bd9Sstevel@tonic-gate  * cache and tlb properties.
34107c478bd9Sstevel@tonic-gate  */
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate static const char l1_icache_str[] = "l1-icache";
34137c478bd9Sstevel@tonic-gate static const char l1_dcache_str[] = "l1-dcache";
34147c478bd9Sstevel@tonic-gate static const char l2_cache_str[] = "l2-cache";
3415ae115bc7Smrj static const char l3_cache_str[] = "l3-cache";
34167c478bd9Sstevel@tonic-gate static const char itlb4k_str[] = "itlb-4K";
34177c478bd9Sstevel@tonic-gate static const char dtlb4k_str[] = "dtlb-4K";
3418824e4fecSvd224797 static const char itlb2M_str[] = "itlb-2M";
34197c478bd9Sstevel@tonic-gate static const char itlb4M_str[] = "itlb-4M";
34207c478bd9Sstevel@tonic-gate static const char dtlb4M_str[] = "dtlb-4M";
342125dfb062Sksadhukh static const char dtlb24_str[] = "dtlb0-2M-4M";
34227c478bd9Sstevel@tonic-gate static const char itlb424_str[] = "itlb-4K-2M-4M";
342325dfb062Sksadhukh static const char itlb24_str[] = "itlb-2M-4M";
34247c478bd9Sstevel@tonic-gate static const char dtlb44_str[] = "dtlb-4K-4M";
34257c478bd9Sstevel@tonic-gate static const char sl1_dcache_str[] = "sectored-l1-dcache";
34267c478bd9Sstevel@tonic-gate static const char sl2_cache_str[] = "sectored-l2-cache";
34277c478bd9Sstevel@tonic-gate static const char itrace_str[] = "itrace-cache";
34287c478bd9Sstevel@tonic-gate static const char sl3_cache_str[] = "sectored-l3-cache";
342925dfb062Sksadhukh static const char sh_l2_tlb4k_str[] = "shared-l2-tlb-4k";
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate static const struct cachetab {
34327c478bd9Sstevel@tonic-gate 	uint8_t 	ct_code;
34337c478bd9Sstevel@tonic-gate 	uint8_t		ct_assoc;
34347c478bd9Sstevel@tonic-gate 	uint16_t 	ct_line_size;
34357c478bd9Sstevel@tonic-gate 	size_t		ct_size;
34367c478bd9Sstevel@tonic-gate 	const char	*ct_label;
34377c478bd9Sstevel@tonic-gate } intel_ctab[] = {
3438824e4fecSvd224797 	/*
3439824e4fecSvd224797 	 * maintain descending order!
3440824e4fecSvd224797 	 *
3441824e4fecSvd224797 	 * Codes ignored - Reason
3442824e4fecSvd224797 	 * ----------------------
3443824e4fecSvd224797 	 * 40H - intel_cpuid_4_cache_info() disambiguates l2/l3 cache
3444824e4fecSvd224797 	 * f0H/f1H - Currently we do not interpret prefetch size by design
3445824e4fecSvd224797 	 */
344625dfb062Sksadhukh 	{ 0xe4, 16, 64, 8*1024*1024, l3_cache_str},
344725dfb062Sksadhukh 	{ 0xe3, 16, 64, 4*1024*1024, l3_cache_str},
344825dfb062Sksadhukh 	{ 0xe2, 16, 64, 2*1024*1024, l3_cache_str},
344925dfb062Sksadhukh 	{ 0xde, 12, 64, 6*1024*1024, l3_cache_str},
345025dfb062Sksadhukh 	{ 0xdd, 12, 64, 3*1024*1024, l3_cache_str},
345125dfb062Sksadhukh 	{ 0xdc, 12, 64, ((1*1024*1024)+(512*1024)), l3_cache_str},
345225dfb062Sksadhukh 	{ 0xd8, 8, 64, 4*1024*1024, l3_cache_str},
345325dfb062Sksadhukh 	{ 0xd7, 8, 64, 2*1024*1024, l3_cache_str},
345425dfb062Sksadhukh 	{ 0xd6, 8, 64, 1*1024*1024, l3_cache_str},
345525dfb062Sksadhukh 	{ 0xd2, 4, 64, 2*1024*1024, l3_cache_str},
345625dfb062Sksadhukh 	{ 0xd1, 4, 64, 1*1024*1024, l3_cache_str},
345725dfb062Sksadhukh 	{ 0xd0, 4, 64, 512*1024, l3_cache_str},
345825dfb062Sksadhukh 	{ 0xca, 4, 0, 512, sh_l2_tlb4k_str},
3459824e4fecSvd224797 	{ 0xc0, 4, 0, 8, dtlb44_str },
3460824e4fecSvd224797 	{ 0xba, 4, 0, 64, dtlb4k_str },
3461ae115bc7Smrj 	{ 0xb4, 4, 0, 256, dtlb4k_str },
34627c478bd9Sstevel@tonic-gate 	{ 0xb3, 4, 0, 128, dtlb4k_str },
346325dfb062Sksadhukh 	{ 0xb2, 4, 0, 64, itlb4k_str },
34647c478bd9Sstevel@tonic-gate 	{ 0xb0, 4, 0, 128, itlb4k_str },
34657c478bd9Sstevel@tonic-gate 	{ 0x87, 8, 64, 1024*1024, l2_cache_str},
34667c478bd9Sstevel@tonic-gate 	{ 0x86, 4, 64, 512*1024, l2_cache_str},
34677c478bd9Sstevel@tonic-gate 	{ 0x85, 8, 32, 2*1024*1024, l2_cache_str},
34687c478bd9Sstevel@tonic-gate 	{ 0x84, 8, 32, 1024*1024, l2_cache_str},
34697c478bd9Sstevel@tonic-gate 	{ 0x83, 8, 32, 512*1024, l2_cache_str},
34707c478bd9Sstevel@tonic-gate 	{ 0x82, 8, 32, 256*1024, l2_cache_str},
3471824e4fecSvd224797 	{ 0x80, 8, 64, 512*1024, l2_cache_str},
34727c478bd9Sstevel@tonic-gate 	{ 0x7f, 2, 64, 512*1024, l2_cache_str},
34737c478bd9Sstevel@tonic-gate 	{ 0x7d, 8, 64, 2*1024*1024, sl2_cache_str},
34747c478bd9Sstevel@tonic-gate 	{ 0x7c, 8, 64, 1024*1024, sl2_cache_str},
34757c478bd9Sstevel@tonic-gate 	{ 0x7b, 8, 64, 512*1024, sl2_cache_str},
34767c478bd9Sstevel@tonic-gate 	{ 0x7a, 8, 64, 256*1024, sl2_cache_str},
34777c478bd9Sstevel@tonic-gate 	{ 0x79, 8, 64, 128*1024, sl2_cache_str},
34787c478bd9Sstevel@tonic-gate 	{ 0x78, 8, 64, 1024*1024, l2_cache_str},
3479ae115bc7Smrj 	{ 0x73, 8, 0, 64*1024, itrace_str},
34807c478bd9Sstevel@tonic-gate 	{ 0x72, 8, 0, 32*1024, itrace_str},
34817c478bd9Sstevel@tonic-gate 	{ 0x71, 8, 0, 16*1024, itrace_str},
34827c478bd9Sstevel@tonic-gate 	{ 0x70, 8, 0, 12*1024, itrace_str},
34837c478bd9Sstevel@tonic-gate 	{ 0x68, 4, 64, 32*1024, sl1_dcache_str},
34847c478bd9Sstevel@tonic-gate 	{ 0x67, 4, 64, 16*1024, sl1_dcache_str},
34857c478bd9Sstevel@tonic-gate 	{ 0x66, 4, 64, 8*1024, sl1_dcache_str},
34867c478bd9Sstevel@tonic-gate 	{ 0x60, 8, 64, 16*1024, sl1_dcache_str},
34877c478bd9Sstevel@tonic-gate 	{ 0x5d, 0, 0, 256, dtlb44_str},
34887c478bd9Sstevel@tonic-gate 	{ 0x5c, 0, 0, 128, dtlb44_str},
34897c478bd9Sstevel@tonic-gate 	{ 0x5b, 0, 0, 64, dtlb44_str},
349025dfb062Sksadhukh 	{ 0x5a, 4, 0, 32, dtlb24_str},
3491824e4fecSvd224797 	{ 0x59, 0, 0, 16, dtlb4k_str},
3492824e4fecSvd224797 	{ 0x57, 4, 0, 16, dtlb4k_str},
3493824e4fecSvd224797 	{ 0x56, 4, 0, 16, dtlb4M_str},
349425dfb062Sksadhukh 	{ 0x55, 0, 0, 7, itlb24_str},
34957c478bd9Sstevel@tonic-gate 	{ 0x52, 0, 0, 256, itlb424_str},
34967c478bd9Sstevel@tonic-gate 	{ 0x51, 0, 0, 128, itlb424_str},
34977c478bd9Sstevel@tonic-gate 	{ 0x50, 0, 0, 64, itlb424_str},
3498824e4fecSvd224797 	{ 0x4f, 0, 0, 32, itlb4k_str},
3499824e4fecSvd224797 	{ 0x4e, 24, 64, 6*1024*1024, l2_cache_str},
3500ae115bc7Smrj 	{ 0x4d, 16, 64, 16*1024*1024, l3_cache_str},
3501ae115bc7Smrj 	{ 0x4c, 12, 64, 12*1024*1024, l3_cache_str},
3502ae115bc7Smrj 	{ 0x4b, 16, 64, 8*1024*1024, l3_cache_str},
3503ae115bc7Smrj 	{ 0x4a, 12, 64, 6*1024*1024, l3_cache_str},
3504ae115bc7Smrj 	{ 0x49, 16, 64, 4*1024*1024, l3_cache_str},
3505824e4fecSvd224797 	{ 0x48, 12, 64, 3*1024*1024, l2_cache_str},
3506ae115bc7Smrj 	{ 0x47, 8, 64, 8*1024*1024, l3_cache_str},
3507ae115bc7Smrj 	{ 0x46, 4, 64, 4*1024*1024, l3_cache_str},
35087c478bd9Sstevel@tonic-gate 	{ 0x45, 4, 32, 2*1024*1024, l2_cache_str},
35097c478bd9Sstevel@tonic-gate 	{ 0x44, 4, 32, 1024*1024, l2_cache_str},
35107c478bd9Sstevel@tonic-gate 	{ 0x43, 4, 32, 512*1024, l2_cache_str},
35117c478bd9Sstevel@tonic-gate 	{ 0x42, 4, 32, 256*1024, l2_cache_str},
35127c478bd9Sstevel@tonic-gate 	{ 0x41, 4, 32, 128*1024, l2_cache_str},
3513ae115bc7Smrj 	{ 0x3e, 4, 64, 512*1024, sl2_cache_str},
3514ae115bc7Smrj 	{ 0x3d, 6, 64, 384*1024, sl2_cache_str},
35157c478bd9Sstevel@tonic-gate 	{ 0x3c, 4, 64, 256*1024, sl2_cache_str},
35167c478bd9Sstevel@tonic-gate 	{ 0x3b, 2, 64, 128*1024, sl2_cache_str},
3517ae115bc7Smrj 	{ 0x3a, 6, 64, 192*1024, sl2_cache_str},
35187c478bd9Sstevel@tonic-gate 	{ 0x39, 4, 64, 128*1024, sl2_cache_str},
35197c478bd9Sstevel@tonic-gate 	{ 0x30, 8, 64, 32*1024, l1_icache_str},
35207c478bd9Sstevel@tonic-gate 	{ 0x2c, 8, 64, 32*1024, l1_dcache_str},
35217c478bd9Sstevel@tonic-gate 	{ 0x29, 8, 64, 4096*1024, sl3_cache_str},
35227c478bd9Sstevel@tonic-gate 	{ 0x25, 8, 64, 2048*1024, sl3_cache_str},
35237c478bd9Sstevel@tonic-gate 	{ 0x23, 8, 64, 1024*1024, sl3_cache_str},
35247c478bd9Sstevel@tonic-gate 	{ 0x22, 4, 64, 512*1024, sl3_cache_str},
3525824e4fecSvd224797 	{ 0x0e, 6, 64, 24*1024, l1_dcache_str},
352625dfb062Sksadhukh 	{ 0x0d, 4, 32, 16*1024, l1_dcache_str},
35277c478bd9Sstevel@tonic-gate 	{ 0x0c, 4, 32, 16*1024, l1_dcache_str},
3528ae115bc7Smrj 	{ 0x0b, 4, 0, 4, itlb4M_str},
35297c478bd9Sstevel@tonic-gate 	{ 0x0a, 2, 32, 8*1024, l1_dcache_str},
35307c478bd9Sstevel@tonic-gate 	{ 0x08, 4, 32, 16*1024, l1_icache_str},
35317c478bd9Sstevel@tonic-gate 	{ 0x06, 4, 32, 8*1024, l1_icache_str},
3532824e4fecSvd224797 	{ 0x05, 4, 0, 32, dtlb4M_str},
35337c478bd9Sstevel@tonic-gate 	{ 0x04, 4, 0, 8, dtlb4M_str},
35347c478bd9Sstevel@tonic-gate 	{ 0x03, 4, 0, 64, dtlb4k_str},
35357c478bd9Sstevel@tonic-gate 	{ 0x02, 4, 0, 2, itlb4M_str},
35367c478bd9Sstevel@tonic-gate 	{ 0x01, 4, 0, 32, itlb4k_str},
35377c478bd9Sstevel@tonic-gate 	{ 0 }
35387c478bd9Sstevel@tonic-gate };
35397c478bd9Sstevel@tonic-gate 
35407c478bd9Sstevel@tonic-gate static const struct cachetab cyrix_ctab[] = {
35417c478bd9Sstevel@tonic-gate 	{ 0x70, 4, 0, 32, "tlb-4K" },
35427c478bd9Sstevel@tonic-gate 	{ 0x80, 4, 16, 16*1024, "l1-cache" },
35437c478bd9Sstevel@tonic-gate 	{ 0 }
35447c478bd9Sstevel@tonic-gate };
35457c478bd9Sstevel@tonic-gate 
35467c478bd9Sstevel@tonic-gate /*
35477c478bd9Sstevel@tonic-gate  * Search a cache table for a matching entry
35487c478bd9Sstevel@tonic-gate  */
35497c478bd9Sstevel@tonic-gate static const struct cachetab *
35507c478bd9Sstevel@tonic-gate find_cacheent(const struct cachetab *ct, uint_t code)
35517c478bd9Sstevel@tonic-gate {
35527c478bd9Sstevel@tonic-gate 	if (code != 0) {
35537c478bd9Sstevel@tonic-gate 		for (; ct->ct_code != 0; ct++)
35547c478bd9Sstevel@tonic-gate 			if (ct->ct_code <= code)
35557c478bd9Sstevel@tonic-gate 				break;
35567c478bd9Sstevel@tonic-gate 		if (ct->ct_code == code)
35577c478bd9Sstevel@tonic-gate 			return (ct);
35587c478bd9Sstevel@tonic-gate 	}
35597c478bd9Sstevel@tonic-gate 	return (NULL);
35607c478bd9Sstevel@tonic-gate }
35617c478bd9Sstevel@tonic-gate 
35627c478bd9Sstevel@tonic-gate /*
35637dee861bSksadhukh  * Populate cachetab entry with L2 or L3 cache-information using
35647dee861bSksadhukh  * cpuid function 4. This function is called from intel_walk_cacheinfo()
35657dee861bSksadhukh  * when descriptor 0x49 is encountered. It returns 0 if no such cache
35667dee861bSksadhukh  * information is found.
35677dee861bSksadhukh  */
35687dee861bSksadhukh static int
35697dee861bSksadhukh intel_cpuid_4_cache_info(struct cachetab *ct, struct cpuid_info *cpi)
35707dee861bSksadhukh {
35717dee861bSksadhukh 	uint32_t level, i;
35727dee861bSksadhukh 	int ret = 0;
35737dee861bSksadhukh 
35747dee861bSksadhukh 	for (i = 0; i < cpi->cpi_std_4_size; i++) {
35757dee861bSksadhukh 		level = CPI_CACHE_LVL(cpi->cpi_std_4[i]);
35767dee861bSksadhukh 
35777dee861bSksadhukh 		if (level == 2 || level == 3) {
35787dee861bSksadhukh 			ct->ct_assoc = CPI_CACHE_WAYS(cpi->cpi_std_4[i]) + 1;
35797dee861bSksadhukh 			ct->ct_line_size =
35807dee861bSksadhukh 			    CPI_CACHE_COH_LN_SZ(cpi->cpi_std_4[i]) + 1;
35817dee861bSksadhukh 			ct->ct_size = ct->ct_assoc *
35827dee861bSksadhukh 			    (CPI_CACHE_PARTS(cpi->cpi_std_4[i]) + 1) *
35837dee861bSksadhukh 			    ct->ct_line_size *
35847dee861bSksadhukh 			    (cpi->cpi_std_4[i]->cp_ecx + 1);
35857dee861bSksadhukh 
35867dee861bSksadhukh 			if (level == 2) {
35877dee861bSksadhukh 				ct->ct_label = l2_cache_str;
35887dee861bSksadhukh 			} else if (level == 3) {
35897dee861bSksadhukh 				ct->ct_label = l3_cache_str;
35907dee861bSksadhukh 			}
35917dee861bSksadhukh 			ret = 1;
35927dee861bSksadhukh 		}
35937dee861bSksadhukh 	}
35947dee861bSksadhukh 
35957dee861bSksadhukh 	return (ret);
35967dee861bSksadhukh }
35977dee861bSksadhukh 
35987dee861bSksadhukh /*
35997c478bd9Sstevel@tonic-gate  * Walk the cacheinfo descriptor, applying 'func' to every valid element
36007c478bd9Sstevel@tonic-gate  * The walk is terminated if the walker returns non-zero.
36017c478bd9Sstevel@tonic-gate  */
36027c478bd9Sstevel@tonic-gate static void
36037c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(struct cpuid_info *cpi,
36047c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
36057c478bd9Sstevel@tonic-gate {
36067c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
3607824e4fecSvd224797 	struct cachetab des_49_ct, des_b1_ct;
36087c478bd9Sstevel@tonic-gate 	uint8_t *dp;
36097c478bd9Sstevel@tonic-gate 	int i;
36107c478bd9Sstevel@tonic-gate 
36117c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
36127c478bd9Sstevel@tonic-gate 		return;
3613f1d742a9Sksadhukh 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
3614f1d742a9Sksadhukh 		/*
3615f1d742a9Sksadhukh 		 * For overloaded descriptor 0x49 we use cpuid function 4
36167dee861bSksadhukh 		 * if supported by the current processor, to create
3617f1d742a9Sksadhukh 		 * cache information.
3618824e4fecSvd224797 		 * For overloaded descriptor 0xb1 we use X86_PAE flag
3619824e4fecSvd224797 		 * to disambiguate the cache information.
3620f1d742a9Sksadhukh 		 */
36217dee861bSksadhukh 		if (*dp == 0x49 && cpi->cpi_maxeax >= 0x4 &&
36227dee861bSksadhukh 		    intel_cpuid_4_cache_info(&des_49_ct, cpi) == 1) {
36237dee861bSksadhukh 				ct = &des_49_ct;
3624824e4fecSvd224797 		} else if (*dp == 0xb1) {
3625824e4fecSvd224797 			des_b1_ct.ct_code = 0xb1;
3626824e4fecSvd224797 			des_b1_ct.ct_assoc = 4;
3627824e4fecSvd224797 			des_b1_ct.ct_line_size = 0;
36287417cfdeSKuriakose Kuruvilla 			if (is_x86_feature(x86_featureset, X86FSET_PAE)) {
3629824e4fecSvd224797 				des_b1_ct.ct_size = 8;
3630824e4fecSvd224797 				des_b1_ct.ct_label = itlb2M_str;
3631824e4fecSvd224797 			} else {
3632824e4fecSvd224797 				des_b1_ct.ct_size = 4;
3633824e4fecSvd224797 				des_b1_ct.ct_label = itlb4M_str;
3634824e4fecSvd224797 			}
3635824e4fecSvd224797 			ct = &des_b1_ct;
36367dee861bSksadhukh 		} else {
36377dee861bSksadhukh 			if ((ct = find_cacheent(intel_ctab, *dp)) == NULL) {
3638f1d742a9Sksadhukh 				continue;
3639f1d742a9Sksadhukh 			}
36407dee861bSksadhukh 		}
3641f1d742a9Sksadhukh 
36427dee861bSksadhukh 		if (func(arg, ct) != 0) {
36437c478bd9Sstevel@tonic-gate 			break;
36447c478bd9Sstevel@tonic-gate 		}
36457c478bd9Sstevel@tonic-gate 	}
3646f1d742a9Sksadhukh }
36477c478bd9Sstevel@tonic-gate 
36487c478bd9Sstevel@tonic-gate /*
36497c478bd9Sstevel@tonic-gate  * (Like the Intel one, except for Cyrix CPUs)
36507c478bd9Sstevel@tonic-gate  */
36517c478bd9Sstevel@tonic-gate static void
36527c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(struct cpuid_info *cpi,
36537c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
36547c478bd9Sstevel@tonic-gate {
36557c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
36567c478bd9Sstevel@tonic-gate 	uint8_t *dp;
36577c478bd9Sstevel@tonic-gate 	int i;
36587c478bd9Sstevel@tonic-gate 
36597c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
36607c478bd9Sstevel@tonic-gate 		return;
36617c478bd9Sstevel@tonic-gate 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
36627c478bd9Sstevel@tonic-gate 		/*
36637c478bd9Sstevel@tonic-gate 		 * Search Cyrix-specific descriptor table first ..
36647c478bd9Sstevel@tonic-gate 		 */
36657c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(cyrix_ctab, *dp)) != NULL) {
36667c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
36677c478bd9Sstevel@tonic-gate 				break;
36687c478bd9Sstevel@tonic-gate 			continue;
36697c478bd9Sstevel@tonic-gate 		}
36707c478bd9Sstevel@tonic-gate 		/*
36717c478bd9Sstevel@tonic-gate 		 * .. else fall back to the Intel one
36727c478bd9Sstevel@tonic-gate 		 */
36737c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(intel_ctab, *dp)) != NULL) {
36747c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
36757c478bd9Sstevel@tonic-gate 				break;
36767c478bd9Sstevel@tonic-gate 			continue;
36777c478bd9Sstevel@tonic-gate 		}
36787c478bd9Sstevel@tonic-gate 	}
36797c478bd9Sstevel@tonic-gate }
36807c478bd9Sstevel@tonic-gate 
36817c478bd9Sstevel@tonic-gate /*
36827c478bd9Sstevel@tonic-gate  * A cacheinfo walker that adds associativity, line-size, and size properties
36837c478bd9Sstevel@tonic-gate  * to the devinfo node it is passed as an argument.
36847c478bd9Sstevel@tonic-gate  */
36857c478bd9Sstevel@tonic-gate static int
36867c478bd9Sstevel@tonic-gate add_cacheent_props(void *arg, const struct cachetab *ct)
36877c478bd9Sstevel@tonic-gate {
36887c478bd9Sstevel@tonic-gate 	dev_info_t *devi = arg;
36897c478bd9Sstevel@tonic-gate 
36907c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, assoc_str, ct->ct_assoc);
36917c478bd9Sstevel@tonic-gate 	if (ct->ct_line_size != 0)
36927c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, ct->ct_label, line_str,
36937c478bd9Sstevel@tonic-gate 		    ct->ct_line_size);
36947c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, size_str, ct->ct_size);
36957c478bd9Sstevel@tonic-gate 	return (0);
36967c478bd9Sstevel@tonic-gate }
36977c478bd9Sstevel@tonic-gate 
3698f1d742a9Sksadhukh 
36997c478bd9Sstevel@tonic-gate static const char fully_assoc[] = "fully-associative?";
37007c478bd9Sstevel@tonic-gate 
37017c478bd9Sstevel@tonic-gate /*
37027c478bd9Sstevel@tonic-gate  * AMD style cache/tlb description
37037c478bd9Sstevel@tonic-gate  *
37047c478bd9Sstevel@tonic-gate  * Extended functions 5 and 6 directly describe properties of
37057c478bd9Sstevel@tonic-gate  * tlbs and various cache levels.
37067c478bd9Sstevel@tonic-gate  */
37077c478bd9Sstevel@tonic-gate static void
37087c478bd9Sstevel@tonic-gate add_amd_assoc(dev_info_t *devi, const char *label, uint_t assoc)
37097c478bd9Sstevel@tonic-gate {
37107c478bd9Sstevel@tonic-gate 	switch (assoc) {
37117c478bd9Sstevel@tonic-gate 	case 0:	/* reserved; ignore */
37127c478bd9Sstevel@tonic-gate 		break;
37137c478bd9Sstevel@tonic-gate 	default:
37147c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
37157c478bd9Sstevel@tonic-gate 		break;
37167c478bd9Sstevel@tonic-gate 	case 0xff:
37177c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
37187c478bd9Sstevel@tonic-gate 		break;
37197c478bd9Sstevel@tonic-gate 	}
37207c478bd9Sstevel@tonic-gate }
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate static void
37237c478bd9Sstevel@tonic-gate add_amd_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
37247c478bd9Sstevel@tonic-gate {
37257c478bd9Sstevel@tonic-gate 	if (size == 0)
37267c478bd9Sstevel@tonic-gate 		return;
37277c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
37287c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
37297c478bd9Sstevel@tonic-gate }
37307c478bd9Sstevel@tonic-gate 
37317c478bd9Sstevel@tonic-gate static void
37327c478bd9Sstevel@tonic-gate add_amd_cache(dev_info_t *devi, const char *label,
37337c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
37347c478bd9Sstevel@tonic-gate {
37357c478bd9Sstevel@tonic-gate 	if (size == 0 || line_size == 0)
37367c478bd9Sstevel@tonic-gate 		return;
37377c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
37387c478bd9Sstevel@tonic-gate 	/*
37397c478bd9Sstevel@tonic-gate 	 * Most AMD parts have a sectored cache. Multiple cache lines are
37407c478bd9Sstevel@tonic-gate 	 * associated with each tag. A sector consists of all cache lines
37417c478bd9Sstevel@tonic-gate 	 * associated with a tag. For example, the AMD K6-III has a sector
37427c478bd9Sstevel@tonic-gate 	 * size of 2 cache lines per tag.
37437c478bd9Sstevel@tonic-gate 	 */
37447c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
37457c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
37467c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
37477c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
37487c478bd9Sstevel@tonic-gate }
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate static void
37517c478bd9Sstevel@tonic-gate add_amd_l2_assoc(dev_info_t *devi, const char *label, uint_t assoc)
37527c478bd9Sstevel@tonic-gate {
37537c478bd9Sstevel@tonic-gate 	switch (assoc) {
37547c478bd9Sstevel@tonic-gate 	case 0:	/* off */
37557c478bd9Sstevel@tonic-gate 		break;
37567c478bd9Sstevel@tonic-gate 	case 1:
37577c478bd9Sstevel@tonic-gate 	case 2:
37587c478bd9Sstevel@tonic-gate 	case 4:
37597c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
37607c478bd9Sstevel@tonic-gate 		break;
37617c478bd9Sstevel@tonic-gate 	case 6:
37627c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 8);
37637c478bd9Sstevel@tonic-gate 		break;
37647c478bd9Sstevel@tonic-gate 	case 8:
37657c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 16);
37667c478bd9Sstevel@tonic-gate 		break;
37677c478bd9Sstevel@tonic-gate 	case 0xf:
37687c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
37697c478bd9Sstevel@tonic-gate 		break;
37707c478bd9Sstevel@tonic-gate 	default: /* reserved; ignore */
37717c478bd9Sstevel@tonic-gate 		break;
37727c478bd9Sstevel@tonic-gate 	}
37737c478bd9Sstevel@tonic-gate }
37747c478bd9Sstevel@tonic-gate 
37757c478bd9Sstevel@tonic-gate static void
37767c478bd9Sstevel@tonic-gate add_amd_l2_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
37777c478bd9Sstevel@tonic-gate {
37787c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0)
37797c478bd9Sstevel@tonic-gate 		return;
37807c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
37817c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
37827c478bd9Sstevel@tonic-gate }
37837c478bd9Sstevel@tonic-gate 
37847c478bd9Sstevel@tonic-gate static void
37857c478bd9Sstevel@tonic-gate add_amd_l2_cache(dev_info_t *devi, const char *label,
37867c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
37877c478bd9Sstevel@tonic-gate {
37887c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0 || line_size == 0)
37897c478bd9Sstevel@tonic-gate 		return;
37907c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
37917c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
37927c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
37937c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
37947c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
37957c478bd9Sstevel@tonic-gate }
37967c478bd9Sstevel@tonic-gate 
37977c478bd9Sstevel@tonic-gate static void
37987c478bd9Sstevel@tonic-gate amd_cache_info(struct cpuid_info *cpi, dev_info_t *devi)
37997c478bd9Sstevel@tonic-gate {
38008949bcd6Sandrei 	struct cpuid_regs *cp;
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000005)
38037c478bd9Sstevel@tonic-gate 		return;
38047c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[5];
38057c478bd9Sstevel@tonic-gate 
38067c478bd9Sstevel@tonic-gate 	/*
38077c478bd9Sstevel@tonic-gate 	 * 4M/2M L1 TLB configuration
38087c478bd9Sstevel@tonic-gate 	 *
38097c478bd9Sstevel@tonic-gate 	 * We report the size for 2M pages because AMD uses two
38107c478bd9Sstevel@tonic-gate 	 * TLB entries for one 4M page.
38117c478bd9Sstevel@tonic-gate 	 */
38127c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "dtlb-2M",
38137c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 31, 24), BITX(cp->cp_eax, 23, 16));
38147c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "itlb-2M",
38157c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 15, 8), BITX(cp->cp_eax, 7, 0));
38167c478bd9Sstevel@tonic-gate 
38177c478bd9Sstevel@tonic-gate 	/*
38187c478bd9Sstevel@tonic-gate 	 * 4K L1 TLB configuration
38197c478bd9Sstevel@tonic-gate 	 */
38207c478bd9Sstevel@tonic-gate 
38217c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
38227c478bd9Sstevel@tonic-gate 		uint_t nentries;
38237c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
38247c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5) {
38257c478bd9Sstevel@tonic-gate 			/*
38267c478bd9Sstevel@tonic-gate 			 * Crusoe processors have 256 TLB entries, but
38277c478bd9Sstevel@tonic-gate 			 * cpuid data format constrains them to only
38287c478bd9Sstevel@tonic-gate 			 * reporting 255 of them.
38297c478bd9Sstevel@tonic-gate 			 */
38307c478bd9Sstevel@tonic-gate 			if ((nentries = BITX(cp->cp_ebx, 23, 16)) == 255)
38317c478bd9Sstevel@tonic-gate 				nentries = 256;
38327c478bd9Sstevel@tonic-gate 			/*
38337c478bd9Sstevel@tonic-gate 			 * Crusoe processors also have a unified TLB
38347c478bd9Sstevel@tonic-gate 			 */
38357c478bd9Sstevel@tonic-gate 			add_amd_tlb(devi, "tlb-4K", BITX(cp->cp_ebx, 31, 24),
38367c478bd9Sstevel@tonic-gate 			    nentries);
38377c478bd9Sstevel@tonic-gate 			break;
38387c478bd9Sstevel@tonic-gate 		}
38397c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
38407c478bd9Sstevel@tonic-gate 	default:
38417c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, itlb4k_str,
38427c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 31, 24), BITX(cp->cp_ebx, 23, 16));
38437c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, dtlb4k_str,
38447c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 15, 8), BITX(cp->cp_ebx, 7, 0));
38457c478bd9Sstevel@tonic-gate 		break;
38467c478bd9Sstevel@tonic-gate 	}
38477c478bd9Sstevel@tonic-gate 
38487c478bd9Sstevel@tonic-gate 	/*
38497c478bd9Sstevel@tonic-gate 	 * data L1 cache configuration
38507c478bd9Sstevel@tonic-gate 	 */
38517c478bd9Sstevel@tonic-gate 
38527c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_dcache_str,
38537c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 24), BITX(cp->cp_ecx, 23, 16),
38547c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 15, 8), BITX(cp->cp_ecx, 7, 0));
38557c478bd9Sstevel@tonic-gate 
38567c478bd9Sstevel@tonic-gate 	/*
38577c478bd9Sstevel@tonic-gate 	 * code L1 cache configuration
38587c478bd9Sstevel@tonic-gate 	 */
38597c478bd9Sstevel@tonic-gate 
38607c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_icache_str,
38617c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 31, 24), BITX(cp->cp_edx, 23, 16),
38627c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 15, 8), BITX(cp->cp_edx, 7, 0));
38637c478bd9Sstevel@tonic-gate 
38647c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
38657c478bd9Sstevel@tonic-gate 		return;
38667c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
38677c478bd9Sstevel@tonic-gate 
38687c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for large pages */
38697c478bd9Sstevel@tonic-gate 
38707c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_eax, 31, 16) == 0)
38717c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-2M",
38727c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
38737c478bd9Sstevel@tonic-gate 	else {
38747c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-2M",
38757c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
38767c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-2M",
38777c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
38787c478bd9Sstevel@tonic-gate 	}
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for 4K pages */
38817c478bd9Sstevel@tonic-gate 
38827c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_ebx, 31, 16) == 0) {
38837c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-4K",
38847c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
38857c478bd9Sstevel@tonic-gate 	} else {
38867c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-4K",
38877c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
38887c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-4K",
38897c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
38907c478bd9Sstevel@tonic-gate 	}
38917c478bd9Sstevel@tonic-gate 
38927c478bd9Sstevel@tonic-gate 	add_amd_l2_cache(devi, l2_cache_str,
38937c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 16), BITX(cp->cp_ecx, 15, 12),
38947c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 11, 8), BITX(cp->cp_ecx, 7, 0));
38957c478bd9Sstevel@tonic-gate }
38967c478bd9Sstevel@tonic-gate 
38977c478bd9Sstevel@tonic-gate /*
38987c478bd9Sstevel@tonic-gate  * There are two basic ways that the x86 world describes it cache
38997c478bd9Sstevel@tonic-gate  * and tlb architecture - Intel's way and AMD's way.
39007c478bd9Sstevel@tonic-gate  *
39017c478bd9Sstevel@tonic-gate  * Return which flavor of cache architecture we should use
39027c478bd9Sstevel@tonic-gate  */
39037c478bd9Sstevel@tonic-gate static int
39047c478bd9Sstevel@tonic-gate x86_which_cacheinfo(struct cpuid_info *cpi)
39057c478bd9Sstevel@tonic-gate {
39067c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
39077c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
39087c478bd9Sstevel@tonic-gate 		if (cpi->cpi_maxeax >= 2)
39097c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
39107c478bd9Sstevel@tonic-gate 		break;
39117c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
39127c478bd9Sstevel@tonic-gate 		/*
39137c478bd9Sstevel@tonic-gate 		 * The K5 model 1 was the first part from AMD that reported
39147c478bd9Sstevel@tonic-gate 		 * cache sizes via extended cpuid functions.
39157c478bd9Sstevel@tonic-gate 		 */
39167c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
39177c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
39187c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
39197c478bd9Sstevel@tonic-gate 		break;
39207c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
39217c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5)
39227c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
39237c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
39247c478bd9Sstevel@tonic-gate 	default:
39257c478bd9Sstevel@tonic-gate 		/*
39267c478bd9Sstevel@tonic-gate 		 * If they have extended CPU data for 0x80000005
39277c478bd9Sstevel@tonic-gate 		 * then we assume they have AMD-format cache
39287c478bd9Sstevel@tonic-gate 		 * information.
39297c478bd9Sstevel@tonic-gate 		 *
39307c478bd9Sstevel@tonic-gate 		 * If not, and the vendor happens to be Cyrix,
39317c478bd9Sstevel@tonic-gate 		 * then try our-Cyrix specific handler.
39327c478bd9Sstevel@tonic-gate 		 *
39337c478bd9Sstevel@tonic-gate 		 * If we're not Cyrix, then assume we're using Intel's
39347c478bd9Sstevel@tonic-gate 		 * table-driven format instead.
39357c478bd9Sstevel@tonic-gate 		 */
39367c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax >= 0x80000005)
39377c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
39387c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_vendor == X86_VENDOR_Cyrix)
39397c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Cyrix);
39407c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_maxeax >= 2)
39417c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
39427c478bd9Sstevel@tonic-gate 		break;
39437c478bd9Sstevel@tonic-gate 	}
39447c478bd9Sstevel@tonic-gate 	return (-1);
39457c478bd9Sstevel@tonic-gate }
39467c478bd9Sstevel@tonic-gate 
39477c478bd9Sstevel@tonic-gate void
3948fa96bd91SMichael Corcoran cpuid_set_cpu_properties(void *dip, processorid_t cpu_id,
3949fa96bd91SMichael Corcoran     struct cpuid_info *cpi)
39507c478bd9Sstevel@tonic-gate {
39517c478bd9Sstevel@tonic-gate 	dev_info_t *cpu_devi;
39527c478bd9Sstevel@tonic-gate 	int create;
39537c478bd9Sstevel@tonic-gate 
3954fa96bd91SMichael Corcoran 	cpu_devi = (dev_info_t *)dip;
39557c478bd9Sstevel@tonic-gate 
39567c478bd9Sstevel@tonic-gate 	/* device_type */
39577c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
39587c478bd9Sstevel@tonic-gate 	    "device_type", "cpu");
39597c478bd9Sstevel@tonic-gate 
39607c478bd9Sstevel@tonic-gate 	/* reg */
39617c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39627c478bd9Sstevel@tonic-gate 	    "reg", cpu_id);
39637c478bd9Sstevel@tonic-gate 
39647c478bd9Sstevel@tonic-gate 	/* cpu-mhz, and clock-frequency */
39657c478bd9Sstevel@tonic-gate 	if (cpu_freq > 0) {
39667c478bd9Sstevel@tonic-gate 		long long mul;
39677c478bd9Sstevel@tonic-gate 
39687c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39697c478bd9Sstevel@tonic-gate 		    "cpu-mhz", cpu_freq);
39707c478bd9Sstevel@tonic-gate 		if ((mul = cpu_freq * 1000000LL) <= INT_MAX)
39717c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39727c478bd9Sstevel@tonic-gate 			    "clock-frequency", (int)mul);
39737c478bd9Sstevel@tonic-gate 	}
39747c478bd9Sstevel@tonic-gate 
39757417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) {
39767c478bd9Sstevel@tonic-gate 		return;
39777c478bd9Sstevel@tonic-gate 	}
39787c478bd9Sstevel@tonic-gate 
39797c478bd9Sstevel@tonic-gate 	/* vendor-id */
39807c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
39817c478bd9Sstevel@tonic-gate 	    "vendor-id", cpi->cpi_vendorstr);
39827c478bd9Sstevel@tonic-gate 
39837c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax == 0) {
39847c478bd9Sstevel@tonic-gate 		return;
39857c478bd9Sstevel@tonic-gate 	}
39867c478bd9Sstevel@tonic-gate 
39877c478bd9Sstevel@tonic-gate 	/*
39887c478bd9Sstevel@tonic-gate 	 * family, model, and step
39897c478bd9Sstevel@tonic-gate 	 */
39907c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39917c478bd9Sstevel@tonic-gate 	    "family", CPI_FAMILY(cpi));
39927c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39937c478bd9Sstevel@tonic-gate 	    "cpu-model", CPI_MODEL(cpi));
39947c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
39957c478bd9Sstevel@tonic-gate 	    "stepping-id", CPI_STEP(cpi));
39967c478bd9Sstevel@tonic-gate 
39977c478bd9Sstevel@tonic-gate 	/* type */
39987c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
39997c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
40007c478bd9Sstevel@tonic-gate 		create = 1;
40017c478bd9Sstevel@tonic-gate 		break;
40027c478bd9Sstevel@tonic-gate 	default:
40037c478bd9Sstevel@tonic-gate 		create = 0;
40047c478bd9Sstevel@tonic-gate 		break;
40057c478bd9Sstevel@tonic-gate 	}
40067c478bd9Sstevel@tonic-gate 	if (create)
40077c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40087c478bd9Sstevel@tonic-gate 		    "type", CPI_TYPE(cpi));
40097c478bd9Sstevel@tonic-gate 
40107c478bd9Sstevel@tonic-gate 	/* ext-family */
40117c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40127c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
40137c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
40147c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
40157c478bd9Sstevel@tonic-gate 		break;
40167c478bd9Sstevel@tonic-gate 	default:
40177c478bd9Sstevel@tonic-gate 		create = 0;
40187c478bd9Sstevel@tonic-gate 		break;
40197c478bd9Sstevel@tonic-gate 	}
40207c478bd9Sstevel@tonic-gate 	if (create)
40217c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40227c478bd9Sstevel@tonic-gate 		    "ext-family", CPI_FAMILY_XTD(cpi));
40237c478bd9Sstevel@tonic-gate 
40247c478bd9Sstevel@tonic-gate 	/* ext-model */
40257c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40267c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
402763d3f7dfSkk208521 		create = IS_EXTENDED_MODEL_INTEL(cpi);
402868c91426Sdmick 		break;
40297c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
4030ee88d2b9Skchow 		create = CPI_FAMILY(cpi) == 0xf;
40317c478bd9Sstevel@tonic-gate 		break;
40327c478bd9Sstevel@tonic-gate 	default:
40337c478bd9Sstevel@tonic-gate 		create = 0;
40347c478bd9Sstevel@tonic-gate 		break;
40357c478bd9Sstevel@tonic-gate 	}
40367c478bd9Sstevel@tonic-gate 	if (create)
40377c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40387c478bd9Sstevel@tonic-gate 		    "ext-model", CPI_MODEL_XTD(cpi));
40397c478bd9Sstevel@tonic-gate 
40407c478bd9Sstevel@tonic-gate 	/* generation */
40417c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40427c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
40437c478bd9Sstevel@tonic-gate 		/*
40447c478bd9Sstevel@tonic-gate 		 * AMD K5 model 1 was the first part to support this
40457c478bd9Sstevel@tonic-gate 		 */
40467c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
40477c478bd9Sstevel@tonic-gate 		break;
40487c478bd9Sstevel@tonic-gate 	default:
40497c478bd9Sstevel@tonic-gate 		create = 0;
40507c478bd9Sstevel@tonic-gate 		break;
40517c478bd9Sstevel@tonic-gate 	}
40527c478bd9Sstevel@tonic-gate 	if (create)
40537c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40547c478bd9Sstevel@tonic-gate 		    "generation", BITX((cpi)->cpi_extd[1].cp_eax, 11, 8));
40557c478bd9Sstevel@tonic-gate 
40567c478bd9Sstevel@tonic-gate 	/* brand-id */
40577c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40587c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
40597c478bd9Sstevel@tonic-gate 		/*
40607c478bd9Sstevel@tonic-gate 		 * brand id first appeared on Pentium III Xeon model 8,
40617c478bd9Sstevel@tonic-gate 		 * and Celeron model 8 processors and Opteron
40627c478bd9Sstevel@tonic-gate 		 */
40637c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family > 6 ||
40647c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 6 && cpi->cpi_model >= 8);
40657c478bd9Sstevel@tonic-gate 		break;
40667c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
40677c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
40687c478bd9Sstevel@tonic-gate 		break;
40697c478bd9Sstevel@tonic-gate 	default:
40707c478bd9Sstevel@tonic-gate 		create = 0;
40717c478bd9Sstevel@tonic-gate 		break;
40727c478bd9Sstevel@tonic-gate 	}
40737c478bd9Sstevel@tonic-gate 	if (create && cpi->cpi_brandid != 0) {
40747c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40757c478bd9Sstevel@tonic-gate 		    "brand-id", cpi->cpi_brandid);
40767c478bd9Sstevel@tonic-gate 	}
40777c478bd9Sstevel@tonic-gate 
40787c478bd9Sstevel@tonic-gate 	/* chunks, and apic-id */
40797c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40807c478bd9Sstevel@tonic-gate 		/*
40817c478bd9Sstevel@tonic-gate 		 * first available on Pentium IV and Opteron (K8)
40827c478bd9Sstevel@tonic-gate 		 */
40835ff02082Sdmick 	case X86_VENDOR_Intel:
40845ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
40855ff02082Sdmick 		break;
40865ff02082Sdmick 	case X86_VENDOR_AMD:
40877c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
40887c478bd9Sstevel@tonic-gate 		break;
40897c478bd9Sstevel@tonic-gate 	default:
40907c478bd9Sstevel@tonic-gate 		create = 0;
40917c478bd9Sstevel@tonic-gate 		break;
40927c478bd9Sstevel@tonic-gate 	}
40937c478bd9Sstevel@tonic-gate 	if (create) {
40947c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40957c478bd9Sstevel@tonic-gate 		    "chunks", CPI_CHUNKS(cpi));
40967c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
4097b6917abeSmishra 		    "apic-id", cpi->cpi_apicid);
40987aec1d6eScindi 		if (cpi->cpi_chipid >= 0) {
40997c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41007c478bd9Sstevel@tonic-gate 			    "chip#", cpi->cpi_chipid);
41017aec1d6eScindi 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41027aec1d6eScindi 			    "clog#", cpi->cpi_clogid);
41037aec1d6eScindi 		}
41047c478bd9Sstevel@tonic-gate 	}
41057c478bd9Sstevel@tonic-gate 
41067c478bd9Sstevel@tonic-gate 	/* cpuid-features */
41077c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41087c478bd9Sstevel@tonic-gate 	    "cpuid-features", CPI_FEATURES_EDX(cpi));
41097c478bd9Sstevel@tonic-gate 
41107c478bd9Sstevel@tonic-gate 
41117c478bd9Sstevel@tonic-gate 	/* cpuid-features-ecx */
41127c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41137c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41145ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
41157c478bd9Sstevel@tonic-gate 		break;
41167c478bd9Sstevel@tonic-gate 	default:
41177c478bd9Sstevel@tonic-gate 		create = 0;
41187c478bd9Sstevel@tonic-gate 		break;
41197c478bd9Sstevel@tonic-gate 	}
41207c478bd9Sstevel@tonic-gate 	if (create)
41217c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41227c478bd9Sstevel@tonic-gate 		    "cpuid-features-ecx", CPI_FEATURES_ECX(cpi));
41237c478bd9Sstevel@tonic-gate 
41247c478bd9Sstevel@tonic-gate 	/* ext-cpuid-features */
41257c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41265ff02082Sdmick 	case X86_VENDOR_Intel:
41277c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41287c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
41297c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
41307c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
41317c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
41327c478bd9Sstevel@tonic-gate 		break;
41337c478bd9Sstevel@tonic-gate 	default:
41347c478bd9Sstevel@tonic-gate 		create = 0;
41357c478bd9Sstevel@tonic-gate 		break;
41367c478bd9Sstevel@tonic-gate 	}
41375ff02082Sdmick 	if (create) {
41387c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41397c478bd9Sstevel@tonic-gate 		    "ext-cpuid-features", CPI_FEATURES_XTD_EDX(cpi));
41405ff02082Sdmick 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41415ff02082Sdmick 		    "ext-cpuid-features-ecx", CPI_FEATURES_XTD_ECX(cpi));
41425ff02082Sdmick 	}
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate 	/*
41457c478bd9Sstevel@tonic-gate 	 * Brand String first appeared in Intel Pentium IV, AMD K5
41467c478bd9Sstevel@tonic-gate 	 * model 1, and Cyrix GXm.  On earlier models we try and
41477c478bd9Sstevel@tonic-gate 	 * simulate something similar .. so this string should always
41487c478bd9Sstevel@tonic-gate 	 * same -something- about the processor, however lame.
41497c478bd9Sstevel@tonic-gate 	 */
41507c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
41517c478bd9Sstevel@tonic-gate 	    "brand-string", cpi->cpi_brandstr);
41527c478bd9Sstevel@tonic-gate 
41537c478bd9Sstevel@tonic-gate 	/*
41547c478bd9Sstevel@tonic-gate 	 * Finally, cache and tlb information
41557c478bd9Sstevel@tonic-gate 	 */
41567c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
41577c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41587c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
41597c478bd9Sstevel@tonic-gate 		break;
41607c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
41617c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
41627c478bd9Sstevel@tonic-gate 		break;
41637c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41647c478bd9Sstevel@tonic-gate 		amd_cache_info(cpi, cpu_devi);
41657c478bd9Sstevel@tonic-gate 		break;
41667c478bd9Sstevel@tonic-gate 	default:
41677c478bd9Sstevel@tonic-gate 		break;
41687c478bd9Sstevel@tonic-gate 	}
41697c478bd9Sstevel@tonic-gate }
41707c478bd9Sstevel@tonic-gate 
41717c478bd9Sstevel@tonic-gate struct l2info {
41727c478bd9Sstevel@tonic-gate 	int *l2i_csz;
41737c478bd9Sstevel@tonic-gate 	int *l2i_lsz;
41747c478bd9Sstevel@tonic-gate 	int *l2i_assoc;
41757c478bd9Sstevel@tonic-gate 	int l2i_ret;
41767c478bd9Sstevel@tonic-gate };
41777c478bd9Sstevel@tonic-gate 
41787c478bd9Sstevel@tonic-gate /*
41797c478bd9Sstevel@tonic-gate  * A cacheinfo walker that fetches the size, line-size and associativity
41807c478bd9Sstevel@tonic-gate  * of the L2 cache
41817c478bd9Sstevel@tonic-gate  */
41827c478bd9Sstevel@tonic-gate static int
41837c478bd9Sstevel@tonic-gate intel_l2cinfo(void *arg, const struct cachetab *ct)
41847c478bd9Sstevel@tonic-gate {
41857c478bd9Sstevel@tonic-gate 	struct l2info *l2i = arg;
41867c478bd9Sstevel@tonic-gate 	int *ip;
41877c478bd9Sstevel@tonic-gate 
41887c478bd9Sstevel@tonic-gate 	if (ct->ct_label != l2_cache_str &&
41897c478bd9Sstevel@tonic-gate 	    ct->ct_label != sl2_cache_str)
41907c478bd9Sstevel@tonic-gate 		return (0);	/* not an L2 -- keep walking */
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_csz) != NULL)
41937c478bd9Sstevel@tonic-gate 		*ip = ct->ct_size;
41947c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_lsz) != NULL)
41957c478bd9Sstevel@tonic-gate 		*ip = ct->ct_line_size;
41967c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_assoc) != NULL)
41977c478bd9Sstevel@tonic-gate 		*ip = ct->ct_assoc;
41987c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = ct->ct_size;
41997c478bd9Sstevel@tonic-gate 	return (1);		/* was an L2 -- terminate walk */
42007c478bd9Sstevel@tonic-gate }
42017c478bd9Sstevel@tonic-gate 
4202606303c9Skchow /*
4203606303c9Skchow  * AMD L2/L3 Cache and TLB Associativity Field Definition:
4204606303c9Skchow  *
4205606303c9Skchow  *	Unlike the associativity for the L1 cache and tlb where the 8 bit
4206606303c9Skchow  *	value is the associativity, the associativity for the L2 cache and
4207606303c9Skchow  *	tlb is encoded in the following table. The 4 bit L2 value serves as
4208606303c9Skchow  *	an index into the amd_afd[] array to determine the associativity.
4209606303c9Skchow  *	-1 is undefined. 0 is fully associative.
4210606303c9Skchow  */
4211606303c9Skchow 
4212606303c9Skchow static int amd_afd[] =
4213606303c9Skchow 	{-1, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, 0};
4214606303c9Skchow 
42157c478bd9Sstevel@tonic-gate static void
42167c478bd9Sstevel@tonic-gate amd_l2cacheinfo(struct cpuid_info *cpi, struct l2info *l2i)
42177c478bd9Sstevel@tonic-gate {
42188949bcd6Sandrei 	struct cpuid_regs *cp;
42197c478bd9Sstevel@tonic-gate 	uint_t size, assoc;
4220606303c9Skchow 	int i;
42217c478bd9Sstevel@tonic-gate 	int *ip;
42227c478bd9Sstevel@tonic-gate 
42237c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
42247c478bd9Sstevel@tonic-gate 		return;
42257c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
42267c478bd9Sstevel@tonic-gate 
4227606303c9Skchow 	if ((i = BITX(cp->cp_ecx, 15, 12)) != 0 &&
42287c478bd9Sstevel@tonic-gate 	    (size = BITX(cp->cp_ecx, 31, 16)) != 0) {
42297c478bd9Sstevel@tonic-gate 		uint_t cachesz = size * 1024;
4230606303c9Skchow 		assoc = amd_afd[i];
42317c478bd9Sstevel@tonic-gate 
4232606303c9Skchow 		ASSERT(assoc != -1);
42337c478bd9Sstevel@tonic-gate 
42347c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_csz) != NULL)
42357c478bd9Sstevel@tonic-gate 			*ip = cachesz;
42367c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_lsz) != NULL)
42377c478bd9Sstevel@tonic-gate 			*ip = BITX(cp->cp_ecx, 7, 0);
42387c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_assoc) != NULL)
42397c478bd9Sstevel@tonic-gate 			*ip = assoc;
42407c478bd9Sstevel@tonic-gate 		l2i->l2i_ret = cachesz;
42417c478bd9Sstevel@tonic-gate 	}
42427c478bd9Sstevel@tonic-gate }
42437c478bd9Sstevel@tonic-gate 
42447c478bd9Sstevel@tonic-gate int
42457c478bd9Sstevel@tonic-gate getl2cacheinfo(cpu_t *cpu, int *csz, int *lsz, int *assoc)
42467c478bd9Sstevel@tonic-gate {
42477c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
42487c478bd9Sstevel@tonic-gate 	struct l2info __l2info, *l2i = &__l2info;
42497c478bd9Sstevel@tonic-gate 
42507c478bd9Sstevel@tonic-gate 	l2i->l2i_csz = csz;
42517c478bd9Sstevel@tonic-gate 	l2i->l2i_lsz = lsz;
42527c478bd9Sstevel@tonic-gate 	l2i->l2i_assoc = assoc;
42537c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = -1;
42547c478bd9Sstevel@tonic-gate 
42557c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
42567c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
42577c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
42587c478bd9Sstevel@tonic-gate 		break;
42597c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
42607c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
42617c478bd9Sstevel@tonic-gate 		break;
42627c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
42637c478bd9Sstevel@tonic-gate 		amd_l2cacheinfo(cpi, l2i);
42647c478bd9Sstevel@tonic-gate 		break;
42657c478bd9Sstevel@tonic-gate 	default:
42667c478bd9Sstevel@tonic-gate 		break;
42677c478bd9Sstevel@tonic-gate 	}
42687c478bd9Sstevel@tonic-gate 	return (l2i->l2i_ret);
42697c478bd9Sstevel@tonic-gate }
4270f98fbcecSbholler 
4271843e1988Sjohnlev #if !defined(__xpv)
4272843e1988Sjohnlev 
42735b8a6efeSbholler uint32_t *
42745b8a6efeSbholler cpuid_mwait_alloc(cpu_t *cpu)
42755b8a6efeSbholler {
42765b8a6efeSbholler 	uint32_t	*ret;
42775b8a6efeSbholler 	size_t		mwait_size;
42785b8a6efeSbholler 
4279a3114836SGerry Liu 	ASSERT(cpuid_checkpass(CPU, 2));
42805b8a6efeSbholler 
4281a3114836SGerry Liu 	mwait_size = CPU->cpu_m.mcpu_cpi->cpi_mwait.mon_max;
42825b8a6efeSbholler 	if (mwait_size == 0)
42835b8a6efeSbholler 		return (NULL);
42845b8a6efeSbholler 
42855b8a6efeSbholler 	/*
42865b8a6efeSbholler 	 * kmem_alloc() returns cache line size aligned data for mwait_size
42875b8a6efeSbholler 	 * allocations.  mwait_size is currently cache line sized.  Neither
42885b8a6efeSbholler 	 * of these implementation details are guarantied to be true in the
42895b8a6efeSbholler 	 * future.
42905b8a6efeSbholler 	 *
42915b8a6efeSbholler 	 * First try allocating mwait_size as kmem_alloc() currently returns
42925b8a6efeSbholler 	 * correctly aligned memory.  If kmem_alloc() does not return
42935b8a6efeSbholler 	 * mwait_size aligned memory, then use mwait_size ROUNDUP.
42945b8a6efeSbholler 	 *
42955b8a6efeSbholler 	 * Set cpi_mwait.buf_actual and cpi_mwait.size_actual in case we
42965b8a6efeSbholler 	 * decide to free this memory.
42975b8a6efeSbholler 	 */
42985b8a6efeSbholler 	ret = kmem_zalloc(mwait_size, KM_SLEEP);
42995b8a6efeSbholler 	if (ret == (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size)) {
43005b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
43015b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size;
43025b8a6efeSbholler 		*ret = MWAIT_RUNNING;
43035b8a6efeSbholler 		return (ret);
43045b8a6efeSbholler 	} else {
43055b8a6efeSbholler 		kmem_free(ret, mwait_size);
43065b8a6efeSbholler 		ret = kmem_zalloc(mwait_size * 2, KM_SLEEP);
43075b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
43085b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size * 2;
43095b8a6efeSbholler 		ret = (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size);
43105b8a6efeSbholler 		*ret = MWAIT_RUNNING;
43115b8a6efeSbholler 		return (ret);
43125b8a6efeSbholler 	}
43135b8a6efeSbholler }
43145b8a6efeSbholler 
43155b8a6efeSbholler void
43165b8a6efeSbholler cpuid_mwait_free(cpu_t *cpu)
4317f98fbcecSbholler {
4318a3114836SGerry Liu 	if (cpu->cpu_m.mcpu_cpi == NULL) {
4319a3114836SGerry Liu 		return;
4320a3114836SGerry Liu 	}
43215b8a6efeSbholler 
43225b8a6efeSbholler 	if (cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual != NULL &&
43235b8a6efeSbholler 	    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual > 0) {
43245b8a6efeSbholler 		kmem_free(cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual,
43255b8a6efeSbholler 		    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual);
43265b8a6efeSbholler 	}
43275b8a6efeSbholler 
43285b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = NULL;
43295b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = 0;
4330f98fbcecSbholler }
4331843e1988Sjohnlev 
4332247dbb3dSsudheer void
4333247dbb3dSsudheer patch_tsc_read(int flag)
4334247dbb3dSsudheer {
4335247dbb3dSsudheer 	size_t cnt;
4336e4b86885SCheng Sean Ye 
4337247dbb3dSsudheer 	switch (flag) {
4338247dbb3dSsudheer 	case X86_NO_TSC:
4339247dbb3dSsudheer 		cnt = &_no_rdtsc_end - &_no_rdtsc_start;
43402b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt);
4341247dbb3dSsudheer 		break;
4342247dbb3dSsudheer 	case X86_HAVE_TSCP:
4343247dbb3dSsudheer 		cnt = &_tscp_end - &_tscp_start;
43442b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt);
4345247dbb3dSsudheer 		break;
4346247dbb3dSsudheer 	case X86_TSC_MFENCE:
4347247dbb3dSsudheer 		cnt = &_tsc_mfence_end - &_tsc_mfence_start;
43482b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read,
43492b0bcb26Ssudheer 		    (void *)&_tsc_mfence_start, cnt);
4350247dbb3dSsudheer 		break;
435115363b27Ssudheer 	case X86_TSC_LFENCE:
435215363b27Ssudheer 		cnt = &_tsc_lfence_end - &_tsc_lfence_start;
435315363b27Ssudheer 		(void) memcpy((void *)tsc_read,
435415363b27Ssudheer 		    (void *)&_tsc_lfence_start, cnt);
435515363b27Ssudheer 		break;
4356247dbb3dSsudheer 	default:
4357247dbb3dSsudheer 		break;
4358247dbb3dSsudheer 	}
4359247dbb3dSsudheer }
4360247dbb3dSsudheer 
43610e751525SEric Saxe int
43620e751525SEric Saxe cpuid_deep_cstates_supported(void)
43630e751525SEric Saxe {
43640e751525SEric Saxe 	struct cpuid_info *cpi;
43650e751525SEric Saxe 	struct cpuid_regs regs;
43660e751525SEric Saxe 
43670e751525SEric Saxe 	ASSERT(cpuid_checkpass(CPU, 1));
43680e751525SEric Saxe 
43690e751525SEric Saxe 	cpi = CPU->cpu_m.mcpu_cpi;
43700e751525SEric Saxe 
43717417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID))
43720e751525SEric Saxe 		return (0);
43730e751525SEric Saxe 
43740e751525SEric Saxe 	switch (cpi->cpi_vendor) {
43750e751525SEric Saxe 	case X86_VENDOR_Intel:
43760e751525SEric Saxe 		if (cpi->cpi_xmaxeax < 0x80000007)
43770e751525SEric Saxe 			return (0);
43780e751525SEric Saxe 
43790e751525SEric Saxe 		/*
43800e751525SEric Saxe 		 * TSC run at a constant rate in all ACPI C-states?
43810e751525SEric Saxe 		 */
43820e751525SEric Saxe 		regs.cp_eax = 0x80000007;
43830e751525SEric Saxe 		(void) __cpuid_insn(&regs);
43840e751525SEric Saxe 		return (regs.cp_edx & CPUID_TSC_CSTATE_INVARIANCE);
43850e751525SEric Saxe 
43860e751525SEric Saxe 	default:
43870e751525SEric Saxe 		return (0);
43880e751525SEric Saxe 	}
43890e751525SEric Saxe }
43900e751525SEric Saxe 
4391e774b42bSBill Holler #endif	/* !__xpv */
4392e774b42bSBill Holler 
4393e774b42bSBill Holler void
4394e774b42bSBill Holler post_startup_cpu_fixups(void)
4395e774b42bSBill Holler {
4396e774b42bSBill Holler #ifndef __xpv
4397e774b42bSBill Holler 	/*
4398e774b42bSBill Holler 	 * Some AMD processors support C1E state. Entering this state will
4399e774b42bSBill Holler 	 * cause the local APIC timer to stop, which we can't deal with at
4400e774b42bSBill Holler 	 * this time.
4401e774b42bSBill Holler 	 */
4402e774b42bSBill Holler 	if (cpuid_getvendor(CPU) == X86_VENDOR_AMD) {
4403e774b42bSBill Holler 		on_trap_data_t otd;
4404e774b42bSBill Holler 		uint64_t reg;
4405e774b42bSBill Holler 
4406e774b42bSBill Holler 		if (!on_trap(&otd, OT_DATA_ACCESS)) {
4407e774b42bSBill Holler 			reg = rdmsr(MSR_AMD_INT_PENDING_CMP_HALT);
4408e774b42bSBill Holler 			/* Disable C1E state if it is enabled by BIOS */
4409e774b42bSBill Holler 			if ((reg >> AMD_ACTONCMPHALT_SHIFT) &
4410e774b42bSBill Holler 			    AMD_ACTONCMPHALT_MASK) {
4411e774b42bSBill Holler 				reg &= ~(AMD_ACTONCMPHALT_MASK <<
4412e774b42bSBill Holler 				    AMD_ACTONCMPHALT_SHIFT);
4413e774b42bSBill Holler 				wrmsr(MSR_AMD_INT_PENDING_CMP_HALT, reg);
4414e774b42bSBill Holler 			}
4415e774b42bSBill Holler 		}
4416e774b42bSBill Holler 		no_trap();
4417e774b42bSBill Holler 	}
4418e774b42bSBill Holler #endif	/* !__xpv */
4419e774b42bSBill Holler }
4420e774b42bSBill Holler 
4421cef70d2cSBill Holler /*
44227af88ac7SKuriakose Kuruvilla  * Setup necessary registers to enable XSAVE feature on this processor.
44237af88ac7SKuriakose Kuruvilla  * This function needs to be called early enough, so that no xsave/xrstor
44247af88ac7SKuriakose Kuruvilla  * ops will execute on the processor before the MSRs are properly set up.
44257af88ac7SKuriakose Kuruvilla  *
44267af88ac7SKuriakose Kuruvilla  * Current implementation has the following assumption:
44277af88ac7SKuriakose Kuruvilla  * - cpuid_pass1() is done, so that X86 features are known.
44287af88ac7SKuriakose Kuruvilla  * - fpu_probe() is done, so that fp_save_mech is chosen.
44297af88ac7SKuriakose Kuruvilla  */
44307af88ac7SKuriakose Kuruvilla void
44317af88ac7SKuriakose Kuruvilla xsave_setup_msr(cpu_t *cpu)
44327af88ac7SKuriakose Kuruvilla {
44337af88ac7SKuriakose Kuruvilla 	ASSERT(fp_save_mech == FP_XSAVE);
44347af88ac7SKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
44357af88ac7SKuriakose Kuruvilla 
44367af88ac7SKuriakose Kuruvilla 	/* Enable OSXSAVE in CR4. */
44377af88ac7SKuriakose Kuruvilla 	setcr4(getcr4() | CR4_OSXSAVE);
44387af88ac7SKuriakose Kuruvilla 	/*
44397af88ac7SKuriakose Kuruvilla 	 * Update SW copy of ECX, so that /dev/cpu/self/cpuid will report
44407af88ac7SKuriakose Kuruvilla 	 * correct value.
44417af88ac7SKuriakose Kuruvilla 	 */
44427af88ac7SKuriakose Kuruvilla 	cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_ecx |= CPUID_INTC_ECX_OSXSAVE;
44437af88ac7SKuriakose Kuruvilla 	setup_xfem();
44447af88ac7SKuriakose Kuruvilla }
44457af88ac7SKuriakose Kuruvilla 
44467af88ac7SKuriakose Kuruvilla /*
4447cef70d2cSBill Holler  * Starting with the Westmere processor the local
4448cef70d2cSBill Holler  * APIC timer will continue running in all C-states,
4449cef70d2cSBill Holler  * including the deepest C-states.
4450cef70d2cSBill Holler  */
4451cef70d2cSBill Holler int
4452cef70d2cSBill Holler cpuid_arat_supported(void)
4453cef70d2cSBill Holler {
4454cef70d2cSBill Holler 	struct cpuid_info *cpi;
4455cef70d2cSBill Holler 	struct cpuid_regs regs;
4456cef70d2cSBill Holler 
4457cef70d2cSBill Holler 	ASSERT(cpuid_checkpass(CPU, 1));
44587417cfdeSKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
4459cef70d2cSBill Holler 
4460cef70d2cSBill Holler 	cpi = CPU->cpu_m.mcpu_cpi;
4461cef70d2cSBill Holler 
4462cef70d2cSBill Holler 	switch (cpi->cpi_vendor) {
4463cef70d2cSBill Holler 	case X86_VENDOR_Intel:
4464cef70d2cSBill Holler 		/*
4465cef70d2cSBill Holler 		 * Always-running Local APIC Timer is
4466cef70d2cSBill Holler 		 * indicated by CPUID.6.EAX[2].
4467cef70d2cSBill Holler 		 */
4468cef70d2cSBill Holler 		if (cpi->cpi_maxeax >= 6) {
4469cef70d2cSBill Holler 			regs.cp_eax = 6;
4470cef70d2cSBill Holler 			(void) cpuid_insn(NULL, &regs);
4471cef70d2cSBill Holler 			return (regs.cp_eax & CPUID_CSTATE_ARAT);
4472cef70d2cSBill Holler 		} else {
4473cef70d2cSBill Holler 			return (0);
4474cef70d2cSBill Holler 		}
4475cef70d2cSBill Holler 	default:
4476cef70d2cSBill Holler 		return (0);
4477cef70d2cSBill Holler 	}
4478cef70d2cSBill Holler }
4479cef70d2cSBill Holler 
4480f21ed392Saubrey.li@intel.com /*
4481f21ed392Saubrey.li@intel.com  * Check support for Intel ENERGY_PERF_BIAS feature
4482f21ed392Saubrey.li@intel.com  */
4483f21ed392Saubrey.li@intel.com int
4484f21ed392Saubrey.li@intel.com cpuid_iepb_supported(struct cpu *cp)
4485f21ed392Saubrey.li@intel.com {
4486f21ed392Saubrey.li@intel.com 	struct cpuid_info *cpi = cp->cpu_m.mcpu_cpi;
4487f21ed392Saubrey.li@intel.com 	struct cpuid_regs regs;
4488f21ed392Saubrey.li@intel.com 
4489f21ed392Saubrey.li@intel.com 	ASSERT(cpuid_checkpass(cp, 1));
4490f21ed392Saubrey.li@intel.com 
44917417cfdeSKuriakose Kuruvilla 	if (!(is_x86_feature(x86_featureset, X86FSET_CPUID)) ||
44927417cfdeSKuriakose Kuruvilla 	    !(is_x86_feature(x86_featureset, X86FSET_MSR))) {
4493f21ed392Saubrey.li@intel.com 		return (0);
4494f21ed392Saubrey.li@intel.com 	}
4495f21ed392Saubrey.li@intel.com 
4496f21ed392Saubrey.li@intel.com 	/*
4497f21ed392Saubrey.li@intel.com 	 * Intel ENERGY_PERF_BIAS MSR is indicated by
4498f21ed392Saubrey.li@intel.com 	 * capability bit CPUID.6.ECX.3
4499f21ed392Saubrey.li@intel.com 	 */
4500f21ed392Saubrey.li@intel.com 	if ((cpi->cpi_vendor != X86_VENDOR_Intel) || (cpi->cpi_maxeax < 6))
4501f21ed392Saubrey.li@intel.com 		return (0);
4502f21ed392Saubrey.li@intel.com 
4503f21ed392Saubrey.li@intel.com 	regs.cp_eax = 0x6;
4504f21ed392Saubrey.li@intel.com 	(void) cpuid_insn(NULL, &regs);
4505f21ed392Saubrey.li@intel.com 	return (regs.cp_ecx & CPUID_EPB_SUPPORT);
4506f21ed392Saubrey.li@intel.com }
4507f21ed392Saubrey.li@intel.com 
450841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /*
450941afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Check support for TSC deadline timer
451041afdfa7SKrishnendu Sadhukhan - Sun Microsystems  *
451141afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * TSC deadline timer provides a superior software programming
451241afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * model over local APIC timer that eliminates "time drifts".
451341afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Instead of specifying a relative time, software specifies an
451441afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * absolute time as the target at which the processor should
451541afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * generate a timer event.
451641afdfa7SKrishnendu Sadhukhan - Sun Microsystems  */
451741afdfa7SKrishnendu Sadhukhan - Sun Microsystems int
451841afdfa7SKrishnendu Sadhukhan - Sun Microsystems cpuid_deadline_tsc_supported(void)
451941afdfa7SKrishnendu Sadhukhan - Sun Microsystems {
452041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	struct cpuid_info *cpi = CPU->cpu_m.mcpu_cpi;
452141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	struct cpuid_regs regs;
452241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
452341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	ASSERT(cpuid_checkpass(CPU, 1));
452441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
452541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
452641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	switch (cpi->cpi_vendor) {
452741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	case X86_VENDOR_Intel:
452841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		if (cpi->cpi_maxeax >= 1) {
452941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			regs.cp_eax = 1;
453041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			(void) cpuid_insn(NULL, &regs);
453141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			return (regs.cp_ecx & CPUID_DEADLINE_TSC);
453241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		} else {
453341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			return (0);
453441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		}
453541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	default:
453641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		return (0);
453741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	}
453841afdfa7SKrishnendu Sadhukhan - Sun Microsystems }
453941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
454022cc0e45SBill Holler #if defined(__amd64) && !defined(__xpv)
454122cc0e45SBill Holler /*
454222cc0e45SBill Holler  * Patch in versions of bcopy for high performance Intel Nhm processors
454322cc0e45SBill Holler  * and later...
454422cc0e45SBill Holler  */
454522cc0e45SBill Holler void
454622cc0e45SBill Holler patch_memops(uint_t vendor)
454722cc0e45SBill Holler {
454822cc0e45SBill Holler 	size_t cnt, i;
454922cc0e45SBill Holler 	caddr_t to, from;
455022cc0e45SBill Holler 
45517417cfdeSKuriakose Kuruvilla 	if ((vendor == X86_VENDOR_Intel) &&
45527417cfdeSKuriakose Kuruvilla 	    is_x86_feature(x86_featureset, X86FSET_SSE4_2)) {
455322cc0e45SBill Holler 		cnt = &bcopy_patch_end - &bcopy_patch_start;
455422cc0e45SBill Holler 		to = &bcopy_ck_size;
455522cc0e45SBill Holler 		from = &bcopy_patch_start;
455622cc0e45SBill Holler 		for (i = 0; i < cnt; i++) {
455722cc0e45SBill Holler 			*to++ = *from++;
455822cc0e45SBill Holler 		}
455922cc0e45SBill Holler 	}
456022cc0e45SBill Holler }
456122cc0e45SBill Holler #endif  /* __amd64 && !__xpv */
45622d2efdc6SVuong Nguyen 
45632d2efdc6SVuong Nguyen /*
45642d2efdc6SVuong Nguyen  * This function finds the number of bits to represent the number of cores per
45652d2efdc6SVuong Nguyen  * chip and the number of strands per core for the Intel platforms.
45662d2efdc6SVuong Nguyen  * It re-uses the x2APIC cpuid code of the cpuid_pass2().
45672d2efdc6SVuong Nguyen  */
45682d2efdc6SVuong Nguyen void
45692d2efdc6SVuong Nguyen cpuid_get_ext_topo(uint_t vendor, uint_t *core_nbits, uint_t *strand_nbits)
45702d2efdc6SVuong Nguyen {
45712d2efdc6SVuong Nguyen 	struct cpuid_regs regs;
45722d2efdc6SVuong Nguyen 	struct cpuid_regs *cp = &regs;
45732d2efdc6SVuong Nguyen 
45742d2efdc6SVuong Nguyen 	if (vendor != X86_VENDOR_Intel) {
45752d2efdc6SVuong Nguyen 		return;
45762d2efdc6SVuong Nguyen 	}
45772d2efdc6SVuong Nguyen 
45782d2efdc6SVuong Nguyen 	/* if the cpuid level is 0xB, extended topo is available. */
45792d2efdc6SVuong Nguyen 	cp->cp_eax = 0;
45802d2efdc6SVuong Nguyen 	if (__cpuid_insn(cp) >= 0xB) {
45812d2efdc6SVuong Nguyen 
45822d2efdc6SVuong Nguyen 		cp->cp_eax = 0xB;
45832d2efdc6SVuong Nguyen 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
45842d2efdc6SVuong Nguyen 		(void) __cpuid_insn(cp);
45852d2efdc6SVuong Nguyen 
45862d2efdc6SVuong Nguyen 		/*
45872d2efdc6SVuong Nguyen 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
45882d2efdc6SVuong Nguyen 		 * indicates that the extended topology enumeration leaf is
45892d2efdc6SVuong Nguyen 		 * available.
45902d2efdc6SVuong Nguyen 		 */
45912d2efdc6SVuong Nguyen 		if (cp->cp_ebx) {
45922d2efdc6SVuong Nguyen 			uint_t coreid_shift = 0;
45932d2efdc6SVuong Nguyen 			uint_t chipid_shift = 0;
45942d2efdc6SVuong Nguyen 			uint_t i;
45952d2efdc6SVuong Nguyen 			uint_t level;
45962d2efdc6SVuong Nguyen 
45972d2efdc6SVuong Nguyen 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
45982d2efdc6SVuong Nguyen 				cp->cp_eax = 0xB;
45992d2efdc6SVuong Nguyen 				cp->cp_ecx = i;
46002d2efdc6SVuong Nguyen 
46012d2efdc6SVuong Nguyen 				(void) __cpuid_insn(cp);
46022d2efdc6SVuong Nguyen 				level = CPI_CPU_LEVEL_TYPE(cp);
46032d2efdc6SVuong Nguyen 
46042d2efdc6SVuong Nguyen 				if (level == 1) {
46052d2efdc6SVuong Nguyen 					/*
46062d2efdc6SVuong Nguyen 					 * Thread level processor topology
46072d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
46082d2efdc6SVuong Nguyen 					 * to get the coreid.
46092d2efdc6SVuong Nguyen 					 */
46102d2efdc6SVuong Nguyen 					coreid_shift = BITX(cp->cp_eax, 4, 0);
46112d2efdc6SVuong Nguyen 				} else if (level == 2) {
46122d2efdc6SVuong Nguyen 					/*
46132d2efdc6SVuong Nguyen 					 * Core level processor topology
46142d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
46152d2efdc6SVuong Nguyen 					 * to get the chipid.
46162d2efdc6SVuong Nguyen 					 */
46172d2efdc6SVuong Nguyen 					chipid_shift = BITX(cp->cp_eax, 4, 0);
46182d2efdc6SVuong Nguyen 				}
46192d2efdc6SVuong Nguyen 			}
46202d2efdc6SVuong Nguyen 
46212d2efdc6SVuong Nguyen 			if (coreid_shift > 0 && chipid_shift > coreid_shift) {
46222d2efdc6SVuong Nguyen 				*strand_nbits = coreid_shift;
46232d2efdc6SVuong Nguyen 				*core_nbits = chipid_shift - coreid_shift;
46242d2efdc6SVuong Nguyen 			}
46252d2efdc6SVuong Nguyen 		}
46262d2efdc6SVuong Nguyen 	}
46272d2efdc6SVuong Nguyen }
4628