17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ee88d2b9Skchow * Common Development and Distribution License (the "License"). 6ee88d2b9Skchow * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 226e5580c9SFrank Van Der Linden * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 23cfe84b82SMatt Amdur * Copyright (c) 2011 by Delphix. All rights reserved. 2479ec9da8SYuri Pankov * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25*6eedf6a5SJosef 'Jeff' Sipek * Copyright 2014 Josef "Jeff" Sipek <jeffpc@josefsipek.net> 267c478bd9Sstevel@tonic-gate */ 27cef70d2cSBill Holler /* 2841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Copyright (c) 2010, Intel Corporation. 29cef70d2cSBill Holler * All rights reserved. 30cef70d2cSBill Holler */ 318031591dSSrihari Venkatesan /* 328031591dSSrihari Venkatesan * Portions Copyright 2009 Advanced Micro Devices, Inc. 338031591dSSrihari Venkatesan */ 34faa20166SBryan Cantrill /* 35f3390f39SRobert Mustacchi * Copyright (c) 2012, Joyent, Inc. All rights reserved. 36faa20166SBryan Cantrill */ 377c478bd9Sstevel@tonic-gate /* 387c478bd9Sstevel@tonic-gate * Various routines to handle identification 397c478bd9Sstevel@tonic-gate * and classification of x86 processors. 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 447c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h> 457c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 467c478bd9Sstevel@tonic-gate #include <sys/systm.h> 477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 487c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 497c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 507c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 517c478bd9Sstevel@tonic-gate #include <sys/processor.h> 525b8a6efeSbholler #include <sys/sysmacros.h> 53fb2f18f8Sesaxe #include <sys/pg.h> 547c478bd9Sstevel@tonic-gate #include <sys/fp.h> 557c478bd9Sstevel@tonic-gate #include <sys/controlregs.h> 567c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 57dfea898aSKuriakose Kuruvilla #include <sys/auxv_386.h> 587c478bd9Sstevel@tonic-gate #include <sys/memnode.h> 598031591dSSrihari Venkatesan #include <sys/pci_cfgspace.h> 607c478bd9Sstevel@tonic-gate 61e4b86885SCheng Sean Ye #ifdef __xpv 62e4b86885SCheng Sean Ye #include <sys/hypervisor.h> 63e774b42bSBill Holler #else 64e774b42bSBill Holler #include <sys/ontrap.h> 65e4b86885SCheng Sean Ye #endif 66e4b86885SCheng Sean Ye 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * Pass 0 of cpuid feature analysis happens in locore. It contains special code 697c478bd9Sstevel@tonic-gate * to recognize Cyrix processors that are not cpuid-compliant, and to deal with 707c478bd9Sstevel@tonic-gate * them accordingly. For most modern processors, feature detection occurs here 717c478bd9Sstevel@tonic-gate * in pass 1. 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * Pass 1 of cpuid feature analysis happens just at the beginning of mlsetup() 747c478bd9Sstevel@tonic-gate * for the boot CPU and does the basic analysis that the early kernel needs. 757417cfdeSKuriakose Kuruvilla * x86_featureset is set based on the return value of cpuid_pass1() of the boot 767c478bd9Sstevel@tonic-gate * CPU. 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * Pass 1 includes: 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * o Determining vendor/model/family/stepping and setting x86_type and 817c478bd9Sstevel@tonic-gate * x86_vendor accordingly. 827c478bd9Sstevel@tonic-gate * o Processing the feature flags returned by the cpuid instruction while 837c478bd9Sstevel@tonic-gate * applying any workarounds or tricks for the specific processor. 847c478bd9Sstevel@tonic-gate * o Mapping the feature flags into Solaris feature bits (X86_*). 857c478bd9Sstevel@tonic-gate * o Processing extended feature flags if supported by the processor, 867c478bd9Sstevel@tonic-gate * again while applying specific processor knowledge. 877c478bd9Sstevel@tonic-gate * o Determining the CMT characteristics of the system. 887c478bd9Sstevel@tonic-gate * 897c478bd9Sstevel@tonic-gate * Pass 1 is done on non-boot CPUs during their initialization and the results 907c478bd9Sstevel@tonic-gate * are used only as a meager attempt at ensuring that all processors within the 917c478bd9Sstevel@tonic-gate * system support the same features. 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * Pass 2 of cpuid feature analysis happens just at the beginning 947c478bd9Sstevel@tonic-gate * of startup(). It just copies in and corrects the remainder 957c478bd9Sstevel@tonic-gate * of the cpuid data we depend on: standard cpuid functions that we didn't 967c478bd9Sstevel@tonic-gate * need for pass1 feature analysis, and extended cpuid functions beyond the 977c478bd9Sstevel@tonic-gate * simple feature processing done in pass1. 987c478bd9Sstevel@tonic-gate * 997c478bd9Sstevel@tonic-gate * Pass 3 of cpuid analysis is invoked after basic kernel services; in 1007c478bd9Sstevel@tonic-gate * particular kernel memory allocation has been made available. It creates a 1017c478bd9Sstevel@tonic-gate * readable brand string based on the data collected in the first two passes. 1027c478bd9Sstevel@tonic-gate * 1037c478bd9Sstevel@tonic-gate * Pass 4 of cpuid analysis is invoked after post_startup() when all 1047c478bd9Sstevel@tonic-gate * the support infrastructure for various hardware features has been 1057c478bd9Sstevel@tonic-gate * initialized. It determines which processor features will be reported 1067c478bd9Sstevel@tonic-gate * to userland via the aux vector. 1077c478bd9Sstevel@tonic-gate * 1087c478bd9Sstevel@tonic-gate * All passes are executed on all CPUs, but only the boot CPU determines what 1097c478bd9Sstevel@tonic-gate * features the kernel will use. 1107c478bd9Sstevel@tonic-gate * 1117c478bd9Sstevel@tonic-gate * Much of the worst junk in this file is for the support of processors 1127c478bd9Sstevel@tonic-gate * that didn't really implement the cpuid instruction properly. 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * NOTE: The accessor functions (cpuid_get*) are aware of, and ASSERT upon, 1157c478bd9Sstevel@tonic-gate * the pass numbers. Accordingly, changes to the pass code may require changes 1167c478bd9Sstevel@tonic-gate * to the accessor code. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate uint_t x86_vendor = X86_VENDOR_IntelClone; 1207c478bd9Sstevel@tonic-gate uint_t x86_type = X86_TYPE_OTHER; 12186c1f4dcSVikram Hegde uint_t x86_clflush_size = 0; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4046376; 1247c478bd9Sstevel@tonic-gate 125dfea898aSKuriakose Kuruvilla uchar_t x86_featureset[BT_SIZEOFMAP(NUM_X86_FEATURES)]; 1267417cfdeSKuriakose Kuruvilla 127dfea898aSKuriakose Kuruvilla static char *x86_feature_names[NUM_X86_FEATURES] = { 1287417cfdeSKuriakose Kuruvilla "lgpg", 1297417cfdeSKuriakose Kuruvilla "tsc", 1307417cfdeSKuriakose Kuruvilla "msr", 1317417cfdeSKuriakose Kuruvilla "mtrr", 1327417cfdeSKuriakose Kuruvilla "pge", 1337417cfdeSKuriakose Kuruvilla "de", 1347417cfdeSKuriakose Kuruvilla "cmov", 1357417cfdeSKuriakose Kuruvilla "mmx", 1367417cfdeSKuriakose Kuruvilla "mca", 1377417cfdeSKuriakose Kuruvilla "pae", 1387417cfdeSKuriakose Kuruvilla "cv8", 1397417cfdeSKuriakose Kuruvilla "pat", 1407417cfdeSKuriakose Kuruvilla "sep", 1417417cfdeSKuriakose Kuruvilla "sse", 1427417cfdeSKuriakose Kuruvilla "sse2", 1437417cfdeSKuriakose Kuruvilla "htt", 1447417cfdeSKuriakose Kuruvilla "asysc", 1457417cfdeSKuriakose Kuruvilla "nx", 1467417cfdeSKuriakose Kuruvilla "sse3", 1477417cfdeSKuriakose Kuruvilla "cx16", 1487417cfdeSKuriakose Kuruvilla "cmp", 1497417cfdeSKuriakose Kuruvilla "tscp", 1507417cfdeSKuriakose Kuruvilla "mwait", 1517417cfdeSKuriakose Kuruvilla "sse4a", 1527417cfdeSKuriakose Kuruvilla "cpuid", 1537417cfdeSKuriakose Kuruvilla "ssse3", 1547417cfdeSKuriakose Kuruvilla "sse4_1", 1557417cfdeSKuriakose Kuruvilla "sse4_2", 1567417cfdeSKuriakose Kuruvilla "1gpg", 1577417cfdeSKuriakose Kuruvilla "clfsh", 1587417cfdeSKuriakose Kuruvilla "64", 1597417cfdeSKuriakose Kuruvilla "aes", 1607af88ac7SKuriakose Kuruvilla "pclmulqdq", 1617af88ac7SKuriakose Kuruvilla "xsave", 162faa20166SBryan Cantrill "avx", 163faa20166SBryan Cantrill "vmx", 1647660e73fSHans Rosenfeld "svm", 165ebb8ac07SRobert Mustacchi "topoext", 166ebb8ac07SRobert Mustacchi "f16c", 167*6eedf6a5SJosef 'Jeff' Sipek "rdrand", 168*6eedf6a5SJosef 'Jeff' Sipek "x2apic", 169faa20166SBryan Cantrill }; 1707417cfdeSKuriakose Kuruvilla 1717417cfdeSKuriakose Kuruvilla boolean_t 1727417cfdeSKuriakose Kuruvilla is_x86_feature(void *featureset, uint_t feature) 1737417cfdeSKuriakose Kuruvilla { 1747417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1757417cfdeSKuriakose Kuruvilla return (BT_TEST((ulong_t *)featureset, feature)); 1767417cfdeSKuriakose Kuruvilla } 1777417cfdeSKuriakose Kuruvilla 1787417cfdeSKuriakose Kuruvilla void 1797417cfdeSKuriakose Kuruvilla add_x86_feature(void *featureset, uint_t feature) 1807417cfdeSKuriakose Kuruvilla { 1817417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1827417cfdeSKuriakose Kuruvilla BT_SET((ulong_t *)featureset, feature); 1837417cfdeSKuriakose Kuruvilla } 1847417cfdeSKuriakose Kuruvilla 1857417cfdeSKuriakose Kuruvilla void 1867417cfdeSKuriakose Kuruvilla remove_x86_feature(void *featureset, uint_t feature) 1877417cfdeSKuriakose Kuruvilla { 1887417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1897417cfdeSKuriakose Kuruvilla BT_CLEAR((ulong_t *)featureset, feature); 1907417cfdeSKuriakose Kuruvilla } 1917417cfdeSKuriakose Kuruvilla 1927417cfdeSKuriakose Kuruvilla boolean_t 1937417cfdeSKuriakose Kuruvilla compare_x86_featureset(void *setA, void *setB) 1947417cfdeSKuriakose Kuruvilla { 1957417cfdeSKuriakose Kuruvilla /* 1967417cfdeSKuriakose Kuruvilla * We assume that the unused bits of the bitmap are always zero. 1977417cfdeSKuriakose Kuruvilla */ 1987417cfdeSKuriakose Kuruvilla if (memcmp(setA, setB, BT_SIZEOFMAP(NUM_X86_FEATURES)) == 0) { 1997417cfdeSKuriakose Kuruvilla return (B_TRUE); 2007417cfdeSKuriakose Kuruvilla } else { 2017417cfdeSKuriakose Kuruvilla return (B_FALSE); 2027417cfdeSKuriakose Kuruvilla } 2037417cfdeSKuriakose Kuruvilla } 2047417cfdeSKuriakose Kuruvilla 2057417cfdeSKuriakose Kuruvilla void 2067417cfdeSKuriakose Kuruvilla print_x86_featureset(void *featureset) 2077417cfdeSKuriakose Kuruvilla { 2087417cfdeSKuriakose Kuruvilla uint_t i; 2097417cfdeSKuriakose Kuruvilla 2107417cfdeSKuriakose Kuruvilla for (i = 0; i < NUM_X86_FEATURES; i++) { 2117417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, i)) { 2127417cfdeSKuriakose Kuruvilla cmn_err(CE_CONT, "?x86_feature: %s\n", 2137417cfdeSKuriakose Kuruvilla x86_feature_names[i]); 2147417cfdeSKuriakose Kuruvilla } 2157417cfdeSKuriakose Kuruvilla } 2167417cfdeSKuriakose Kuruvilla } 2177417cfdeSKuriakose Kuruvilla 2187af88ac7SKuriakose Kuruvilla static size_t xsave_state_size = 0; 2197af88ac7SKuriakose Kuruvilla uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE); 2207af88ac7SKuriakose Kuruvilla boolean_t xsave_force_disable = B_FALSE; 2217af88ac7SKuriakose Kuruvilla 2227997e108SSurya Prakki /* 22379ec9da8SYuri Pankov * This is set to platform type we are running on. 2247997e108SSurya Prakki */ 225349b53ddSStuart Maybee static int platform_type = -1; 226349b53ddSStuart Maybee 227349b53ddSStuart Maybee #if !defined(__xpv) 228349b53ddSStuart Maybee /* 229349b53ddSStuart Maybee * Variable to patch if hypervisor platform detection needs to be 230349b53ddSStuart Maybee * disabled (e.g. platform_type will always be HW_NATIVE if this is 0). 231349b53ddSStuart Maybee */ 232349b53ddSStuart Maybee int enable_platform_detection = 1; 233349b53ddSStuart Maybee #endif 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 236f98fbcecSbholler * monitor/mwait info. 2375b8a6efeSbholler * 2385b8a6efeSbholler * size_actual and buf_actual are the real address and size allocated to get 2395b8a6efeSbholler * proper mwait_buf alignement. buf_actual and size_actual should be passed 2405b8a6efeSbholler * to kmem_free(). Currently kmem_alloc() and mwait happen to both use 2415b8a6efeSbholler * processor cache-line alignment, but this is not guarantied in the furture. 242f98fbcecSbholler */ 243f98fbcecSbholler struct mwait_info { 244f98fbcecSbholler size_t mon_min; /* min size to avoid missed wakeups */ 245f98fbcecSbholler size_t mon_max; /* size to avoid false wakeups */ 2465b8a6efeSbholler size_t size_actual; /* size actually allocated */ 2475b8a6efeSbholler void *buf_actual; /* memory actually allocated */ 248f98fbcecSbholler uint32_t support; /* processor support of monitor/mwait */ 249f98fbcecSbholler }; 250f98fbcecSbholler 251f98fbcecSbholler /* 2527af88ac7SKuriakose Kuruvilla * xsave/xrestor info. 2537af88ac7SKuriakose Kuruvilla * 2547af88ac7SKuriakose Kuruvilla * This structure contains HW feature bits and size of the xsave save area. 2557af88ac7SKuriakose Kuruvilla * Note: the kernel will use the maximum size required for all hardware 2567af88ac7SKuriakose Kuruvilla * features. It is not optimize for potential memory savings if features at 2577af88ac7SKuriakose Kuruvilla * the end of the save area are not enabled. 2587af88ac7SKuriakose Kuruvilla */ 2597af88ac7SKuriakose Kuruvilla struct xsave_info { 2607af88ac7SKuriakose Kuruvilla uint32_t xsav_hw_features_low; /* Supported HW features */ 2617af88ac7SKuriakose Kuruvilla uint32_t xsav_hw_features_high; /* Supported HW features */ 2627af88ac7SKuriakose Kuruvilla size_t xsav_max_size; /* max size save area for HW features */ 2637af88ac7SKuriakose Kuruvilla size_t ymm_size; /* AVX: size of ymm save area */ 2647af88ac7SKuriakose Kuruvilla size_t ymm_offset; /* AVX: offset for ymm save area */ 2657af88ac7SKuriakose Kuruvilla }; 2667af88ac7SKuriakose Kuruvilla 2677af88ac7SKuriakose Kuruvilla 2687af88ac7SKuriakose Kuruvilla /* 2697c478bd9Sstevel@tonic-gate * These constants determine how many of the elements of the 2707c478bd9Sstevel@tonic-gate * cpuid we cache in the cpuid_info data structure; the 2717c478bd9Sstevel@tonic-gate * remaining elements are accessible via the cpuid instruction. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate #define NMAX_CPI_STD 6 /* eax = 0 .. 5 */ 2757660e73fSHans Rosenfeld #define NMAX_CPI_EXTD 0x1f /* eax = 0x80000000 .. 0x8000001e */ 2768031591dSSrihari Venkatesan 2778031591dSSrihari Venkatesan /* 2788031591dSSrihari Venkatesan * Some terminology needs to be explained: 2798031591dSSrihari Venkatesan * - Socket: Something that can be plugged into a motherboard. 2808031591dSSrihari Venkatesan * - Package: Same as socket 2818031591dSSrihari Venkatesan * - Chip: Same as socket. Note that AMD's documentation uses term "chip" 2828031591dSSrihari Venkatesan * differently: there, chip is the same as processor node (below) 2838031591dSSrihari Venkatesan * - Processor node: Some AMD processors have more than one 2848031591dSSrihari Venkatesan * "subprocessor" embedded in a package. These subprocessors (nodes) 2858031591dSSrihari Venkatesan * are fully-functional processors themselves with cores, caches, 2868031591dSSrihari Venkatesan * memory controllers, PCI configuration spaces. They are connected 2878031591dSSrihari Venkatesan * inside the package with Hypertransport links. On single-node 2888031591dSSrihari Venkatesan * processors, processor node is equivalent to chip/socket/package. 2897660e73fSHans Rosenfeld * - Compute Unit: Some AMD processors pair cores in "compute units" that 2907660e73fSHans Rosenfeld * share the FPU and the I$ and L2 caches. 2918031591dSSrihari Venkatesan */ 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate struct cpuid_info { 2947c478bd9Sstevel@tonic-gate uint_t cpi_pass; /* last pass completed */ 2957c478bd9Sstevel@tonic-gate /* 2967c478bd9Sstevel@tonic-gate * standard function information 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate uint_t cpi_maxeax; /* fn 0: %eax */ 2997c478bd9Sstevel@tonic-gate char cpi_vendorstr[13]; /* fn 0: %ebx:%ecx:%edx */ 3007c478bd9Sstevel@tonic-gate uint_t cpi_vendor; /* enum of cpi_vendorstr */ 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate uint_t cpi_family; /* fn 1: extended family */ 3037c478bd9Sstevel@tonic-gate uint_t cpi_model; /* fn 1: extended model */ 3047c478bd9Sstevel@tonic-gate uint_t cpi_step; /* fn 1: stepping */ 3058031591dSSrihari Venkatesan chipid_t cpi_chipid; /* fn 1: %ebx: Intel: chip # */ 3068031591dSSrihari Venkatesan /* AMD: package/socket # */ 3077c478bd9Sstevel@tonic-gate uint_t cpi_brandid; /* fn 1: %ebx: brand ID */ 3087c478bd9Sstevel@tonic-gate int cpi_clogid; /* fn 1: %ebx: thread # */ 3098949bcd6Sandrei uint_t cpi_ncpu_per_chip; /* fn 1: %ebx: logical cpu count */ 3107c478bd9Sstevel@tonic-gate uint8_t cpi_cacheinfo[16]; /* fn 2: intel-style cache desc */ 3117c478bd9Sstevel@tonic-gate uint_t cpi_ncache; /* fn 2: number of elements */ 312d129bde2Sesaxe uint_t cpi_ncpu_shr_last_cache; /* fn 4: %eax: ncpus sharing cache */ 313d129bde2Sesaxe id_t cpi_last_lvl_cacheid; /* fn 4: %eax: derived cache id */ 314d129bde2Sesaxe uint_t cpi_std_4_size; /* fn 4: number of fn 4 elements */ 315d129bde2Sesaxe struct cpuid_regs **cpi_std_4; /* fn 4: %ecx == 0 .. fn4_size */ 3168949bcd6Sandrei struct cpuid_regs cpi_std[NMAX_CPI_STD]; /* 0 .. 5 */ 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * extended function information 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate uint_t cpi_xmaxeax; /* fn 0x80000000: %eax */ 3217c478bd9Sstevel@tonic-gate char cpi_brandstr[49]; /* fn 0x8000000[234] */ 3227c478bd9Sstevel@tonic-gate uint8_t cpi_pabits; /* fn 0x80000006: %eax */ 3237c478bd9Sstevel@tonic-gate uint8_t cpi_vabits; /* fn 0x80000006: %eax */ 3248031591dSSrihari Venkatesan struct cpuid_regs cpi_extd[NMAX_CPI_EXTD]; /* 0x800000XX */ 3258031591dSSrihari Venkatesan 32610569901Sgavinm id_t cpi_coreid; /* same coreid => strands share core */ 32710569901Sgavinm int cpi_pkgcoreid; /* core number within single package */ 3288949bcd6Sandrei uint_t cpi_ncore_per_chip; /* AMD: fn 0x80000008: %ecx[7-0] */ 3298949bcd6Sandrei /* Intel: fn 4: %eax[31-26] */ 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * supported feature information 3327c478bd9Sstevel@tonic-gate */ 333ae115bc7Smrj uint32_t cpi_support[5]; 3347c478bd9Sstevel@tonic-gate #define STD_EDX_FEATURES 0 3357c478bd9Sstevel@tonic-gate #define AMD_EDX_FEATURES 1 3367c478bd9Sstevel@tonic-gate #define TM_EDX_FEATURES 2 3377c478bd9Sstevel@tonic-gate #define STD_ECX_FEATURES 3 338ae115bc7Smrj #define AMD_ECX_FEATURES 4 3398a40a695Sgavinm /* 3408a40a695Sgavinm * Synthesized information, where known. 3418a40a695Sgavinm */ 3428a40a695Sgavinm uint32_t cpi_chiprev; /* See X86_CHIPREV_* in x86_archext.h */ 3438a40a695Sgavinm const char *cpi_chiprevstr; /* May be NULL if chiprev unknown */ 3448a40a695Sgavinm uint32_t cpi_socket; /* Chip package/socket type */ 345f98fbcecSbholler 346f98fbcecSbholler struct mwait_info cpi_mwait; /* fn 5: monitor/mwait info */ 347b6917abeSmishra uint32_t cpi_apicid; 3488031591dSSrihari Venkatesan uint_t cpi_procnodeid; /* AMD: nodeID on HT, Intel: chipid */ 3498031591dSSrihari Venkatesan uint_t cpi_procnodes_per_pkg; /* AMD: # of nodes in the package */ 3508031591dSSrihari Venkatesan /* Intel: 1 */ 3517660e73fSHans Rosenfeld uint_t cpi_compunitid; /* AMD: ComputeUnit ID, Intel: coreid */ 3527660e73fSHans Rosenfeld uint_t cpi_cores_per_compunit; /* AMD: # of cores in the ComputeUnit */ 3537af88ac7SKuriakose Kuruvilla 3547af88ac7SKuriakose Kuruvilla struct xsave_info cpi_xsave; /* fn D: xsave/xrestor info */ 3557c478bd9Sstevel@tonic-gate }; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate static struct cpuid_info cpuid_info0; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * These bit fields are defined by the Intel Application Note AP-485 3627c478bd9Sstevel@tonic-gate * "Intel Processor Identification and the CPUID Instruction" 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate #define CPI_FAMILY_XTD(cpi) BITX((cpi)->cpi_std[1].cp_eax, 27, 20) 3657c478bd9Sstevel@tonic-gate #define CPI_MODEL_XTD(cpi) BITX((cpi)->cpi_std[1].cp_eax, 19, 16) 3667c478bd9Sstevel@tonic-gate #define CPI_TYPE(cpi) BITX((cpi)->cpi_std[1].cp_eax, 13, 12) 3677c478bd9Sstevel@tonic-gate #define CPI_FAMILY(cpi) BITX((cpi)->cpi_std[1].cp_eax, 11, 8) 3687c478bd9Sstevel@tonic-gate #define CPI_STEP(cpi) BITX((cpi)->cpi_std[1].cp_eax, 3, 0) 3697c478bd9Sstevel@tonic-gate #define CPI_MODEL(cpi) BITX((cpi)->cpi_std[1].cp_eax, 7, 4) 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate #define CPI_FEATURES_EDX(cpi) ((cpi)->cpi_std[1].cp_edx) 3727c478bd9Sstevel@tonic-gate #define CPI_FEATURES_ECX(cpi) ((cpi)->cpi_std[1].cp_ecx) 3737c478bd9Sstevel@tonic-gate #define CPI_FEATURES_XTD_EDX(cpi) ((cpi)->cpi_extd[1].cp_edx) 3747c478bd9Sstevel@tonic-gate #define CPI_FEATURES_XTD_ECX(cpi) ((cpi)->cpi_extd[1].cp_ecx) 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate #define CPI_BRANDID(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 7, 0) 3777c478bd9Sstevel@tonic-gate #define CPI_CHUNKS(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 15, 7) 3787c478bd9Sstevel@tonic-gate #define CPI_CPU_COUNT(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 23, 16) 3797c478bd9Sstevel@tonic-gate #define CPI_APIC_ID(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 31, 24) 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate #define CPI_MAXEAX_MAX 0x100 /* sanity control */ 3827c478bd9Sstevel@tonic-gate #define CPI_XMAXEAX_MAX 0x80000100 383d129bde2Sesaxe #define CPI_FN4_ECX_MAX 0x20 /* sanity: max fn 4 levels */ 384b6917abeSmishra #define CPI_FNB_ECX_MAX 0x20 /* sanity: max fn B levels */ 385d129bde2Sesaxe 386d129bde2Sesaxe /* 387d129bde2Sesaxe * Function 4 (Deterministic Cache Parameters) macros 388d129bde2Sesaxe * Defined by Intel Application Note AP-485 389d129bde2Sesaxe */ 390d129bde2Sesaxe #define CPI_NUM_CORES(regs) BITX((regs)->cp_eax, 31, 26) 391d129bde2Sesaxe #define CPI_NTHR_SHR_CACHE(regs) BITX((regs)->cp_eax, 25, 14) 392d129bde2Sesaxe #define CPI_FULL_ASSOC_CACHE(regs) BITX((regs)->cp_eax, 9, 9) 393d129bde2Sesaxe #define CPI_SELF_INIT_CACHE(regs) BITX((regs)->cp_eax, 8, 8) 394d129bde2Sesaxe #define CPI_CACHE_LVL(regs) BITX((regs)->cp_eax, 7, 5) 395d129bde2Sesaxe #define CPI_CACHE_TYPE(regs) BITX((regs)->cp_eax, 4, 0) 396b6917abeSmishra #define CPI_CPU_LEVEL_TYPE(regs) BITX((regs)->cp_ecx, 15, 8) 397d129bde2Sesaxe 398d129bde2Sesaxe #define CPI_CACHE_WAYS(regs) BITX((regs)->cp_ebx, 31, 22) 399d129bde2Sesaxe #define CPI_CACHE_PARTS(regs) BITX((regs)->cp_ebx, 21, 12) 400d129bde2Sesaxe #define CPI_CACHE_COH_LN_SZ(regs) BITX((regs)->cp_ebx, 11, 0) 401d129bde2Sesaxe 402d129bde2Sesaxe #define CPI_CACHE_SETS(regs) BITX((regs)->cp_ecx, 31, 0) 403d129bde2Sesaxe 404d129bde2Sesaxe #define CPI_PREFCH_STRIDE(regs) BITX((regs)->cp_edx, 9, 0) 405d129bde2Sesaxe 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* 4085ff02082Sdmick * A couple of shorthand macros to identify "later" P6-family chips 4095ff02082Sdmick * like the Pentium M and Core. First, the "older" P6-based stuff 4105ff02082Sdmick * (loosely defined as "pre-Pentium-4"): 4115ff02082Sdmick * P6, PII, Mobile PII, PII Xeon, PIII, Mobile PIII, PIII Xeon 4125ff02082Sdmick */ 4135ff02082Sdmick 4145ff02082Sdmick #define IS_LEGACY_P6(cpi) ( \ 4155ff02082Sdmick cpi->cpi_family == 6 && \ 4165ff02082Sdmick (cpi->cpi_model == 1 || \ 4175ff02082Sdmick cpi->cpi_model == 3 || \ 4185ff02082Sdmick cpi->cpi_model == 5 || \ 4195ff02082Sdmick cpi->cpi_model == 6 || \ 4205ff02082Sdmick cpi->cpi_model == 7 || \ 4215ff02082Sdmick cpi->cpi_model == 8 || \ 4225ff02082Sdmick cpi->cpi_model == 0xA || \ 4235ff02082Sdmick cpi->cpi_model == 0xB) \ 4245ff02082Sdmick ) 4255ff02082Sdmick 4265ff02082Sdmick /* A "new F6" is everything with family 6 that's not the above */ 4275ff02082Sdmick #define IS_NEW_F6(cpi) ((cpi->cpi_family == 6) && !IS_LEGACY_P6(cpi)) 4285ff02082Sdmick 429bf91205bSksadhukh /* Extended family/model support */ 430bf91205bSksadhukh #define IS_EXTENDED_MODEL_INTEL(cpi) (cpi->cpi_family == 0x6 || \ 431bf91205bSksadhukh cpi->cpi_family >= 0xf) 432bf91205bSksadhukh 4335ff02082Sdmick /* 434f98fbcecSbholler * Info for monitor/mwait idle loop. 435f98fbcecSbholler * 436f98fbcecSbholler * See cpuid section of "Intel 64 and IA-32 Architectures Software Developer's 437f98fbcecSbholler * Manual Volume 2A: Instruction Set Reference, A-M" #25366-022US, November 438f98fbcecSbholler * 2006. 439f98fbcecSbholler * See MONITOR/MWAIT section of "AMD64 Architecture Programmer's Manual 440f98fbcecSbholler * Documentation Updates" #33633, Rev 2.05, December 2006. 441f98fbcecSbholler */ 442f98fbcecSbholler #define MWAIT_SUPPORT (0x00000001) /* mwait supported */ 443f98fbcecSbholler #define MWAIT_EXTENSIONS (0x00000002) /* extenstion supported */ 444f98fbcecSbholler #define MWAIT_ECX_INT_ENABLE (0x00000004) /* ecx 1 extension supported */ 445f98fbcecSbholler #define MWAIT_SUPPORTED(cpi) ((cpi)->cpi_std[1].cp_ecx & CPUID_INTC_ECX_MON) 446f98fbcecSbholler #define MWAIT_INT_ENABLE(cpi) ((cpi)->cpi_std[5].cp_ecx & 0x2) 447f98fbcecSbholler #define MWAIT_EXTENSION(cpi) ((cpi)->cpi_std[5].cp_ecx & 0x1) 448f98fbcecSbholler #define MWAIT_SIZE_MIN(cpi) BITX((cpi)->cpi_std[5].cp_eax, 15, 0) 449f98fbcecSbholler #define MWAIT_SIZE_MAX(cpi) BITX((cpi)->cpi_std[5].cp_ebx, 15, 0) 450f98fbcecSbholler /* 451f98fbcecSbholler * Number of sub-cstates for a given c-state. 452f98fbcecSbholler */ 453f98fbcecSbholler #define MWAIT_NUM_SUBC_STATES(cpi, c_state) \ 454f98fbcecSbholler BITX((cpi)->cpi_std[5].cp_edx, c_state + 3, c_state) 455f98fbcecSbholler 4568a40a695Sgavinm /* 4577af88ac7SKuriakose Kuruvilla * XSAVE leaf 0xD enumeration 4587af88ac7SKuriakose Kuruvilla */ 4597af88ac7SKuriakose Kuruvilla #define CPUID_LEAFD_2_YMM_OFFSET 576 4607af88ac7SKuriakose Kuruvilla #define CPUID_LEAFD_2_YMM_SIZE 256 4617af88ac7SKuriakose Kuruvilla 4627af88ac7SKuriakose Kuruvilla /* 463e4b86885SCheng Sean Ye * Functions we consune from cpuid_subr.c; don't publish these in a header 464e4b86885SCheng Sean Ye * file to try and keep people using the expected cpuid_* interfaces. 4658a40a695Sgavinm */ 466e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t); 46789e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t); 468e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t); 469e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t); 470e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *); 4718a40a695Sgavinm 4728a40a695Sgavinm /* 473ae115bc7Smrj * Apply up various platform-dependent restrictions where the 474ae115bc7Smrj * underlying platform restrictions mean the CPU can be marked 475ae115bc7Smrj * as less capable than its cpuid instruction would imply. 476ae115bc7Smrj */ 477843e1988Sjohnlev #if defined(__xpv) 478843e1988Sjohnlev static void 479843e1988Sjohnlev platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp) 480843e1988Sjohnlev { 481843e1988Sjohnlev switch (eax) { 482e4b86885SCheng Sean Ye case 1: { 483e4b86885SCheng Sean Ye uint32_t mcamask = DOMAIN_IS_INITDOMAIN(xen_info) ? 484e4b86885SCheng Sean Ye 0 : CPUID_INTC_EDX_MCA; 485843e1988Sjohnlev cp->cp_edx &= 486e4b86885SCheng Sean Ye ~(mcamask | 487e4b86885SCheng Sean Ye CPUID_INTC_EDX_PSE | 488843e1988Sjohnlev CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE | 489843e1988Sjohnlev CPUID_INTC_EDX_SEP | CPUID_INTC_EDX_MTRR | 490843e1988Sjohnlev CPUID_INTC_EDX_PGE | CPUID_INTC_EDX_PAT | 491843e1988Sjohnlev CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP | 492843e1988Sjohnlev CPUID_INTC_EDX_PSE36 | CPUID_INTC_EDX_HTT); 493843e1988Sjohnlev break; 494e4b86885SCheng Sean Ye } 495ae115bc7Smrj 496843e1988Sjohnlev case 0x80000001: 497843e1988Sjohnlev cp->cp_edx &= 498843e1988Sjohnlev ~(CPUID_AMD_EDX_PSE | 499843e1988Sjohnlev CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE | 500843e1988Sjohnlev CPUID_AMD_EDX_MTRR | CPUID_AMD_EDX_PGE | 501843e1988Sjohnlev CPUID_AMD_EDX_PAT | CPUID_AMD_EDX_PSE36 | 502843e1988Sjohnlev CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP | 503843e1988Sjohnlev CPUID_AMD_EDX_TSCP); 504843e1988Sjohnlev cp->cp_ecx &= ~CPUID_AMD_ECX_CMP_LGCY; 505843e1988Sjohnlev break; 506843e1988Sjohnlev default: 507843e1988Sjohnlev break; 508843e1988Sjohnlev } 509843e1988Sjohnlev 510843e1988Sjohnlev switch (vendor) { 511843e1988Sjohnlev case X86_VENDOR_Intel: 512843e1988Sjohnlev switch (eax) { 513843e1988Sjohnlev case 4: 514843e1988Sjohnlev /* 515843e1988Sjohnlev * Zero out the (ncores-per-chip - 1) field 516843e1988Sjohnlev */ 517843e1988Sjohnlev cp->cp_eax &= 0x03fffffff; 518843e1988Sjohnlev break; 519843e1988Sjohnlev default: 520843e1988Sjohnlev break; 521843e1988Sjohnlev } 522843e1988Sjohnlev break; 523843e1988Sjohnlev case X86_VENDOR_AMD: 524843e1988Sjohnlev switch (eax) { 5252ef50f01SJoe Bonasera 5262ef50f01SJoe Bonasera case 0x80000001: 5272ef50f01SJoe Bonasera cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D; 5282ef50f01SJoe Bonasera break; 5292ef50f01SJoe Bonasera 530843e1988Sjohnlev case 0x80000008: 531843e1988Sjohnlev /* 532843e1988Sjohnlev * Zero out the (ncores-per-chip - 1) field 533843e1988Sjohnlev */ 534843e1988Sjohnlev cp->cp_ecx &= 0xffffff00; 535843e1988Sjohnlev break; 536843e1988Sjohnlev default: 537843e1988Sjohnlev break; 538843e1988Sjohnlev } 539843e1988Sjohnlev break; 540843e1988Sjohnlev default: 541843e1988Sjohnlev break; 542843e1988Sjohnlev } 543843e1988Sjohnlev } 544843e1988Sjohnlev #else 545ae115bc7Smrj #define platform_cpuid_mangle(vendor, eax, cp) /* nothing */ 546843e1988Sjohnlev #endif 547ae115bc7Smrj 548ae115bc7Smrj /* 5497c478bd9Sstevel@tonic-gate * Some undocumented ways of patching the results of the cpuid 5507c478bd9Sstevel@tonic-gate * instruction to permit running Solaris 10 on future cpus that 5517c478bd9Sstevel@tonic-gate * we don't currently support. Could be set to non-zero values 5527c478bd9Sstevel@tonic-gate * via settings in eeprom. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_include; 5567c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_exclude; 5577c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_include; 5587c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_exclude; 5597c478bd9Sstevel@tonic-gate 560a3114836SGerry Liu /* 561a3114836SGerry Liu * Allocate space for mcpu_cpi in the machcpu structure for all non-boot CPUs. 562a3114836SGerry Liu */ 563ae115bc7Smrj void 564ae115bc7Smrj cpuid_alloc_space(cpu_t *cpu) 565ae115bc7Smrj { 566ae115bc7Smrj /* 567ae115bc7Smrj * By convention, cpu0 is the boot cpu, which is set up 568ae115bc7Smrj * before memory allocation is available. All other cpus get 569ae115bc7Smrj * their cpuid_info struct allocated here. 570ae115bc7Smrj */ 571ae115bc7Smrj ASSERT(cpu->cpu_id != 0); 572a3114836SGerry Liu ASSERT(cpu->cpu_m.mcpu_cpi == NULL); 573ae115bc7Smrj cpu->cpu_m.mcpu_cpi = 574ae115bc7Smrj kmem_zalloc(sizeof (*cpu->cpu_m.mcpu_cpi), KM_SLEEP); 575ae115bc7Smrj } 576ae115bc7Smrj 577ae115bc7Smrj void 578ae115bc7Smrj cpuid_free_space(cpu_t *cpu) 579ae115bc7Smrj { 580d129bde2Sesaxe struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 581d129bde2Sesaxe int i; 582d129bde2Sesaxe 583a3114836SGerry Liu ASSERT(cpi != NULL); 584a3114836SGerry Liu ASSERT(cpi != &cpuid_info0); 585d129bde2Sesaxe 586d129bde2Sesaxe /* 587d129bde2Sesaxe * Free up any function 4 related dynamic storage 588d129bde2Sesaxe */ 589d129bde2Sesaxe for (i = 1; i < cpi->cpi_std_4_size; i++) 590d129bde2Sesaxe kmem_free(cpi->cpi_std_4[i], sizeof (struct cpuid_regs)); 591d129bde2Sesaxe if (cpi->cpi_std_4_size > 0) 592d129bde2Sesaxe kmem_free(cpi->cpi_std_4, 593d129bde2Sesaxe cpi->cpi_std_4_size * sizeof (struct cpuid_regs *)); 594d129bde2Sesaxe 595a3114836SGerry Liu kmem_free(cpi, sizeof (*cpi)); 596a3114836SGerry Liu cpu->cpu_m.mcpu_cpi = NULL; 597ae115bc7Smrj } 598ae115bc7Smrj 599551bc2a6Smrj #if !defined(__xpv) 600cfe84b82SMatt Amdur /* 601cfe84b82SMatt Amdur * Determine the type of the underlying platform. This is used to customize 602cfe84b82SMatt Amdur * initialization of various subsystems (e.g. TSC). determine_platform() must 603cfe84b82SMatt Amdur * only ever be called once to prevent two processors from seeing different 60479ec9da8SYuri Pankov * values of platform_type. Must be called before cpuid_pass1(), the earliest 60579ec9da8SYuri Pankov * consumer to execute (uses _cpuid_chiprev --> synth_amd_info --> get_hwenv). 606cfe84b82SMatt Amdur */ 607cfe84b82SMatt Amdur void 608cfe84b82SMatt Amdur determine_platform(void) 609551bc2a6Smrj { 610551bc2a6Smrj struct cpuid_regs cp; 61179ec9da8SYuri Pankov uint32_t base; 61279ec9da8SYuri Pankov uint32_t regs[4]; 61379ec9da8SYuri Pankov char *hvstr = (char *)regs; 614551bc2a6Smrj 615cfe84b82SMatt Amdur ASSERT(platform_type == -1); 616cfe84b82SMatt Amdur 617349b53ddSStuart Maybee platform_type = HW_NATIVE; 618349b53ddSStuart Maybee 619349b53ddSStuart Maybee if (!enable_platform_detection) 620349b53ddSStuart Maybee return; 621349b53ddSStuart Maybee 622551bc2a6Smrj /* 62379ec9da8SYuri Pankov * If Hypervisor CPUID bit is set, try to determine hypervisor 62479ec9da8SYuri Pankov * vendor signature, and set platform type accordingly. 62579ec9da8SYuri Pankov * 62679ec9da8SYuri Pankov * References: 62779ec9da8SYuri Pankov * http://lkml.org/lkml/2008/10/1/246 62879ec9da8SYuri Pankov * http://kb.vmware.com/kb/1009458 629551bc2a6Smrj */ 63079ec9da8SYuri Pankov cp.cp_eax = 0x1; 631551bc2a6Smrj (void) __cpuid_insn(&cp); 63279ec9da8SYuri Pankov if ((cp.cp_ecx & CPUID_INTC_ECX_HV) != 0) { 63379ec9da8SYuri Pankov cp.cp_eax = 0x40000000; 63479ec9da8SYuri Pankov (void) __cpuid_insn(&cp); 63579ec9da8SYuri Pankov regs[0] = cp.cp_ebx; 63679ec9da8SYuri Pankov regs[1] = cp.cp_ecx; 63779ec9da8SYuri Pankov regs[2] = cp.cp_edx; 63879ec9da8SYuri Pankov regs[3] = 0; 63979ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_XEN_HVM) == 0) { 640b9bfdccdSStuart Maybee platform_type = HW_XEN_HVM; 6416e5580c9SFrank Van Der Linden return; 642551bc2a6Smrj } 64379ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_VMWARE) == 0) { 64479ec9da8SYuri Pankov platform_type = HW_VMWARE; 64579ec9da8SYuri Pankov return; 64679ec9da8SYuri Pankov } 64779ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_KVM) == 0) { 64879ec9da8SYuri Pankov platform_type = HW_KVM; 64979ec9da8SYuri Pankov return; 65079ec9da8SYuri Pankov } 65179ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_MICROSOFT) == 0) 65279ec9da8SYuri Pankov platform_type = HW_MICROSOFT; 65379ec9da8SYuri Pankov } else { 65479ec9da8SYuri Pankov /* 65579ec9da8SYuri Pankov * Check older VMware hardware versions. VMware hypervisor is 65679ec9da8SYuri Pankov * detected by performing an IN operation to VMware hypervisor 65779ec9da8SYuri Pankov * port and checking that value returned in %ebx is VMware 65879ec9da8SYuri Pankov * hypervisor magic value. 65979ec9da8SYuri Pankov * 66079ec9da8SYuri Pankov * References: http://kb.vmware.com/kb/1009458 66179ec9da8SYuri Pankov */ 66279ec9da8SYuri Pankov vmware_port(VMWARE_HVCMD_GETVERSION, regs); 66379ec9da8SYuri Pankov if (regs[1] == VMWARE_HVMAGIC) { 66479ec9da8SYuri Pankov platform_type = HW_VMWARE; 66579ec9da8SYuri Pankov return; 66679ec9da8SYuri Pankov } 667b9bfdccdSStuart Maybee } 668b9bfdccdSStuart Maybee 66979ec9da8SYuri Pankov /* 67079ec9da8SYuri Pankov * Check Xen hypervisor. In a fully virtualized domain, 67179ec9da8SYuri Pankov * Xen's pseudo-cpuid function returns a string representing the 67279ec9da8SYuri Pankov * Xen signature in %ebx, %ecx, and %edx. %eax contains the maximum 67379ec9da8SYuri Pankov * supported cpuid function. We need at least a (base + 2) leaf value 67479ec9da8SYuri Pankov * to do what we want to do. Try different base values, since the 67579ec9da8SYuri Pankov * hypervisor might use a different one depending on whether Hyper-V 67679ec9da8SYuri Pankov * emulation is switched on by default or not. 67779ec9da8SYuri Pankov */ 67879ec9da8SYuri Pankov for (base = 0x40000000; base < 0x40010000; base += 0x100) { 67979ec9da8SYuri Pankov cp.cp_eax = base; 68079ec9da8SYuri Pankov (void) __cpuid_insn(&cp); 68179ec9da8SYuri Pankov regs[0] = cp.cp_ebx; 68279ec9da8SYuri Pankov regs[1] = cp.cp_ecx; 68379ec9da8SYuri Pankov regs[2] = cp.cp_edx; 68479ec9da8SYuri Pankov regs[3] = 0; 68579ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_XEN_HVM) == 0 && 68679ec9da8SYuri Pankov cp.cp_eax >= (base + 2)) { 68779ec9da8SYuri Pankov platform_type &= ~HW_NATIVE; 68879ec9da8SYuri Pankov platform_type |= HW_XEN_HVM; 68979ec9da8SYuri Pankov return; 69079ec9da8SYuri Pankov } 69179ec9da8SYuri Pankov } 6926e5580c9SFrank Van Der Linden } 6936e5580c9SFrank Van Der Linden 694b9bfdccdSStuart Maybee int 695b9bfdccdSStuart Maybee get_hwenv(void) 696b9bfdccdSStuart Maybee { 697cfe84b82SMatt Amdur ASSERT(platform_type != -1); 698b9bfdccdSStuart Maybee return (platform_type); 699b9bfdccdSStuart Maybee } 700b9bfdccdSStuart Maybee 701b9bfdccdSStuart Maybee int 702b9bfdccdSStuart Maybee is_controldom(void) 703b9bfdccdSStuart Maybee { 704b9bfdccdSStuart Maybee return (0); 705b9bfdccdSStuart Maybee } 706b9bfdccdSStuart Maybee 707b9bfdccdSStuart Maybee #else 708b9bfdccdSStuart Maybee 709b9bfdccdSStuart Maybee int 710b9bfdccdSStuart Maybee get_hwenv(void) 711b9bfdccdSStuart Maybee { 712b9bfdccdSStuart Maybee return (HW_XEN_PV); 713b9bfdccdSStuart Maybee } 714b9bfdccdSStuart Maybee 715b9bfdccdSStuart Maybee int 716b9bfdccdSStuart Maybee is_controldom(void) 717b9bfdccdSStuart Maybee { 718b9bfdccdSStuart Maybee return (DOMAIN_IS_INITDOMAIN(xen_info)); 719b9bfdccdSStuart Maybee } 720b9bfdccdSStuart Maybee 721551bc2a6Smrj #endif /* __xpv */ 722551bc2a6Smrj 7238031591dSSrihari Venkatesan static void 7247417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu_t *cpu, void *feature) 7258031591dSSrihari Venkatesan { 7268031591dSSrihari Venkatesan uint_t i; 7278031591dSSrihari Venkatesan uint_t chipid_shift = 0; 7288031591dSSrihari Venkatesan uint_t coreid_shift = 0; 7298031591dSSrihari Venkatesan struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 7308031591dSSrihari Venkatesan 7318031591dSSrihari Venkatesan for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1) 7328031591dSSrihari Venkatesan chipid_shift++; 7338031591dSSrihari Venkatesan 7348031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_apicid >> chipid_shift; 7358031591dSSrihari Venkatesan cpi->cpi_clogid = cpi->cpi_apicid & ((1 << chipid_shift) - 1); 7368031591dSSrihari Venkatesan 7377417cfdeSKuriakose Kuruvilla if (is_x86_feature(feature, X86FSET_CMP)) { 7388031591dSSrihari Venkatesan /* 7398031591dSSrihari Venkatesan * Multi-core (and possibly multi-threaded) 7408031591dSSrihari Venkatesan * processors. 7418031591dSSrihari Venkatesan */ 7428031591dSSrihari Venkatesan uint_t ncpu_per_core; 7438031591dSSrihari Venkatesan if (cpi->cpi_ncore_per_chip == 1) 7448031591dSSrihari Venkatesan ncpu_per_core = cpi->cpi_ncpu_per_chip; 7458031591dSSrihari Venkatesan else if (cpi->cpi_ncore_per_chip > 1) 7468031591dSSrihari Venkatesan ncpu_per_core = cpi->cpi_ncpu_per_chip / 7478031591dSSrihari Venkatesan cpi->cpi_ncore_per_chip; 7488031591dSSrihari Venkatesan /* 7498031591dSSrihari Venkatesan * 8bit APIC IDs on dual core Pentiums 7508031591dSSrihari Venkatesan * look like this: 7518031591dSSrihari Venkatesan * 7528031591dSSrihari Venkatesan * +-----------------------+------+------+ 7538031591dSSrihari Venkatesan * | Physical Package ID | MC | HT | 7548031591dSSrihari Venkatesan * +-----------------------+------+------+ 7558031591dSSrihari Venkatesan * <------- chipid --------> 7568031591dSSrihari Venkatesan * <------- coreid ---------------> 7578031591dSSrihari Venkatesan * <--- clogid --> 7588031591dSSrihari Venkatesan * <------> 7598031591dSSrihari Venkatesan * pkgcoreid 7608031591dSSrihari Venkatesan * 7618031591dSSrihari Venkatesan * Where the number of bits necessary to 7628031591dSSrihari Venkatesan * represent MC and HT fields together equals 7638031591dSSrihari Venkatesan * to the minimum number of bits necessary to 7648031591dSSrihari Venkatesan * store the value of cpi->cpi_ncpu_per_chip. 7658031591dSSrihari Venkatesan * Of those bits, the MC part uses the number 7668031591dSSrihari Venkatesan * of bits necessary to store the value of 7678031591dSSrihari Venkatesan * cpi->cpi_ncore_per_chip. 7688031591dSSrihari Venkatesan */ 7698031591dSSrihari Venkatesan for (i = 1; i < ncpu_per_core; i <<= 1) 7708031591dSSrihari Venkatesan coreid_shift++; 7718031591dSSrihari Venkatesan cpi->cpi_coreid = cpi->cpi_apicid >> coreid_shift; 7728031591dSSrihari Venkatesan cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift; 7737417cfdeSKuriakose Kuruvilla } else if (is_x86_feature(feature, X86FSET_HTT)) { 7748031591dSSrihari Venkatesan /* 7758031591dSSrihari Venkatesan * Single-core multi-threaded processors. 7768031591dSSrihari Venkatesan */ 7778031591dSSrihari Venkatesan cpi->cpi_coreid = cpi->cpi_chipid; 7788031591dSSrihari Venkatesan cpi->cpi_pkgcoreid = 0; 7798031591dSSrihari Venkatesan } 7808031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 7817660e73fSHans Rosenfeld cpi->cpi_compunitid = cpi->cpi_coreid; 7828031591dSSrihari Venkatesan } 7838031591dSSrihari Venkatesan 7848031591dSSrihari Venkatesan static void 7858031591dSSrihari Venkatesan cpuid_amd_getids(cpu_t *cpu) 7868031591dSSrihari Venkatesan { 7871fbe4a4fSSrihari Venkatesan int i, first_half, coreidsz; 7888031591dSSrihari Venkatesan uint32_t nb_caps_reg; 7898031591dSSrihari Venkatesan uint_t node2_1; 7908031591dSSrihari Venkatesan struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 7917660e73fSHans Rosenfeld struct cpuid_regs *cp; 7928031591dSSrihari Venkatesan 7938031591dSSrihari Venkatesan /* 7948031591dSSrihari Venkatesan * AMD CMP chips currently have a single thread per core. 7958031591dSSrihari Venkatesan * 7968031591dSSrihari Venkatesan * Since no two cpus share a core we must assign a distinct coreid 7978031591dSSrihari Venkatesan * per cpu, and we do this by using the cpu_id. This scheme does not, 7988031591dSSrihari Venkatesan * however, guarantee that sibling cores of a chip will have sequential 7998031591dSSrihari Venkatesan * coreids starting at a multiple of the number of cores per chip - 8008031591dSSrihari Venkatesan * that is usually the case, but if the ACPI MADT table is presented 8018031591dSSrihari Venkatesan * in a different order then we need to perform a few more gymnastics 8028031591dSSrihari Venkatesan * for the pkgcoreid. 8038031591dSSrihari Venkatesan * 8048031591dSSrihari Venkatesan * All processors in the system have the same number of enabled 8058031591dSSrihari Venkatesan * cores. Cores within a processor are always numbered sequentially 8068031591dSSrihari Venkatesan * from 0 regardless of how many or which are disabled, and there 8078031591dSSrihari Venkatesan * is no way for operating system to discover the real core id when some 8088031591dSSrihari Venkatesan * are disabled. 8097660e73fSHans Rosenfeld * 8107660e73fSHans Rosenfeld * In family 0x15, the cores come in pairs called compute units. They 8117660e73fSHans Rosenfeld * share I$ and L2 caches and the FPU. Enumeration of this feature is 8127660e73fSHans Rosenfeld * simplified by the new topology extensions CPUID leaf, indicated by 8137660e73fSHans Rosenfeld * the X86 feature X86FSET_TOPOEXT. 8148031591dSSrihari Venkatesan */ 8158031591dSSrihari Venkatesan 8168031591dSSrihari Venkatesan cpi->cpi_coreid = cpu->cpu_id; 8177660e73fSHans Rosenfeld cpi->cpi_compunitid = cpu->cpu_id; 8188031591dSSrihari Venkatesan 8198031591dSSrihari Venkatesan if (cpi->cpi_xmaxeax >= 0x80000008) { 8208031591dSSrihari Venkatesan 8218031591dSSrihari Venkatesan coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12); 8228031591dSSrihari Venkatesan 8238031591dSSrihari Venkatesan /* 8248031591dSSrihari Venkatesan * In AMD parlance chip is really a node while Solaris 8258031591dSSrihari Venkatesan * sees chip as equivalent to socket/package. 8268031591dSSrihari Venkatesan */ 8278031591dSSrihari Venkatesan cpi->cpi_ncore_per_chip = 8288031591dSSrihari Venkatesan BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1; 8291fbe4a4fSSrihari Venkatesan if (coreidsz == 0) { 8308031591dSSrihari Venkatesan /* Use legacy method */ 8311fbe4a4fSSrihari Venkatesan for (i = 1; i < cpi->cpi_ncore_per_chip; i <<= 1) 8321fbe4a4fSSrihari Venkatesan coreidsz++; 8331fbe4a4fSSrihari Venkatesan if (coreidsz == 0) 8341fbe4a4fSSrihari Venkatesan coreidsz = 1; 8351fbe4a4fSSrihari Venkatesan } 8368031591dSSrihari Venkatesan } else { 8378031591dSSrihari Venkatesan /* Assume single-core part */ 8381fbe4a4fSSrihari Venkatesan cpi->cpi_ncore_per_chip = 1; 83972b70389SJakub Jermar coreidsz = 1; 8408031591dSSrihari Venkatesan } 8418031591dSSrihari Venkatesan 8421fbe4a4fSSrihari Venkatesan cpi->cpi_clogid = cpi->cpi_pkgcoreid = 8431fbe4a4fSSrihari Venkatesan cpi->cpi_apicid & ((1<<coreidsz) - 1); 8448031591dSSrihari Venkatesan cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip; 8458031591dSSrihari Venkatesan 8467660e73fSHans Rosenfeld /* Get node ID, compute unit ID */ 8477660e73fSHans Rosenfeld if (is_x86_feature(x86_featureset, X86FSET_TOPOEXT) && 8487660e73fSHans Rosenfeld cpi->cpi_xmaxeax >= 0x8000001e) { 8497660e73fSHans Rosenfeld cp = &cpi->cpi_extd[0x1e]; 8507660e73fSHans Rosenfeld cp->cp_eax = 0x8000001e; 8517660e73fSHans Rosenfeld (void) __cpuid_insn(cp); 8527660e73fSHans Rosenfeld 8537660e73fSHans Rosenfeld cpi->cpi_procnodes_per_pkg = BITX(cp->cp_ecx, 10, 8) + 1; 8547660e73fSHans Rosenfeld cpi->cpi_procnodeid = BITX(cp->cp_ecx, 7, 0); 8557660e73fSHans Rosenfeld cpi->cpi_cores_per_compunit = BITX(cp->cp_ebx, 15, 8) + 1; 8567660e73fSHans Rosenfeld cpi->cpi_compunitid = BITX(cp->cp_ebx, 7, 0) 8577660e73fSHans Rosenfeld + (cpi->cpi_ncore_per_chip / cpi->cpi_cores_per_compunit) 8587660e73fSHans Rosenfeld * (cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg); 8597660e73fSHans Rosenfeld } else if (cpi->cpi_family == 0xf || cpi->cpi_family >= 0x11) { 8601fbe4a4fSSrihari Venkatesan cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7; 8618031591dSSrihari Venkatesan } else if (cpi->cpi_family == 0x10) { 8628031591dSSrihari Venkatesan /* 8638031591dSSrihari Venkatesan * See if we are a multi-node processor. 8648031591dSSrihari Venkatesan * All processors in the system have the same number of nodes 8658031591dSSrihari Venkatesan */ 8668031591dSSrihari Venkatesan nb_caps_reg = pci_getl_func(0, 24, 3, 0xe8); 8678031591dSSrihari Venkatesan if ((cpi->cpi_model < 8) || BITX(nb_caps_reg, 29, 29) == 0) { 8688031591dSSrihari Venkatesan /* Single-node */ 8691fbe4a4fSSrihari Venkatesan cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5, 8701fbe4a4fSSrihari Venkatesan coreidsz); 8718031591dSSrihari Venkatesan } else { 8728031591dSSrihari Venkatesan 8738031591dSSrihari Venkatesan /* 8748031591dSSrihari Venkatesan * Multi-node revision D (2 nodes per package 8758031591dSSrihari Venkatesan * are supported) 8768031591dSSrihari Venkatesan */ 8778031591dSSrihari Venkatesan cpi->cpi_procnodes_per_pkg = 2; 8788031591dSSrihari Venkatesan 8798031591dSSrihari Venkatesan first_half = (cpi->cpi_pkgcoreid <= 8808031591dSSrihari Venkatesan (cpi->cpi_ncore_per_chip/2 - 1)); 8818031591dSSrihari Venkatesan 8828031591dSSrihari Venkatesan if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) { 8838031591dSSrihari Venkatesan /* We are BSP */ 8848031591dSSrihari Venkatesan cpi->cpi_procnodeid = (first_half ? 0 : 1); 8858031591dSSrihari Venkatesan } else { 8868031591dSSrihari Venkatesan 8878031591dSSrihari Venkatesan /* We are AP */ 8888031591dSSrihari Venkatesan /* NodeId[2:1] bits to use for reading F3xe8 */ 8898031591dSSrihari Venkatesan node2_1 = BITX(cpi->cpi_apicid, 5, 4) << 1; 8908031591dSSrihari Venkatesan 8918031591dSSrihari Venkatesan nb_caps_reg = 8928031591dSSrihari Venkatesan pci_getl_func(0, 24 + node2_1, 3, 0xe8); 8938031591dSSrihari Venkatesan 8948031591dSSrihari Venkatesan /* 8958031591dSSrihari Venkatesan * Check IntNodeNum bit (31:30, but bit 31 is 8968031591dSSrihari Venkatesan * always 0 on dual-node processors) 8978031591dSSrihari Venkatesan */ 8988031591dSSrihari Venkatesan if (BITX(nb_caps_reg, 30, 30) == 0) 8998031591dSSrihari Venkatesan cpi->cpi_procnodeid = node2_1 + 9008031591dSSrihari Venkatesan !first_half; 9018031591dSSrihari Venkatesan else 9028031591dSSrihari Venkatesan cpi->cpi_procnodeid = node2_1 + 9038031591dSSrihari Venkatesan first_half; 9048031591dSSrihari Venkatesan } 9058031591dSSrihari Venkatesan } 9068031591dSSrihari Venkatesan } else { 9078031591dSSrihari Venkatesan cpi->cpi_procnodeid = 0; 9088031591dSSrihari Venkatesan } 9097660e73fSHans Rosenfeld 9107660e73fSHans Rosenfeld cpi->cpi_chipid = 9117660e73fSHans Rosenfeld cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg; 9128031591dSSrihari Venkatesan } 9138031591dSSrihari Venkatesan 9147af88ac7SKuriakose Kuruvilla /* 9157af88ac7SKuriakose Kuruvilla * Setup XFeature_Enabled_Mask register. Required by xsave feature. 9167af88ac7SKuriakose Kuruvilla */ 9177af88ac7SKuriakose Kuruvilla void 9187af88ac7SKuriakose Kuruvilla setup_xfem(void) 9197af88ac7SKuriakose Kuruvilla { 9207af88ac7SKuriakose Kuruvilla uint64_t flags = XFEATURE_LEGACY_FP; 9217af88ac7SKuriakose Kuruvilla 9227af88ac7SKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE)); 9237af88ac7SKuriakose Kuruvilla 9247af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_SSE)) 9257af88ac7SKuriakose Kuruvilla flags |= XFEATURE_SSE; 9267af88ac7SKuriakose Kuruvilla 9277af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_AVX)) 9287af88ac7SKuriakose Kuruvilla flags |= XFEATURE_AVX; 9297af88ac7SKuriakose Kuruvilla 9307af88ac7SKuriakose Kuruvilla set_xcr(XFEATURE_ENABLED_MASK, flags); 9317af88ac7SKuriakose Kuruvilla 9327af88ac7SKuriakose Kuruvilla xsave_bv_all = flags; 9337af88ac7SKuriakose Kuruvilla } 9347af88ac7SKuriakose Kuruvilla 935dfea898aSKuriakose Kuruvilla void 936dfea898aSKuriakose Kuruvilla cpuid_pass1(cpu_t *cpu, uchar_t *featureset) 9377c478bd9Sstevel@tonic-gate { 9387c478bd9Sstevel@tonic-gate uint32_t mask_ecx, mask_edx; 9397c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 9408949bcd6Sandrei struct cpuid_regs *cp; 9417c478bd9Sstevel@tonic-gate int xcpuid; 942843e1988Sjohnlev #if !defined(__xpv) 9435b8a6efeSbholler extern int idle_cpu_prefer_mwait; 944843e1988Sjohnlev #endif 945ae115bc7Smrj 9467c478bd9Sstevel@tonic-gate /* 947a3114836SGerry Liu * Space statically allocated for BSP, ensure pointer is set 9487c478bd9Sstevel@tonic-gate */ 9497417cfdeSKuriakose Kuruvilla if (cpu->cpu_id == 0) { 9507417cfdeSKuriakose Kuruvilla if (cpu->cpu_m.mcpu_cpi == NULL) 951ae115bc7Smrj cpu->cpu_m.mcpu_cpi = &cpuid_info0; 9527417cfdeSKuriakose Kuruvilla } 9537417cfdeSKuriakose Kuruvilla 9547417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CPUID); 9557417cfdeSKuriakose Kuruvilla 956ae115bc7Smrj cpi = cpu->cpu_m.mcpu_cpi; 957ae115bc7Smrj ASSERT(cpi != NULL); 9587c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[0]; 9598949bcd6Sandrei cp->cp_eax = 0; 9608949bcd6Sandrei cpi->cpi_maxeax = __cpuid_insn(cp); 9617c478bd9Sstevel@tonic-gate { 9627c478bd9Sstevel@tonic-gate uint32_t *iptr = (uint32_t *)cpi->cpi_vendorstr; 9637c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ebx; 9647c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_edx; 9657c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ecx; 9667c478bd9Sstevel@tonic-gate *(char *)&cpi->cpi_vendorstr[12] = '\0'; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate 969e4b86885SCheng Sean Ye cpi->cpi_vendor = _cpuid_vendorstr_to_vendorcode(cpi->cpi_vendorstr); 9707c478bd9Sstevel@tonic-gate x86_vendor = cpi->cpi_vendor; /* for compatibility */ 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * Limit the range in case of weird hardware 9747c478bd9Sstevel@tonic-gate */ 9757c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax > CPI_MAXEAX_MAX) 9767c478bd9Sstevel@tonic-gate cpi->cpi_maxeax = CPI_MAXEAX_MAX; 9777c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax < 1) 9787c478bd9Sstevel@tonic-gate goto pass1_done; 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[1]; 9818949bcd6Sandrei cp->cp_eax = 1; 9828949bcd6Sandrei (void) __cpuid_insn(cp); 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate /* 9857c478bd9Sstevel@tonic-gate * Extract identifying constants for easy access. 9867c478bd9Sstevel@tonic-gate */ 9877c478bd9Sstevel@tonic-gate cpi->cpi_model = CPI_MODEL(cpi); 9887c478bd9Sstevel@tonic-gate cpi->cpi_family = CPI_FAMILY(cpi); 9897c478bd9Sstevel@tonic-gate 9905ff02082Sdmick if (cpi->cpi_family == 0xf) 9917c478bd9Sstevel@tonic-gate cpi->cpi_family += CPI_FAMILY_XTD(cpi); 9925ff02082Sdmick 99368c91426Sdmick /* 994875b116eSkchow * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf. 99568c91426Sdmick * Intel, and presumably everyone else, uses model == 0xf, as 99668c91426Sdmick * one would expect (max value means possible overflow). Sigh. 99768c91426Sdmick */ 99868c91426Sdmick 99968c91426Sdmick switch (cpi->cpi_vendor) { 1000bf91205bSksadhukh case X86_VENDOR_Intel: 1001bf91205bSksadhukh if (IS_EXTENDED_MODEL_INTEL(cpi)) 1002bf91205bSksadhukh cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 1003447af253Sksadhukh break; 100468c91426Sdmick case X86_VENDOR_AMD: 1005875b116eSkchow if (CPI_FAMILY(cpi) == 0xf) 100668c91426Sdmick cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 100768c91426Sdmick break; 100868c91426Sdmick default: 10095ff02082Sdmick if (cpi->cpi_model == 0xf) 10107c478bd9Sstevel@tonic-gate cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 101168c91426Sdmick break; 101268c91426Sdmick } 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate cpi->cpi_step = CPI_STEP(cpi); 10157c478bd9Sstevel@tonic-gate cpi->cpi_brandid = CPI_BRANDID(cpi); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate /* 10187c478bd9Sstevel@tonic-gate * *default* assumptions: 10197c478bd9Sstevel@tonic-gate * - believe %edx feature word 10207c478bd9Sstevel@tonic-gate * - ignore %ecx feature word 10217c478bd9Sstevel@tonic-gate * - 32-bit virtual and physical addressing 10227c478bd9Sstevel@tonic-gate */ 10237c478bd9Sstevel@tonic-gate mask_edx = 0xffffffff; 10247c478bd9Sstevel@tonic-gate mask_ecx = 0; 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate cpi->cpi_pabits = cpi->cpi_vabits = 32; 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 10297c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 10307c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) 10317c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P5; 10325ff02082Sdmick else if (IS_LEGACY_P6(cpi)) { 10337c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P6; 10347c478bd9Sstevel@tonic-gate pentiumpro_bug4046376 = 1; 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Clear the SEP bit when it was set erroneously 10377c478bd9Sstevel@tonic-gate */ 10387c478bd9Sstevel@tonic-gate if (cpi->cpi_model < 3 && cpi->cpi_step < 3) 10397c478bd9Sstevel@tonic-gate cp->cp_edx &= ~CPUID_INTC_EDX_SEP; 10405ff02082Sdmick } else if (IS_NEW_F6(cpi) || cpi->cpi_family == 0xf) { 10417c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P4; 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * We don't currently depend on any of the %ecx 10447c478bd9Sstevel@tonic-gate * features until Prescott, so we'll only check 10457c478bd9Sstevel@tonic-gate * this from P4 onwards. We might want to revisit 10467c478bd9Sstevel@tonic-gate * that idea later. 10477c478bd9Sstevel@tonic-gate */ 10487c478bd9Sstevel@tonic-gate mask_ecx = 0xffffffff; 10497c478bd9Sstevel@tonic-gate } else if (cpi->cpi_family > 0xf) 10507c478bd9Sstevel@tonic-gate mask_ecx = 0xffffffff; 10517c622d23Sbholler /* 10527c622d23Sbholler * We don't support MONITOR/MWAIT if leaf 5 is not available 10537c622d23Sbholler * to obtain the monitor linesize. 10547c622d23Sbholler */ 10557c622d23Sbholler if (cpi->cpi_maxeax < 5) 10567c622d23Sbholler mask_ecx &= ~CPUID_INTC_ECX_MON; 10577c478bd9Sstevel@tonic-gate break; 10587c478bd9Sstevel@tonic-gate case X86_VENDOR_IntelClone: 10597c478bd9Sstevel@tonic-gate default: 10607c478bd9Sstevel@tonic-gate break; 10617c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 10627c478bd9Sstevel@tonic-gate #if defined(OPTERON_ERRATUM_108) 10637c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 0xf && cpi->cpi_model == 0xe) { 10647c478bd9Sstevel@tonic-gate cp->cp_eax = (0xf0f & cp->cp_eax) | 0xc0; 10657c478bd9Sstevel@tonic-gate cpi->cpi_model = 0xc; 10667c478bd9Sstevel@tonic-gate } else 10677c478bd9Sstevel@tonic-gate #endif 10687c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) { 10697c478bd9Sstevel@tonic-gate /* 10707c478bd9Sstevel@tonic-gate * AMD K5 and K6 10717c478bd9Sstevel@tonic-gate * 10727c478bd9Sstevel@tonic-gate * These CPUs have an incomplete implementation 10737c478bd9Sstevel@tonic-gate * of MCA/MCE which we mask away. 10747c478bd9Sstevel@tonic-gate */ 10758949bcd6Sandrei mask_edx &= ~(CPUID_INTC_EDX_MCE | CPUID_INTC_EDX_MCA); 10768949bcd6Sandrei 10777c478bd9Sstevel@tonic-gate /* 10787c478bd9Sstevel@tonic-gate * Model 0 uses the wrong (APIC) bit 10797c478bd9Sstevel@tonic-gate * to indicate PGE. Fix it here. 10807c478bd9Sstevel@tonic-gate */ 10818949bcd6Sandrei if (cpi->cpi_model == 0) { 10827c478bd9Sstevel@tonic-gate if (cp->cp_edx & 0x200) { 10837c478bd9Sstevel@tonic-gate cp->cp_edx &= ~0x200; 10847c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_PGE; 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate } 10878949bcd6Sandrei 10888949bcd6Sandrei /* 10898949bcd6Sandrei * Early models had problems w/ MMX; disable. 10908949bcd6Sandrei */ 10918949bcd6Sandrei if (cpi->cpi_model < 6) 10928949bcd6Sandrei mask_edx &= ~CPUID_INTC_EDX_MMX; 10938949bcd6Sandrei } 10948949bcd6Sandrei 10958949bcd6Sandrei /* 10968949bcd6Sandrei * For newer families, SSE3 and CX16, at least, are valid; 10978949bcd6Sandrei * enable all 10988949bcd6Sandrei */ 10998949bcd6Sandrei if (cpi->cpi_family >= 0xf) 11008949bcd6Sandrei mask_ecx = 0xffffffff; 11017c622d23Sbholler /* 11027c622d23Sbholler * We don't support MONITOR/MWAIT if leaf 5 is not available 11037c622d23Sbholler * to obtain the monitor linesize. 11047c622d23Sbholler */ 11057c622d23Sbholler if (cpi->cpi_maxeax < 5) 11067c622d23Sbholler mask_ecx &= ~CPUID_INTC_ECX_MON; 11075b8a6efeSbholler 1108843e1988Sjohnlev #if !defined(__xpv) 11095b8a6efeSbholler /* 11105b8a6efeSbholler * Do not use MONITOR/MWAIT to halt in the idle loop on any AMD 11115b8a6efeSbholler * processors. AMD does not intend MWAIT to be used in the cpu 11125b8a6efeSbholler * idle loop on current and future processors. 10h and future 11135b8a6efeSbholler * AMD processors use more power in MWAIT than HLT. 11145b8a6efeSbholler * Pre-family-10h Opterons do not have the MWAIT instruction. 11155b8a6efeSbholler */ 11165b8a6efeSbholler idle_cpu_prefer_mwait = 0; 1117843e1988Sjohnlev #endif 11185b8a6efeSbholler 11197c478bd9Sstevel@tonic-gate break; 11207c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 11217c478bd9Sstevel@tonic-gate /* 11227c478bd9Sstevel@tonic-gate * workaround the NT workaround in CMS 4.1 11237c478bd9Sstevel@tonic-gate */ 11247c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 4 && 11257c478bd9Sstevel@tonic-gate (cpi->cpi_step == 2 || cpi->cpi_step == 3)) 11267c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_CX8; 11277c478bd9Sstevel@tonic-gate break; 11287c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 11297c478bd9Sstevel@tonic-gate /* 11307c478bd9Sstevel@tonic-gate * workaround the NT workarounds again 11317c478bd9Sstevel@tonic-gate */ 11327c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 6) 11337c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_CX8; 11347c478bd9Sstevel@tonic-gate break; 11357c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * We rely heavily on the probing in locore 11387c478bd9Sstevel@tonic-gate * to actually figure out what parts, if any, 11397c478bd9Sstevel@tonic-gate * of the Cyrix cpuid instruction to believe. 11407c478bd9Sstevel@tonic-gate */ 11417c478bd9Sstevel@tonic-gate switch (x86_type) { 11427c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_486: 11437c478bd9Sstevel@tonic-gate mask_edx = 0; 11447c478bd9Sstevel@tonic-gate break; 11457c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86: 11467c478bd9Sstevel@tonic-gate mask_edx = 0; 11477c478bd9Sstevel@tonic-gate break; 11487c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86L: 11497c478bd9Sstevel@tonic-gate mask_edx = 11507c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 11517c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8; 11527c478bd9Sstevel@tonic-gate break; 11537c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86MX: 11547c478bd9Sstevel@tonic-gate mask_edx = 11557c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 11567c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 11577c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 11587c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_PGE | 11597c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 11607c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 11617c478bd9Sstevel@tonic-gate break; 11627c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_GXm: 11637c478bd9Sstevel@tonic-gate mask_edx = 11647c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 11657c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 11667c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 11677c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 11687c478bd9Sstevel@tonic-gate break; 11697c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MediaGX: 11707c478bd9Sstevel@tonic-gate break; 11717c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MII: 11727c478bd9Sstevel@tonic-gate case X86_TYPE_VIA_CYRIX_III: 11737c478bd9Sstevel@tonic-gate mask_edx = 11747c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 11757c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_TSC | 11767c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 11777c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 11787c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_PGE | 11797c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 11807c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 11817c478bd9Sstevel@tonic-gate break; 11827c478bd9Sstevel@tonic-gate default: 11837c478bd9Sstevel@tonic-gate break; 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate break; 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 1188843e1988Sjohnlev #if defined(__xpv) 1189843e1988Sjohnlev /* 1190843e1988Sjohnlev * Do not support MONITOR/MWAIT under a hypervisor 1191843e1988Sjohnlev */ 1192843e1988Sjohnlev mask_ecx &= ~CPUID_INTC_ECX_MON; 11937af88ac7SKuriakose Kuruvilla /* 11947af88ac7SKuriakose Kuruvilla * Do not support XSAVE under a hypervisor for now 11957af88ac7SKuriakose Kuruvilla */ 11967af88ac7SKuriakose Kuruvilla xsave_force_disable = B_TRUE; 11977af88ac7SKuriakose Kuruvilla 1198843e1988Sjohnlev #endif /* __xpv */ 1199843e1988Sjohnlev 12007af88ac7SKuriakose Kuruvilla if (xsave_force_disable) { 12017af88ac7SKuriakose Kuruvilla mask_ecx &= ~CPUID_INTC_ECX_XSAVE; 12027af88ac7SKuriakose Kuruvilla mask_ecx &= ~CPUID_INTC_ECX_AVX; 1203ebb8ac07SRobert Mustacchi mask_ecx &= ~CPUID_INTC_ECX_F16C; 12047af88ac7SKuriakose Kuruvilla } 12057af88ac7SKuriakose Kuruvilla 12067c478bd9Sstevel@tonic-gate /* 12077c478bd9Sstevel@tonic-gate * Now we've figured out the masks that determine 12087c478bd9Sstevel@tonic-gate * which bits we choose to believe, apply the masks 12097c478bd9Sstevel@tonic-gate * to the feature words, then map the kernel's view 12107c478bd9Sstevel@tonic-gate * of these feature words into its feature word. 12117c478bd9Sstevel@tonic-gate */ 12127c478bd9Sstevel@tonic-gate cp->cp_edx &= mask_edx; 12137c478bd9Sstevel@tonic-gate cp->cp_ecx &= mask_ecx; 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate /* 1216ae115bc7Smrj * apply any platform restrictions (we don't call this 1217ae115bc7Smrj * immediately after __cpuid_insn here, because we need the 1218ae115bc7Smrj * workarounds applied above first) 12197c478bd9Sstevel@tonic-gate */ 1220ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 1, cp); 12217c478bd9Sstevel@tonic-gate 1222ae115bc7Smrj /* 1223ae115bc7Smrj * fold in overrides from the "eeprom" mechanism 1224ae115bc7Smrj */ 12257c478bd9Sstevel@tonic-gate cp->cp_edx |= cpuid_feature_edx_include; 12267c478bd9Sstevel@tonic-gate cp->cp_edx &= ~cpuid_feature_edx_exclude; 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate cp->cp_ecx |= cpuid_feature_ecx_include; 12297c478bd9Sstevel@tonic-gate cp->cp_ecx &= ~cpuid_feature_ecx_exclude; 12307c478bd9Sstevel@tonic-gate 12317417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PSE) { 12327417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_LARGEPAGE); 12337417cfdeSKuriakose Kuruvilla } 12347417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_TSC) { 12357417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_TSC); 12367417cfdeSKuriakose Kuruvilla } 12377417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MSR) { 12387417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MSR); 12397417cfdeSKuriakose Kuruvilla } 12407417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MTRR) { 12417417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MTRR); 12427417cfdeSKuriakose Kuruvilla } 12437417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PGE) { 12447417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PGE); 12457417cfdeSKuriakose Kuruvilla } 12467417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_CMOV) { 12477417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMOV); 12487417cfdeSKuriakose Kuruvilla } 12497417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MMX) { 12507417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MMX); 12517417cfdeSKuriakose Kuruvilla } 12527c478bd9Sstevel@tonic-gate if ((cp->cp_edx & CPUID_INTC_EDX_MCE) != 0 && 12537417cfdeSKuriakose Kuruvilla (cp->cp_edx & CPUID_INTC_EDX_MCA) != 0) { 12547417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MCA); 12557417cfdeSKuriakose Kuruvilla } 12567417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PAE) { 12577417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PAE); 12587417cfdeSKuriakose Kuruvilla } 12597417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_CX8) { 12607417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CX8); 12617417cfdeSKuriakose Kuruvilla } 12627417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_CX16) { 12637417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CX16); 12647417cfdeSKuriakose Kuruvilla } 12657417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PAT) { 12667417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PAT); 12677417cfdeSKuriakose Kuruvilla } 12687417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SEP) { 12697417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SEP); 12707417cfdeSKuriakose Kuruvilla } 12717c478bd9Sstevel@tonic-gate if (cp->cp_edx & CPUID_INTC_EDX_FXSR) { 12727c478bd9Sstevel@tonic-gate /* 12737c478bd9Sstevel@tonic-gate * In our implementation, fxsave/fxrstor 12747c478bd9Sstevel@tonic-gate * are prerequisites before we'll even 12757c478bd9Sstevel@tonic-gate * try and do SSE things. 12767c478bd9Sstevel@tonic-gate */ 12777417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SSE) { 12787417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE); 12797417cfdeSKuriakose Kuruvilla } 12807417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SSE2) { 12817417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE2); 12827417cfdeSKuriakose Kuruvilla } 12837417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) { 12847417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE3); 12857417cfdeSKuriakose Kuruvilla } 12867417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) { 12877417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSSE3); 12887417cfdeSKuriakose Kuruvilla } 12897417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) { 12907417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4_1); 12917417cfdeSKuriakose Kuruvilla } 12927417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) { 12937417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4_2); 12947417cfdeSKuriakose Kuruvilla } 12957417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_AES) { 12967417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_AES); 12977417cfdeSKuriakose Kuruvilla } 12987417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) { 12997417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PCLMULQDQ); 1300d0f8ff6eSkk208521 } 13017af88ac7SKuriakose Kuruvilla 13027af88ac7SKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) { 13037af88ac7SKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_XSAVE); 1304ebb8ac07SRobert Mustacchi 13057af88ac7SKuriakose Kuruvilla /* We only test AVX when there is XSAVE */ 13067af88ac7SKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_AVX) { 13077af88ac7SKuriakose Kuruvilla add_x86_feature(featureset, 13087af88ac7SKuriakose Kuruvilla X86FSET_AVX); 1309ebb8ac07SRobert Mustacchi 1310ebb8ac07SRobert Mustacchi if (cp->cp_ecx & CPUID_INTC_ECX_F16C) 1311ebb8ac07SRobert Mustacchi add_x86_feature(featureset, 1312ebb8ac07SRobert Mustacchi X86FSET_F16C); 13137af88ac7SKuriakose Kuruvilla } 13147af88ac7SKuriakose Kuruvilla } 13157c478bd9Sstevel@tonic-gate } 1316*6eedf6a5SJosef 'Jeff' Sipek if (cp->cp_ecx & CPUID_INTC_ECX_X2APIC) { 1317*6eedf6a5SJosef 'Jeff' Sipek add_x86_feature(featureset, X86FSET_X2APIC); 1318*6eedf6a5SJosef 'Jeff' Sipek } 13197417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_DE) { 13207417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_DE); 13217417cfdeSKuriakose Kuruvilla } 13221d1a3942SBill Holler #if !defined(__xpv) 1323f98fbcecSbholler if (cp->cp_ecx & CPUID_INTC_ECX_MON) { 13241d1a3942SBill Holler 13251d1a3942SBill Holler /* 13261d1a3942SBill Holler * We require the CLFLUSH instruction for erratum workaround 13271d1a3942SBill Holler * to use MONITOR/MWAIT. 13281d1a3942SBill Holler */ 13291d1a3942SBill Holler if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) { 1330f98fbcecSbholler cpi->cpi_mwait.support |= MWAIT_SUPPORT; 13317417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MWAIT); 13321d1a3942SBill Holler } else { 13331d1a3942SBill Holler extern int idle_cpu_assert_cflush_monitor; 13341d1a3942SBill Holler 13351d1a3942SBill Holler /* 13361d1a3942SBill Holler * All processors we are aware of which have 13371d1a3942SBill Holler * MONITOR/MWAIT also have CLFLUSH. 13381d1a3942SBill Holler */ 13391d1a3942SBill Holler if (idle_cpu_assert_cflush_monitor) { 13401d1a3942SBill Holler ASSERT((cp->cp_ecx & CPUID_INTC_ECX_MON) && 13411d1a3942SBill Holler (cp->cp_edx & CPUID_INTC_EDX_CLFSH)); 1342f98fbcecSbholler } 13431d1a3942SBill Holler } 13441d1a3942SBill Holler } 13451d1a3942SBill Holler #endif /* __xpv */ 13467c478bd9Sstevel@tonic-gate 1347faa20166SBryan Cantrill if (cp->cp_ecx & CPUID_INTC_ECX_VMX) { 1348faa20166SBryan Cantrill add_x86_feature(featureset, X86FSET_VMX); 1349faa20166SBryan Cantrill } 1350faa20166SBryan Cantrill 1351ebb8ac07SRobert Mustacchi if (cp->cp_ecx & CPUID_INTC_ECX_RDRAND) 1352ebb8ac07SRobert Mustacchi add_x86_feature(featureset, X86FSET_RDRAND); 1353ebb8ac07SRobert Mustacchi 135486c1f4dcSVikram Hegde /* 1355faa20166SBryan Cantrill * Only need it first time, rest of the cpus would follow suit. 135686c1f4dcSVikram Hegde * we only capture this for the bootcpu. 135786c1f4dcSVikram Hegde */ 135886c1f4dcSVikram Hegde if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) { 13597417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CLFSH); 136086c1f4dcSVikram Hegde x86_clflush_size = (BITX(cp->cp_ebx, 15, 8) * 8); 136186c1f4dcSVikram Hegde } 13627417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, X86FSET_PAE)) 13637c478bd9Sstevel@tonic-gate cpi->cpi_pabits = 36; 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate /* 13667c478bd9Sstevel@tonic-gate * Hyperthreading configuration is slightly tricky on Intel 13677c478bd9Sstevel@tonic-gate * and pure clones, and even trickier on AMD. 13687c478bd9Sstevel@tonic-gate * 13697c478bd9Sstevel@tonic-gate * (AMD chose to set the HTT bit on their CMP processors, 13707c478bd9Sstevel@tonic-gate * even though they're not actually hyperthreaded. Thus it 13717c478bd9Sstevel@tonic-gate * takes a bit more work to figure out what's really going 1372ae115bc7Smrj * on ... see the handling of the CMP_LGCY bit below) 13737c478bd9Sstevel@tonic-gate */ 13747c478bd9Sstevel@tonic-gate if (cp->cp_edx & CPUID_INTC_EDX_HTT) { 13757c478bd9Sstevel@tonic-gate cpi->cpi_ncpu_per_chip = CPI_CPU_COUNT(cpi); 13767c478bd9Sstevel@tonic-gate if (cpi->cpi_ncpu_per_chip > 1) 13777417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_HTT); 13788949bcd6Sandrei } else { 13798949bcd6Sandrei cpi->cpi_ncpu_per_chip = 1; 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate /* 13837c478bd9Sstevel@tonic-gate * Work on the "extended" feature information, doing 13847c478bd9Sstevel@tonic-gate * some basic initialization for cpuid_pass2() 13857c478bd9Sstevel@tonic-gate */ 13867c478bd9Sstevel@tonic-gate xcpuid = 0; 13877c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 13887c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 13895ff02082Sdmick if (IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf) 13907c478bd9Sstevel@tonic-gate xcpuid++; 13917c478bd9Sstevel@tonic-gate break; 13927c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 13937c478bd9Sstevel@tonic-gate if (cpi->cpi_family > 5 || 13947c478bd9Sstevel@tonic-gate (cpi->cpi_family == 5 && cpi->cpi_model >= 1)) 13957c478bd9Sstevel@tonic-gate xcpuid++; 13967c478bd9Sstevel@tonic-gate break; 13977c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 13987c478bd9Sstevel@tonic-gate /* 13997c478bd9Sstevel@tonic-gate * Only these Cyrix CPUs are -known- to support 14007c478bd9Sstevel@tonic-gate * extended cpuid operations. 14017c478bd9Sstevel@tonic-gate */ 14027c478bd9Sstevel@tonic-gate if (x86_type == X86_TYPE_VIA_CYRIX_III || 14037c478bd9Sstevel@tonic-gate x86_type == X86_TYPE_CYRIX_GXm) 14047c478bd9Sstevel@tonic-gate xcpuid++; 14057c478bd9Sstevel@tonic-gate break; 14067c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 14077c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 14087c478bd9Sstevel@tonic-gate default: 14097c478bd9Sstevel@tonic-gate xcpuid++; 14107c478bd9Sstevel@tonic-gate break; 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate if (xcpuid) { 14147c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[0]; 14158949bcd6Sandrei cp->cp_eax = 0x80000000; 14168949bcd6Sandrei cpi->cpi_xmaxeax = __cpuid_insn(cp); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax & 0x80000000) { 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax > CPI_XMAXEAX_MAX) 14227c478bd9Sstevel@tonic-gate cpi->cpi_xmaxeax = CPI_XMAXEAX_MAX; 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 14257c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 14267c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 14277c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000001) 14287c478bd9Sstevel@tonic-gate break; 14297c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[1]; 14308949bcd6Sandrei cp->cp_eax = 0x80000001; 14318949bcd6Sandrei (void) __cpuid_insn(cp); 1432ae115bc7Smrj 14337c478bd9Sstevel@tonic-gate if (cpi->cpi_vendor == X86_VENDOR_AMD && 14347c478bd9Sstevel@tonic-gate cpi->cpi_family == 5 && 14357c478bd9Sstevel@tonic-gate cpi->cpi_model == 6 && 14367c478bd9Sstevel@tonic-gate cpi->cpi_step == 6) { 14377c478bd9Sstevel@tonic-gate /* 14387c478bd9Sstevel@tonic-gate * K6 model 6 uses bit 10 to indicate SYSC 14397c478bd9Sstevel@tonic-gate * Later models use bit 11. Fix it here. 14407c478bd9Sstevel@tonic-gate */ 14417c478bd9Sstevel@tonic-gate if (cp->cp_edx & 0x400) { 14427c478bd9Sstevel@tonic-gate cp->cp_edx &= ~0x400; 14437c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_AMD_EDX_SYSC; 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 1447ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000001, cp); 1448ae115bc7Smrj 14497c478bd9Sstevel@tonic-gate /* 14507c478bd9Sstevel@tonic-gate * Compute the additions to the kernel's feature word. 14517c478bd9Sstevel@tonic-gate */ 14527417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_NX) { 14537417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_NX); 14547417cfdeSKuriakose Kuruvilla } 14557c478bd9Sstevel@tonic-gate 145619397407SSherry Moore /* 145719397407SSherry Moore * Regardless whether or not we boot 64-bit, 145819397407SSherry Moore * we should have a way to identify whether 145919397407SSherry Moore * the CPU is capable of running 64-bit. 146019397407SSherry Moore */ 14617417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_LM) { 14627417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_64); 14637417cfdeSKuriakose Kuruvilla } 146419397407SSherry Moore 146502bc52beSkchow #if defined(__amd64) 146602bc52beSkchow /* 1 GB large page - enable only for 64 bit kernel */ 14677417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_1GPG) { 14687417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_1GPG); 14697417cfdeSKuriakose Kuruvilla } 147002bc52beSkchow #endif 147102bc52beSkchow 1472f8801251Skk208521 if ((cpi->cpi_vendor == X86_VENDOR_AMD) && 1473f8801251Skk208521 (cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_FXSR) && 14747417cfdeSKuriakose Kuruvilla (cp->cp_ecx & CPUID_AMD_ECX_SSE4A)) { 14757417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4A); 14767417cfdeSKuriakose Kuruvilla } 1477f8801251Skk208521 14787c478bd9Sstevel@tonic-gate /* 1479ae115bc7Smrj * If both the HTT and CMP_LGCY bits are set, 14808949bcd6Sandrei * then we're not actually HyperThreaded. Read 14818949bcd6Sandrei * "AMD CPUID Specification" for more details. 14827c478bd9Sstevel@tonic-gate */ 14837c478bd9Sstevel@tonic-gate if (cpi->cpi_vendor == X86_VENDOR_AMD && 14847417cfdeSKuriakose Kuruvilla is_x86_feature(featureset, X86FSET_HTT) && 1485ae115bc7Smrj (cp->cp_ecx & CPUID_AMD_ECX_CMP_LGCY)) { 14867417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_HTT); 14877417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMP); 14888949bcd6Sandrei } 1489ae115bc7Smrj #if defined(__amd64) 14907c478bd9Sstevel@tonic-gate /* 14917c478bd9Sstevel@tonic-gate * It's really tricky to support syscall/sysret in 14927c478bd9Sstevel@tonic-gate * the i386 kernel; we rely on sysenter/sysexit 14937c478bd9Sstevel@tonic-gate * instead. In the amd64 kernel, things are -way- 14947c478bd9Sstevel@tonic-gate * better. 14957c478bd9Sstevel@tonic-gate */ 14967417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_SYSC) { 14977417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_ASYSC); 14987417cfdeSKuriakose Kuruvilla } 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate /* 15017c478bd9Sstevel@tonic-gate * While we're thinking about system calls, note 15027c478bd9Sstevel@tonic-gate * that AMD processors don't support sysenter 15037c478bd9Sstevel@tonic-gate * in long mode at all, so don't try to program them. 15047c478bd9Sstevel@tonic-gate */ 15057417cfdeSKuriakose Kuruvilla if (x86_vendor == X86_VENDOR_AMD) { 15067417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_SEP); 15077417cfdeSKuriakose Kuruvilla } 15087c478bd9Sstevel@tonic-gate #endif 15097417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_TSCP) { 15107417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_TSCP); 15117417cfdeSKuriakose Kuruvilla } 1512faa20166SBryan Cantrill 1513faa20166SBryan Cantrill if (cp->cp_ecx & CPUID_AMD_ECX_SVM) { 1514faa20166SBryan Cantrill add_x86_feature(featureset, X86FSET_SVM); 1515faa20166SBryan Cantrill } 15167660e73fSHans Rosenfeld 15177660e73fSHans Rosenfeld if (cp->cp_ecx & CPUID_AMD_ECX_TOPOEXT) { 15187660e73fSHans Rosenfeld add_x86_feature(featureset, X86FSET_TOPOEXT); 15197660e73fSHans Rosenfeld } 15207c478bd9Sstevel@tonic-gate break; 15217c478bd9Sstevel@tonic-gate default: 15227c478bd9Sstevel@tonic-gate break; 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate 15258949bcd6Sandrei /* 15268949bcd6Sandrei * Get CPUID data about processor cores and hyperthreads. 15278949bcd6Sandrei */ 15287c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 15297c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 15308949bcd6Sandrei if (cpi->cpi_maxeax >= 4) { 15318949bcd6Sandrei cp = &cpi->cpi_std[4]; 15328949bcd6Sandrei cp->cp_eax = 4; 15338949bcd6Sandrei cp->cp_ecx = 0; 15348949bcd6Sandrei (void) __cpuid_insn(cp); 1535ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 4, cp); 15368949bcd6Sandrei } 15378949bcd6Sandrei /*FALLTHROUGH*/ 15387c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 15397c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000008) 15407c478bd9Sstevel@tonic-gate break; 15417c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[8]; 15428949bcd6Sandrei cp->cp_eax = 0x80000008; 15438949bcd6Sandrei (void) __cpuid_insn(cp); 1544ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000008, cp); 1545ae115bc7Smrj 15467c478bd9Sstevel@tonic-gate /* 15477c478bd9Sstevel@tonic-gate * Virtual and physical address limits from 15487c478bd9Sstevel@tonic-gate * cpuid override previously guessed values. 15497c478bd9Sstevel@tonic-gate */ 15507c478bd9Sstevel@tonic-gate cpi->cpi_pabits = BITX(cp->cp_eax, 7, 0); 15517c478bd9Sstevel@tonic-gate cpi->cpi_vabits = BITX(cp->cp_eax, 15, 8); 15527c478bd9Sstevel@tonic-gate break; 15537c478bd9Sstevel@tonic-gate default: 15547c478bd9Sstevel@tonic-gate break; 15557c478bd9Sstevel@tonic-gate } 15568949bcd6Sandrei 1557d129bde2Sesaxe /* 1558d129bde2Sesaxe * Derive the number of cores per chip 1559d129bde2Sesaxe */ 15608949bcd6Sandrei switch (cpi->cpi_vendor) { 15618949bcd6Sandrei case X86_VENDOR_Intel: 15628949bcd6Sandrei if (cpi->cpi_maxeax < 4) { 15638949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 15648949bcd6Sandrei break; 15658949bcd6Sandrei } else { 15668949bcd6Sandrei cpi->cpi_ncore_per_chip = 15678949bcd6Sandrei BITX((cpi)->cpi_std[4].cp_eax, 31, 26) + 1; 15688949bcd6Sandrei } 15698949bcd6Sandrei break; 15708949bcd6Sandrei case X86_VENDOR_AMD: 15718949bcd6Sandrei if (cpi->cpi_xmaxeax < 0x80000008) { 15728949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 15738949bcd6Sandrei break; 15748949bcd6Sandrei } else { 157510569901Sgavinm /* 157610569901Sgavinm * On family 0xf cpuid fn 2 ECX[7:0] "NC" is 157710569901Sgavinm * 1 less than the number of physical cores on 157810569901Sgavinm * the chip. In family 0x10 this value can 157910569901Sgavinm * be affected by "downcoring" - it reflects 158010569901Sgavinm * 1 less than the number of cores actually 158110569901Sgavinm * enabled on this node. 158210569901Sgavinm */ 15838949bcd6Sandrei cpi->cpi_ncore_per_chip = 15848949bcd6Sandrei BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1; 15858949bcd6Sandrei } 15868949bcd6Sandrei break; 15878949bcd6Sandrei default: 15888949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 15898949bcd6Sandrei break; 15907c478bd9Sstevel@tonic-gate } 15910e751525SEric Saxe 15920e751525SEric Saxe /* 15930e751525SEric Saxe * Get CPUID data about TSC Invariance in Deep C-State. 15940e751525SEric Saxe */ 15950e751525SEric Saxe switch (cpi->cpi_vendor) { 15960e751525SEric Saxe case X86_VENDOR_Intel: 15970e751525SEric Saxe if (cpi->cpi_maxeax >= 7) { 15980e751525SEric Saxe cp = &cpi->cpi_extd[7]; 15990e751525SEric Saxe cp->cp_eax = 0x80000007; 16000e751525SEric Saxe cp->cp_ecx = 0; 16010e751525SEric Saxe (void) __cpuid_insn(cp); 16020e751525SEric Saxe } 16030e751525SEric Saxe break; 16040e751525SEric Saxe default: 16050e751525SEric Saxe break; 16060e751525SEric Saxe } 1607fa2e767eSgavinm } else { 1608fa2e767eSgavinm cpi->cpi_ncore_per_chip = 1; 16098949bcd6Sandrei } 16108949bcd6Sandrei 16118949bcd6Sandrei /* 16128949bcd6Sandrei * If more than one core, then this processor is CMP. 16138949bcd6Sandrei */ 16147417cfdeSKuriakose Kuruvilla if (cpi->cpi_ncore_per_chip > 1) { 16157417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMP); 16167417cfdeSKuriakose Kuruvilla } 1617ae115bc7Smrj 16188949bcd6Sandrei /* 16198949bcd6Sandrei * If the number of cores is the same as the number 16208949bcd6Sandrei * of CPUs, then we cannot have HyperThreading. 16218949bcd6Sandrei */ 16227417cfdeSKuriakose Kuruvilla if (cpi->cpi_ncpu_per_chip == cpi->cpi_ncore_per_chip) { 16237417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_HTT); 16247417cfdeSKuriakose Kuruvilla } 16258949bcd6Sandrei 16268031591dSSrihari Venkatesan cpi->cpi_apicid = CPI_APIC_ID(cpi); 16278031591dSSrihari Venkatesan cpi->cpi_procnodes_per_pkg = 1; 16287660e73fSHans Rosenfeld cpi->cpi_cores_per_compunit = 1; 16297417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE && 16307417cfdeSKuriakose Kuruvilla is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) { 16318949bcd6Sandrei /* 16328949bcd6Sandrei * Single-core single-threaded processors. 16338949bcd6Sandrei */ 16347c478bd9Sstevel@tonic-gate cpi->cpi_chipid = -1; 16357c478bd9Sstevel@tonic-gate cpi->cpi_clogid = 0; 16368949bcd6Sandrei cpi->cpi_coreid = cpu->cpu_id; 163710569901Sgavinm cpi->cpi_pkgcoreid = 0; 16388031591dSSrihari Venkatesan if (cpi->cpi_vendor == X86_VENDOR_AMD) 16398031591dSSrihari Venkatesan cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 3, 0); 16408031591dSSrihari Venkatesan else 16418031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 16427c478bd9Sstevel@tonic-gate } else if (cpi->cpi_ncpu_per_chip > 1) { 16438031591dSSrihari Venkatesan if (cpi->cpi_vendor == X86_VENDOR_Intel) 16447417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu, featureset); 16458031591dSSrihari Venkatesan else if (cpi->cpi_vendor == X86_VENDOR_AMD) 16468031591dSSrihari Venkatesan cpuid_amd_getids(cpu); 16478031591dSSrihari Venkatesan else { 16488949bcd6Sandrei /* 16498949bcd6Sandrei * All other processors are currently 16508949bcd6Sandrei * assumed to have single cores. 16518949bcd6Sandrei */ 16528949bcd6Sandrei cpi->cpi_coreid = cpi->cpi_chipid; 165310569901Sgavinm cpi->cpi_pkgcoreid = 0; 16548031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 16557660e73fSHans Rosenfeld cpi->cpi_compunitid = cpi->cpi_chipid; 16568949bcd6Sandrei } 16577c478bd9Sstevel@tonic-gate } 16587c478bd9Sstevel@tonic-gate 16598a40a695Sgavinm /* 16608a40a695Sgavinm * Synthesize chip "revision" and socket type 16618a40a695Sgavinm */ 1662e4b86885SCheng Sean Ye cpi->cpi_chiprev = _cpuid_chiprev(cpi->cpi_vendor, cpi->cpi_family, 1663e4b86885SCheng Sean Ye cpi->cpi_model, cpi->cpi_step); 1664e4b86885SCheng Sean Ye cpi->cpi_chiprevstr = _cpuid_chiprevstr(cpi->cpi_vendor, 1665e4b86885SCheng Sean Ye cpi->cpi_family, cpi->cpi_model, cpi->cpi_step); 1666e4b86885SCheng Sean Ye cpi->cpi_socket = _cpuid_skt(cpi->cpi_vendor, cpi->cpi_family, 1667e4b86885SCheng Sean Ye cpi->cpi_model, cpi->cpi_step); 16688a40a695Sgavinm 16697c478bd9Sstevel@tonic-gate pass1_done: 16707c478bd9Sstevel@tonic-gate cpi->cpi_pass = 1; 16717c478bd9Sstevel@tonic-gate } 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate /* 16747c478bd9Sstevel@tonic-gate * Make copies of the cpuid table entries we depend on, in 16757c478bd9Sstevel@tonic-gate * part for ease of parsing now, in part so that we have only 16767c478bd9Sstevel@tonic-gate * one place to correct any of it, in part for ease of 16777c478bd9Sstevel@tonic-gate * later export to userland, and in part so we can look at 16787c478bd9Sstevel@tonic-gate * this stuff in a crash dump. 16797c478bd9Sstevel@tonic-gate */ 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16827c478bd9Sstevel@tonic-gate void 16837c478bd9Sstevel@tonic-gate cpuid_pass2(cpu_t *cpu) 16847c478bd9Sstevel@tonic-gate { 16857c478bd9Sstevel@tonic-gate uint_t n, nmax; 16867c478bd9Sstevel@tonic-gate int i; 16878949bcd6Sandrei struct cpuid_regs *cp; 16887c478bd9Sstevel@tonic-gate uint8_t *dp; 16897c478bd9Sstevel@tonic-gate uint32_t *iptr; 16907c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 1); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax < 1) 16957c478bd9Sstevel@tonic-gate goto pass2_done; 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate if ((nmax = cpi->cpi_maxeax + 1) > NMAX_CPI_STD) 16987c478bd9Sstevel@tonic-gate nmax = NMAX_CPI_STD; 16997c478bd9Sstevel@tonic-gate /* 17007c478bd9Sstevel@tonic-gate * (We already handled n == 0 and n == 1 in pass 1) 17017c478bd9Sstevel@tonic-gate */ 17027c478bd9Sstevel@tonic-gate for (n = 2, cp = &cpi->cpi_std[2]; n < nmax; n++, cp++) { 17038949bcd6Sandrei cp->cp_eax = n; 1704d129bde2Sesaxe 1705d129bde2Sesaxe /* 1706d129bde2Sesaxe * CPUID function 4 expects %ecx to be initialized 1707d129bde2Sesaxe * with an index which indicates which cache to return 1708d129bde2Sesaxe * information about. The OS is expected to call function 4 1709d129bde2Sesaxe * with %ecx set to 0, 1, 2, ... until it returns with 1710d129bde2Sesaxe * EAX[4:0] set to 0, which indicates there are no more 1711d129bde2Sesaxe * caches. 1712d129bde2Sesaxe * 1713d129bde2Sesaxe * Here, populate cpi_std[4] with the information returned by 1714d129bde2Sesaxe * function 4 when %ecx == 0, and do the rest in cpuid_pass3() 1715d129bde2Sesaxe * when dynamic memory allocation becomes available. 1716d129bde2Sesaxe * 1717d129bde2Sesaxe * Note: we need to explicitly initialize %ecx here, since 1718d129bde2Sesaxe * function 4 may have been previously invoked. 1719d129bde2Sesaxe */ 1720d129bde2Sesaxe if (n == 4) 1721d129bde2Sesaxe cp->cp_ecx = 0; 1722d129bde2Sesaxe 17238949bcd6Sandrei (void) __cpuid_insn(cp); 1724ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, n, cp); 17257c478bd9Sstevel@tonic-gate switch (n) { 17267c478bd9Sstevel@tonic-gate case 2: 17277c478bd9Sstevel@tonic-gate /* 17287c478bd9Sstevel@tonic-gate * "the lower 8 bits of the %eax register 17297c478bd9Sstevel@tonic-gate * contain a value that identifies the number 17307c478bd9Sstevel@tonic-gate * of times the cpuid [instruction] has to be 17317c478bd9Sstevel@tonic-gate * executed to obtain a complete image of the 17327c478bd9Sstevel@tonic-gate * processor's caching systems." 17337c478bd9Sstevel@tonic-gate * 17347c478bd9Sstevel@tonic-gate * How *do* they make this stuff up? 17357c478bd9Sstevel@tonic-gate */ 17367c478bd9Sstevel@tonic-gate cpi->cpi_ncache = sizeof (*cp) * 17377c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 7, 0); 17387c478bd9Sstevel@tonic-gate if (cpi->cpi_ncache == 0) 17397c478bd9Sstevel@tonic-gate break; 17407c478bd9Sstevel@tonic-gate cpi->cpi_ncache--; /* skip count byte */ 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate /* 17437c478bd9Sstevel@tonic-gate * Well, for now, rather than attempt to implement 17447c478bd9Sstevel@tonic-gate * this slightly dubious algorithm, we just look 17457c478bd9Sstevel@tonic-gate * at the first 15 .. 17467c478bd9Sstevel@tonic-gate */ 17477c478bd9Sstevel@tonic-gate if (cpi->cpi_ncache > (sizeof (*cp) - 1)) 17487c478bd9Sstevel@tonic-gate cpi->cpi_ncache = sizeof (*cp) - 1; 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate dp = cpi->cpi_cacheinfo; 17517c478bd9Sstevel@tonic-gate if (BITX(cp->cp_eax, 31, 31) == 0) { 17527c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_eax; 175363d3f7dfSkk208521 for (i = 1; i < 4; i++) 17547c478bd9Sstevel@tonic-gate if (p[i] != 0) 17557c478bd9Sstevel@tonic-gate *dp++ = p[i]; 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ebx, 31, 31) == 0) { 17587c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_ebx; 17597c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 17607c478bd9Sstevel@tonic-gate if (p[i] != 0) 17617c478bd9Sstevel@tonic-gate *dp++ = p[i]; 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ecx, 31, 31) == 0) { 17647c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_ecx; 17657c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 17667c478bd9Sstevel@tonic-gate if (p[i] != 0) 17677c478bd9Sstevel@tonic-gate *dp++ = p[i]; 17687c478bd9Sstevel@tonic-gate } 17697c478bd9Sstevel@tonic-gate if (BITX(cp->cp_edx, 31, 31) == 0) { 17707c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_edx; 17717c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 17727c478bd9Sstevel@tonic-gate if (p[i] != 0) 17737c478bd9Sstevel@tonic-gate *dp++ = p[i]; 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate break; 1776f98fbcecSbholler 17777c478bd9Sstevel@tonic-gate case 3: /* Processor serial number, if PSN supported */ 1778f98fbcecSbholler break; 1779f98fbcecSbholler 17807c478bd9Sstevel@tonic-gate case 4: /* Deterministic cache parameters */ 1781f98fbcecSbholler break; 1782f98fbcecSbholler 17837c478bd9Sstevel@tonic-gate case 5: /* Monitor/Mwait parameters */ 17845b8a6efeSbholler { 17855b8a6efeSbholler size_t mwait_size; 1786f98fbcecSbholler 1787f98fbcecSbholler /* 1788f98fbcecSbholler * check cpi_mwait.support which was set in cpuid_pass1 1789f98fbcecSbholler */ 1790f98fbcecSbholler if (!(cpi->cpi_mwait.support & MWAIT_SUPPORT)) 1791f98fbcecSbholler break; 1792f98fbcecSbholler 17935b8a6efeSbholler /* 17945b8a6efeSbholler * Protect ourself from insane mwait line size. 17955b8a6efeSbholler * Workaround for incomplete hardware emulator(s). 17965b8a6efeSbholler */ 17975b8a6efeSbholler mwait_size = (size_t)MWAIT_SIZE_MAX(cpi); 17985b8a6efeSbholler if (mwait_size < sizeof (uint32_t) || 17995b8a6efeSbholler !ISP2(mwait_size)) { 18005b8a6efeSbholler #if DEBUG 18015b8a6efeSbholler cmn_err(CE_NOTE, "Cannot handle cpu %d mwait " 18025d8efbbcSSaurabh Misra "size %ld", cpu->cpu_id, (long)mwait_size); 18035b8a6efeSbholler #endif 18045b8a6efeSbholler break; 18055b8a6efeSbholler } 18065b8a6efeSbholler 1807f98fbcecSbholler cpi->cpi_mwait.mon_min = (size_t)MWAIT_SIZE_MIN(cpi); 18085b8a6efeSbholler cpi->cpi_mwait.mon_max = mwait_size; 1809f98fbcecSbholler if (MWAIT_EXTENSION(cpi)) { 1810f98fbcecSbholler cpi->cpi_mwait.support |= MWAIT_EXTENSIONS; 1811f98fbcecSbholler if (MWAIT_INT_ENABLE(cpi)) 1812f98fbcecSbholler cpi->cpi_mwait.support |= 1813f98fbcecSbholler MWAIT_ECX_INT_ENABLE; 1814f98fbcecSbholler } 1815f98fbcecSbholler break; 18165b8a6efeSbholler } 18177c478bd9Sstevel@tonic-gate default: 18187c478bd9Sstevel@tonic-gate break; 18197c478bd9Sstevel@tonic-gate } 18207c478bd9Sstevel@tonic-gate } 18217c478bd9Sstevel@tonic-gate 1822b6917abeSmishra if (cpi->cpi_maxeax >= 0xB && cpi->cpi_vendor == X86_VENDOR_Intel) { 18235d8efbbcSSaurabh Misra struct cpuid_regs regs; 18245d8efbbcSSaurabh Misra 18255d8efbbcSSaurabh Misra cp = ®s; 1826b6917abeSmishra cp->cp_eax = 0xB; 18275d8efbbcSSaurabh Misra cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 1828b6917abeSmishra 1829b6917abeSmishra (void) __cpuid_insn(cp); 1830b6917abeSmishra 1831b6917abeSmishra /* 1832b6917abeSmishra * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which 1833b6917abeSmishra * indicates that the extended topology enumeration leaf is 1834b6917abeSmishra * available. 1835b6917abeSmishra */ 1836b6917abeSmishra if (cp->cp_ebx) { 1837b6917abeSmishra uint32_t x2apic_id; 1838b6917abeSmishra uint_t coreid_shift = 0; 1839b6917abeSmishra uint_t ncpu_per_core = 1; 1840b6917abeSmishra uint_t chipid_shift = 0; 1841b6917abeSmishra uint_t ncpu_per_chip = 1; 1842b6917abeSmishra uint_t i; 1843b6917abeSmishra uint_t level; 1844b6917abeSmishra 1845b6917abeSmishra for (i = 0; i < CPI_FNB_ECX_MAX; i++) { 1846b6917abeSmishra cp->cp_eax = 0xB; 1847b6917abeSmishra cp->cp_ecx = i; 1848b6917abeSmishra 1849b6917abeSmishra (void) __cpuid_insn(cp); 1850b6917abeSmishra level = CPI_CPU_LEVEL_TYPE(cp); 1851b6917abeSmishra 1852b6917abeSmishra if (level == 1) { 1853b6917abeSmishra x2apic_id = cp->cp_edx; 1854b6917abeSmishra coreid_shift = BITX(cp->cp_eax, 4, 0); 1855b6917abeSmishra ncpu_per_core = BITX(cp->cp_ebx, 15, 0); 1856b6917abeSmishra } else if (level == 2) { 1857b6917abeSmishra x2apic_id = cp->cp_edx; 1858b6917abeSmishra chipid_shift = BITX(cp->cp_eax, 4, 0); 1859b6917abeSmishra ncpu_per_chip = BITX(cp->cp_ebx, 15, 0); 1860b6917abeSmishra } 1861b6917abeSmishra } 1862b6917abeSmishra 1863b6917abeSmishra cpi->cpi_apicid = x2apic_id; 1864b6917abeSmishra cpi->cpi_ncpu_per_chip = ncpu_per_chip; 1865b6917abeSmishra cpi->cpi_ncore_per_chip = ncpu_per_chip / 1866b6917abeSmishra ncpu_per_core; 1867b6917abeSmishra cpi->cpi_chipid = x2apic_id >> chipid_shift; 1868b6917abeSmishra cpi->cpi_clogid = x2apic_id & ((1 << chipid_shift) - 1); 1869b6917abeSmishra cpi->cpi_coreid = x2apic_id >> coreid_shift; 1870b6917abeSmishra cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift; 1871b6917abeSmishra } 18725d8efbbcSSaurabh Misra 18735d8efbbcSSaurabh Misra /* Make cp NULL so that we don't stumble on others */ 18745d8efbbcSSaurabh Misra cp = NULL; 1875b6917abeSmishra } 1876b6917abeSmishra 18777af88ac7SKuriakose Kuruvilla /* 18787af88ac7SKuriakose Kuruvilla * XSAVE enumeration 18797af88ac7SKuriakose Kuruvilla */ 188063408480SHans Rosenfeld if (cpi->cpi_maxeax >= 0xD) { 18817af88ac7SKuriakose Kuruvilla struct cpuid_regs regs; 18827af88ac7SKuriakose Kuruvilla boolean_t cpuid_d_valid = B_TRUE; 18837af88ac7SKuriakose Kuruvilla 18847af88ac7SKuriakose Kuruvilla cp = ®s; 18857af88ac7SKuriakose Kuruvilla cp->cp_eax = 0xD; 18867af88ac7SKuriakose Kuruvilla cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 18877af88ac7SKuriakose Kuruvilla 18887af88ac7SKuriakose Kuruvilla (void) __cpuid_insn(cp); 18897af88ac7SKuriakose Kuruvilla 18907af88ac7SKuriakose Kuruvilla /* 18917af88ac7SKuriakose Kuruvilla * Sanity checks for debug 18927af88ac7SKuriakose Kuruvilla */ 18937af88ac7SKuriakose Kuruvilla if ((cp->cp_eax & XFEATURE_LEGACY_FP) == 0 || 18947af88ac7SKuriakose Kuruvilla (cp->cp_eax & XFEATURE_SSE) == 0) { 18957af88ac7SKuriakose Kuruvilla cpuid_d_valid = B_FALSE; 18967af88ac7SKuriakose Kuruvilla } 18977af88ac7SKuriakose Kuruvilla 18987af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_low = cp->cp_eax; 18997af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_high = cp->cp_edx; 19007af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_max_size = cp->cp_ecx; 19017af88ac7SKuriakose Kuruvilla 19027af88ac7SKuriakose Kuruvilla /* 19037af88ac7SKuriakose Kuruvilla * If the hw supports AVX, get the size and offset in the save 19047af88ac7SKuriakose Kuruvilla * area for the ymm state. 19057af88ac7SKuriakose Kuruvilla */ 19067af88ac7SKuriakose Kuruvilla if (cpi->cpi_xsave.xsav_hw_features_low & XFEATURE_AVX) { 19077af88ac7SKuriakose Kuruvilla cp->cp_eax = 0xD; 19087af88ac7SKuriakose Kuruvilla cp->cp_ecx = 2; 19097af88ac7SKuriakose Kuruvilla cp->cp_edx = cp->cp_ebx = 0; 19107af88ac7SKuriakose Kuruvilla 19117af88ac7SKuriakose Kuruvilla (void) __cpuid_insn(cp); 19127af88ac7SKuriakose Kuruvilla 19137af88ac7SKuriakose Kuruvilla if (cp->cp_ebx != CPUID_LEAFD_2_YMM_OFFSET || 19147af88ac7SKuriakose Kuruvilla cp->cp_eax != CPUID_LEAFD_2_YMM_SIZE) { 19157af88ac7SKuriakose Kuruvilla cpuid_d_valid = B_FALSE; 19167af88ac7SKuriakose Kuruvilla } 19177af88ac7SKuriakose Kuruvilla 19187af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.ymm_size = cp->cp_eax; 19197af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.ymm_offset = cp->cp_ebx; 19207af88ac7SKuriakose Kuruvilla } 19217af88ac7SKuriakose Kuruvilla 19227af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) { 19237af88ac7SKuriakose Kuruvilla xsave_state_size = 0; 19247af88ac7SKuriakose Kuruvilla } else if (cpuid_d_valid) { 19257af88ac7SKuriakose Kuruvilla xsave_state_size = cpi->cpi_xsave.xsav_max_size; 19267af88ac7SKuriakose Kuruvilla } else { 19277af88ac7SKuriakose Kuruvilla /* Broken CPUID 0xD, probably in HVM */ 19287af88ac7SKuriakose Kuruvilla cmn_err(CE_WARN, "cpu%d: CPUID.0xD returns invalid " 19297af88ac7SKuriakose Kuruvilla "value: hw_low = %d, hw_high = %d, xsave_size = %d" 19307af88ac7SKuriakose Kuruvilla ", ymm_size = %d, ymm_offset = %d\n", 19317af88ac7SKuriakose Kuruvilla cpu->cpu_id, cpi->cpi_xsave.xsav_hw_features_low, 19327af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_high, 19337af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.xsav_max_size, 19347af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.ymm_size, 19357af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.ymm_offset); 19367af88ac7SKuriakose Kuruvilla 19377af88ac7SKuriakose Kuruvilla if (xsave_state_size != 0) { 19387af88ac7SKuriakose Kuruvilla /* 19397af88ac7SKuriakose Kuruvilla * This must be a non-boot CPU. We cannot 19407af88ac7SKuriakose Kuruvilla * continue, because boot cpu has already 19417af88ac7SKuriakose Kuruvilla * enabled XSAVE. 19427af88ac7SKuriakose Kuruvilla */ 19437af88ac7SKuriakose Kuruvilla ASSERT(cpu->cpu_id != 0); 19447af88ac7SKuriakose Kuruvilla cmn_err(CE_PANIC, "cpu%d: we have already " 19457af88ac7SKuriakose Kuruvilla "enabled XSAVE on boot cpu, cannot " 19467af88ac7SKuriakose Kuruvilla "continue.", cpu->cpu_id); 19477af88ac7SKuriakose Kuruvilla } else { 19487af88ac7SKuriakose Kuruvilla /* 19497af88ac7SKuriakose Kuruvilla * Must be from boot CPU, OK to disable XSAVE. 19507af88ac7SKuriakose Kuruvilla */ 19517af88ac7SKuriakose Kuruvilla ASSERT(cpu->cpu_id == 0); 19527af88ac7SKuriakose Kuruvilla remove_x86_feature(x86_featureset, 19537af88ac7SKuriakose Kuruvilla X86FSET_XSAVE); 19547af88ac7SKuriakose Kuruvilla remove_x86_feature(x86_featureset, X86FSET_AVX); 19557af88ac7SKuriakose Kuruvilla CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_XSAVE; 19567af88ac7SKuriakose Kuruvilla CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_AVX; 1957ebb8ac07SRobert Mustacchi CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_F16C; 19587af88ac7SKuriakose Kuruvilla xsave_force_disable = B_TRUE; 19597af88ac7SKuriakose Kuruvilla } 19607af88ac7SKuriakose Kuruvilla } 19617af88ac7SKuriakose Kuruvilla } 19627af88ac7SKuriakose Kuruvilla 19637af88ac7SKuriakose Kuruvilla 19647c478bd9Sstevel@tonic-gate if ((cpi->cpi_xmaxeax & 0x80000000) == 0) 19657c478bd9Sstevel@tonic-gate goto pass2_done; 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate if ((nmax = cpi->cpi_xmaxeax - 0x80000000 + 1) > NMAX_CPI_EXTD) 19687c478bd9Sstevel@tonic-gate nmax = NMAX_CPI_EXTD; 19697c478bd9Sstevel@tonic-gate /* 19707c478bd9Sstevel@tonic-gate * Copy the extended properties, fixing them as we go. 19717c478bd9Sstevel@tonic-gate * (We already handled n == 0 and n == 1 in pass 1) 19727c478bd9Sstevel@tonic-gate */ 19737c478bd9Sstevel@tonic-gate iptr = (void *)cpi->cpi_brandstr; 19747c478bd9Sstevel@tonic-gate for (n = 2, cp = &cpi->cpi_extd[2]; n < nmax; cp++, n++) { 19758949bcd6Sandrei cp->cp_eax = 0x80000000 + n; 19768949bcd6Sandrei (void) __cpuid_insn(cp); 1977ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000000 + n, cp); 19787c478bd9Sstevel@tonic-gate switch (n) { 19797c478bd9Sstevel@tonic-gate case 2: 19807c478bd9Sstevel@tonic-gate case 3: 19817c478bd9Sstevel@tonic-gate case 4: 19827c478bd9Sstevel@tonic-gate /* 19837c478bd9Sstevel@tonic-gate * Extract the brand string 19847c478bd9Sstevel@tonic-gate */ 19857c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_eax; 19867c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ebx; 19877c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ecx; 19887c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_edx; 19897c478bd9Sstevel@tonic-gate break; 19907c478bd9Sstevel@tonic-gate case 5: 19917c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 19927c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 19937c478bd9Sstevel@tonic-gate /* 19947c478bd9Sstevel@tonic-gate * The Athlon and Duron were the first 19957c478bd9Sstevel@tonic-gate * parts to report the sizes of the 19967c478bd9Sstevel@tonic-gate * TLB for large pages. Before then, 19977c478bd9Sstevel@tonic-gate * we don't trust the data. 19987c478bd9Sstevel@tonic-gate */ 19997c478bd9Sstevel@tonic-gate if (cpi->cpi_family < 6 || 20007c478bd9Sstevel@tonic-gate (cpi->cpi_family == 6 && 20017c478bd9Sstevel@tonic-gate cpi->cpi_model < 1)) 20027c478bd9Sstevel@tonic-gate cp->cp_eax = 0; 20037c478bd9Sstevel@tonic-gate break; 20047c478bd9Sstevel@tonic-gate default: 20057c478bd9Sstevel@tonic-gate break; 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate break; 20087c478bd9Sstevel@tonic-gate case 6: 20097c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 20107c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 20117c478bd9Sstevel@tonic-gate /* 20127c478bd9Sstevel@tonic-gate * The Athlon and Duron were the first 20137c478bd9Sstevel@tonic-gate * AMD parts with L2 TLB's. 20147c478bd9Sstevel@tonic-gate * Before then, don't trust the data. 20157c478bd9Sstevel@tonic-gate */ 20167c478bd9Sstevel@tonic-gate if (cpi->cpi_family < 6 || 20177c478bd9Sstevel@tonic-gate cpi->cpi_family == 6 && 20187c478bd9Sstevel@tonic-gate cpi->cpi_model < 1) 20197c478bd9Sstevel@tonic-gate cp->cp_eax = cp->cp_ebx = 0; 20207c478bd9Sstevel@tonic-gate /* 20217c478bd9Sstevel@tonic-gate * AMD Duron rev A0 reports L2 20227c478bd9Sstevel@tonic-gate * cache size incorrectly as 1K 20237c478bd9Sstevel@tonic-gate * when it is really 64K 20247c478bd9Sstevel@tonic-gate */ 20257c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 6 && 20267c478bd9Sstevel@tonic-gate cpi->cpi_model == 3 && 20277c478bd9Sstevel@tonic-gate cpi->cpi_step == 0) { 20287c478bd9Sstevel@tonic-gate cp->cp_ecx &= 0xffff; 20297c478bd9Sstevel@tonic-gate cp->cp_ecx |= 0x400000; 20307c478bd9Sstevel@tonic-gate } 20317c478bd9Sstevel@tonic-gate break; 20327c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: /* VIA C3 */ 20337c478bd9Sstevel@tonic-gate /* 20347c478bd9Sstevel@tonic-gate * VIA C3 processors are a bit messed 20357c478bd9Sstevel@tonic-gate * up w.r.t. encoding cache sizes in %ecx 20367c478bd9Sstevel@tonic-gate */ 20377c478bd9Sstevel@tonic-gate if (cpi->cpi_family != 6) 20387c478bd9Sstevel@tonic-gate break; 20397c478bd9Sstevel@tonic-gate /* 20407c478bd9Sstevel@tonic-gate * model 7 and 8 were incorrectly encoded 20417c478bd9Sstevel@tonic-gate * 20427c478bd9Sstevel@tonic-gate * xxx is model 8 really broken? 20437c478bd9Sstevel@tonic-gate */ 20447c478bd9Sstevel@tonic-gate if (cpi->cpi_model == 7 || 20457c478bd9Sstevel@tonic-gate cpi->cpi_model == 8) 20467c478bd9Sstevel@tonic-gate cp->cp_ecx = 20477c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 24) << 16 | 20487c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 23, 16) << 12 | 20497c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 15, 8) << 8 | 20507c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 7, 0); 20517c478bd9Sstevel@tonic-gate /* 20527c478bd9Sstevel@tonic-gate * model 9 stepping 1 has wrong associativity 20537c478bd9Sstevel@tonic-gate */ 20547c478bd9Sstevel@tonic-gate if (cpi->cpi_model == 9 && cpi->cpi_step == 1) 20557c478bd9Sstevel@tonic-gate cp->cp_ecx |= 8 << 12; 20567c478bd9Sstevel@tonic-gate break; 20577c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 20587c478bd9Sstevel@tonic-gate /* 20597c478bd9Sstevel@tonic-gate * Extended L2 Cache features function. 20607c478bd9Sstevel@tonic-gate * First appeared on Prescott. 20617c478bd9Sstevel@tonic-gate */ 20627c478bd9Sstevel@tonic-gate default: 20637c478bd9Sstevel@tonic-gate break; 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate break; 20667c478bd9Sstevel@tonic-gate default: 20677c478bd9Sstevel@tonic-gate break; 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate } 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate pass2_done: 20727c478bd9Sstevel@tonic-gate cpi->cpi_pass = 2; 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate static const char * 20767c478bd9Sstevel@tonic-gate intel_cpubrand(const struct cpuid_info *cpi) 20777c478bd9Sstevel@tonic-gate { 20787c478bd9Sstevel@tonic-gate int i; 20797c478bd9Sstevel@tonic-gate 20807417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 20817c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5) 20827c478bd9Sstevel@tonic-gate return ("i486"); 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate switch (cpi->cpi_family) { 20857c478bd9Sstevel@tonic-gate case 5: 20867c478bd9Sstevel@tonic-gate return ("Intel Pentium(r)"); 20877c478bd9Sstevel@tonic-gate case 6: 20887c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 20897c478bd9Sstevel@tonic-gate uint_t celeron, xeon; 20908949bcd6Sandrei const struct cpuid_regs *cp; 20917c478bd9Sstevel@tonic-gate case 0: 20927c478bd9Sstevel@tonic-gate case 1: 20937c478bd9Sstevel@tonic-gate case 2: 20947c478bd9Sstevel@tonic-gate return ("Intel Pentium(r) Pro"); 20957c478bd9Sstevel@tonic-gate case 3: 20967c478bd9Sstevel@tonic-gate case 4: 20977c478bd9Sstevel@tonic-gate return ("Intel Pentium(r) II"); 20987c478bd9Sstevel@tonic-gate case 6: 20997c478bd9Sstevel@tonic-gate return ("Intel Celeron(r)"); 21007c478bd9Sstevel@tonic-gate case 5: 21017c478bd9Sstevel@tonic-gate case 7: 21027c478bd9Sstevel@tonic-gate celeron = xeon = 0; 21037c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[2]; /* cache info */ 21047c478bd9Sstevel@tonic-gate 210563d3f7dfSkk208521 for (i = 1; i < 4; i++) { 21067c478bd9Sstevel@tonic-gate uint_t tmp; 21077c478bd9Sstevel@tonic-gate 21087c478bd9Sstevel@tonic-gate tmp = (cp->cp_eax >> (8 * i)) & 0xff; 21097c478bd9Sstevel@tonic-gate if (tmp == 0x40) 21107c478bd9Sstevel@tonic-gate celeron++; 21117c478bd9Sstevel@tonic-gate if (tmp >= 0x44 && tmp <= 0x45) 21127c478bd9Sstevel@tonic-gate xeon++; 21137c478bd9Sstevel@tonic-gate } 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 21167c478bd9Sstevel@tonic-gate uint_t tmp; 21177c478bd9Sstevel@tonic-gate 21187c478bd9Sstevel@tonic-gate tmp = (cp->cp_ebx >> (8 * i)) & 0xff; 21197c478bd9Sstevel@tonic-gate if (tmp == 0x40) 21207c478bd9Sstevel@tonic-gate celeron++; 21217c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 21227c478bd9Sstevel@tonic-gate xeon++; 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 21267c478bd9Sstevel@tonic-gate uint_t tmp; 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate tmp = (cp->cp_ecx >> (8 * i)) & 0xff; 21297c478bd9Sstevel@tonic-gate if (tmp == 0x40) 21307c478bd9Sstevel@tonic-gate celeron++; 21317c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 21327c478bd9Sstevel@tonic-gate xeon++; 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 21367c478bd9Sstevel@tonic-gate uint_t tmp; 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate tmp = (cp->cp_edx >> (8 * i)) & 0xff; 21397c478bd9Sstevel@tonic-gate if (tmp == 0x40) 21407c478bd9Sstevel@tonic-gate celeron++; 21417c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 21427c478bd9Sstevel@tonic-gate xeon++; 21437c478bd9Sstevel@tonic-gate } 21447c478bd9Sstevel@tonic-gate 21457c478bd9Sstevel@tonic-gate if (celeron) 21467c478bd9Sstevel@tonic-gate return ("Intel Celeron(r)"); 21477c478bd9Sstevel@tonic-gate if (xeon) 21487c478bd9Sstevel@tonic-gate return (cpi->cpi_model == 5 ? 21497c478bd9Sstevel@tonic-gate "Intel Pentium(r) II Xeon(tm)" : 21507c478bd9Sstevel@tonic-gate "Intel Pentium(r) III Xeon(tm)"); 21517c478bd9Sstevel@tonic-gate return (cpi->cpi_model == 5 ? 21527c478bd9Sstevel@tonic-gate "Intel Pentium(r) II or Pentium(r) II Xeon(tm)" : 21537c478bd9Sstevel@tonic-gate "Intel Pentium(r) III or Pentium(r) III Xeon(tm)"); 21547c478bd9Sstevel@tonic-gate default: 21557c478bd9Sstevel@tonic-gate break; 21567c478bd9Sstevel@tonic-gate } 21577c478bd9Sstevel@tonic-gate default: 21587c478bd9Sstevel@tonic-gate break; 21597c478bd9Sstevel@tonic-gate } 21607c478bd9Sstevel@tonic-gate 21615ff02082Sdmick /* BrandID is present if the field is nonzero */ 21625ff02082Sdmick if (cpi->cpi_brandid != 0) { 21637c478bd9Sstevel@tonic-gate static const struct { 21647c478bd9Sstevel@tonic-gate uint_t bt_bid; 21657c478bd9Sstevel@tonic-gate const char *bt_str; 21667c478bd9Sstevel@tonic-gate } brand_tbl[] = { 21677c478bd9Sstevel@tonic-gate { 0x1, "Intel(r) Celeron(r)" }, 21687c478bd9Sstevel@tonic-gate { 0x2, "Intel(r) Pentium(r) III" }, 21697c478bd9Sstevel@tonic-gate { 0x3, "Intel(r) Pentium(r) III Xeon(tm)" }, 21707c478bd9Sstevel@tonic-gate { 0x4, "Intel(r) Pentium(r) III" }, 21717c478bd9Sstevel@tonic-gate { 0x6, "Mobile Intel(r) Pentium(r) III" }, 21727c478bd9Sstevel@tonic-gate { 0x7, "Mobile Intel(r) Celeron(r)" }, 21737c478bd9Sstevel@tonic-gate { 0x8, "Intel(r) Pentium(r) 4" }, 21747c478bd9Sstevel@tonic-gate { 0x9, "Intel(r) Pentium(r) 4" }, 21757c478bd9Sstevel@tonic-gate { 0xa, "Intel(r) Celeron(r)" }, 21767c478bd9Sstevel@tonic-gate { 0xb, "Intel(r) Xeon(tm)" }, 21777c478bd9Sstevel@tonic-gate { 0xc, "Intel(r) Xeon(tm) MP" }, 21787c478bd9Sstevel@tonic-gate { 0xe, "Mobile Intel(r) Pentium(r) 4" }, 21795ff02082Sdmick { 0xf, "Mobile Intel(r) Celeron(r)" }, 21805ff02082Sdmick { 0x11, "Mobile Genuine Intel(r)" }, 21815ff02082Sdmick { 0x12, "Intel(r) Celeron(r) M" }, 21825ff02082Sdmick { 0x13, "Mobile Intel(r) Celeron(r)" }, 21835ff02082Sdmick { 0x14, "Intel(r) Celeron(r)" }, 21845ff02082Sdmick { 0x15, "Mobile Genuine Intel(r)" }, 21855ff02082Sdmick { 0x16, "Intel(r) Pentium(r) M" }, 21865ff02082Sdmick { 0x17, "Mobile Intel(r) Celeron(r)" } 21877c478bd9Sstevel@tonic-gate }; 21887c478bd9Sstevel@tonic-gate uint_t btblmax = sizeof (brand_tbl) / sizeof (brand_tbl[0]); 21897c478bd9Sstevel@tonic-gate uint_t sgn; 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate sgn = (cpi->cpi_family << 8) | 21927c478bd9Sstevel@tonic-gate (cpi->cpi_model << 4) | cpi->cpi_step; 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate for (i = 0; i < btblmax; i++) 21957c478bd9Sstevel@tonic-gate if (brand_tbl[i].bt_bid == cpi->cpi_brandid) 21967c478bd9Sstevel@tonic-gate break; 21977c478bd9Sstevel@tonic-gate if (i < btblmax) { 21987c478bd9Sstevel@tonic-gate if (sgn == 0x6b1 && cpi->cpi_brandid == 3) 21997c478bd9Sstevel@tonic-gate return ("Intel(r) Celeron(r)"); 22007c478bd9Sstevel@tonic-gate if (sgn < 0xf13 && cpi->cpi_brandid == 0xb) 22017c478bd9Sstevel@tonic-gate return ("Intel(r) Xeon(tm) MP"); 22027c478bd9Sstevel@tonic-gate if (sgn < 0xf13 && cpi->cpi_brandid == 0xe) 22037c478bd9Sstevel@tonic-gate return ("Intel(r) Xeon(tm)"); 22047c478bd9Sstevel@tonic-gate return (brand_tbl[i].bt_str); 22057c478bd9Sstevel@tonic-gate } 22067c478bd9Sstevel@tonic-gate } 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate return (NULL); 22097c478bd9Sstevel@tonic-gate } 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate static const char * 22127c478bd9Sstevel@tonic-gate amd_cpubrand(const struct cpuid_info *cpi) 22137c478bd9Sstevel@tonic-gate { 22147417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 22157c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5) 22167c478bd9Sstevel@tonic-gate return ("i486 compatible"); 22177c478bd9Sstevel@tonic-gate 22187c478bd9Sstevel@tonic-gate switch (cpi->cpi_family) { 22197c478bd9Sstevel@tonic-gate case 5: 22207c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 22217c478bd9Sstevel@tonic-gate case 0: 22227c478bd9Sstevel@tonic-gate case 1: 22237c478bd9Sstevel@tonic-gate case 2: 22247c478bd9Sstevel@tonic-gate case 3: 22257c478bd9Sstevel@tonic-gate case 4: 22267c478bd9Sstevel@tonic-gate case 5: 22277c478bd9Sstevel@tonic-gate return ("AMD-K5(r)"); 22287c478bd9Sstevel@tonic-gate case 6: 22297c478bd9Sstevel@tonic-gate case 7: 22307c478bd9Sstevel@tonic-gate return ("AMD-K6(r)"); 22317c478bd9Sstevel@tonic-gate case 8: 22327c478bd9Sstevel@tonic-gate return ("AMD-K6(r)-2"); 22337c478bd9Sstevel@tonic-gate case 9: 22347c478bd9Sstevel@tonic-gate return ("AMD-K6(r)-III"); 22357c478bd9Sstevel@tonic-gate default: 22367c478bd9Sstevel@tonic-gate return ("AMD (family 5)"); 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate case 6: 22397c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 22407c478bd9Sstevel@tonic-gate case 1: 22417c478bd9Sstevel@tonic-gate return ("AMD-K7(tm)"); 22427c478bd9Sstevel@tonic-gate case 0: 22437c478bd9Sstevel@tonic-gate case 2: 22447c478bd9Sstevel@tonic-gate case 4: 22457c478bd9Sstevel@tonic-gate return ("AMD Athlon(tm)"); 22467c478bd9Sstevel@tonic-gate case 3: 22477c478bd9Sstevel@tonic-gate case 7: 22487c478bd9Sstevel@tonic-gate return ("AMD Duron(tm)"); 22497c478bd9Sstevel@tonic-gate case 6: 22507c478bd9Sstevel@tonic-gate case 8: 22517c478bd9Sstevel@tonic-gate case 10: 22527c478bd9Sstevel@tonic-gate /* 22537c478bd9Sstevel@tonic-gate * Use the L2 cache size to distinguish 22547c478bd9Sstevel@tonic-gate */ 22557c478bd9Sstevel@tonic-gate return ((cpi->cpi_extd[6].cp_ecx >> 16) >= 256 ? 22567c478bd9Sstevel@tonic-gate "AMD Athlon(tm)" : "AMD Duron(tm)"); 22577c478bd9Sstevel@tonic-gate default: 22587c478bd9Sstevel@tonic-gate return ("AMD (family 6)"); 22597c478bd9Sstevel@tonic-gate } 22607c478bd9Sstevel@tonic-gate default: 22617c478bd9Sstevel@tonic-gate break; 22627c478bd9Sstevel@tonic-gate } 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 0xf && cpi->cpi_model == 5 && 22657c478bd9Sstevel@tonic-gate cpi->cpi_brandid != 0) { 22667c478bd9Sstevel@tonic-gate switch (BITX(cpi->cpi_brandid, 7, 5)) { 22677c478bd9Sstevel@tonic-gate case 3: 22687c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) UP 1xx"); 22697c478bd9Sstevel@tonic-gate case 4: 22707c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) DP 2xx"); 22717c478bd9Sstevel@tonic-gate case 5: 22727c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) MP 8xx"); 22737c478bd9Sstevel@tonic-gate default: 22747c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm)"); 22757c478bd9Sstevel@tonic-gate } 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate 22787c478bd9Sstevel@tonic-gate return (NULL); 22797c478bd9Sstevel@tonic-gate } 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate static const char * 22827c478bd9Sstevel@tonic-gate cyrix_cpubrand(struct cpuid_info *cpi, uint_t type) 22837c478bd9Sstevel@tonic-gate { 22847417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 22857c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5 || 22867c478bd9Sstevel@tonic-gate type == X86_TYPE_CYRIX_486) 22877c478bd9Sstevel@tonic-gate return ("i486 compatible"); 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate switch (type) { 22907c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86: 22917c478bd9Sstevel@tonic-gate return ("Cyrix 6x86"); 22927c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86L: 22937c478bd9Sstevel@tonic-gate return ("Cyrix 6x86L"); 22947c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86MX: 22957c478bd9Sstevel@tonic-gate return ("Cyrix 6x86MX"); 22967c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_GXm: 22977c478bd9Sstevel@tonic-gate return ("Cyrix GXm"); 22987c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MediaGX: 22997c478bd9Sstevel@tonic-gate return ("Cyrix MediaGX"); 23007c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MII: 23017c478bd9Sstevel@tonic-gate return ("Cyrix M2"); 23027c478bd9Sstevel@tonic-gate case X86_TYPE_VIA_CYRIX_III: 23037c478bd9Sstevel@tonic-gate return ("VIA Cyrix M3"); 23047c478bd9Sstevel@tonic-gate default: 23057c478bd9Sstevel@tonic-gate /* 23067c478bd9Sstevel@tonic-gate * Have another wild guess .. 23077c478bd9Sstevel@tonic-gate */ 23087c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 4 && cpi->cpi_model == 9) 23097c478bd9Sstevel@tonic-gate return ("Cyrix 5x86"); 23107c478bd9Sstevel@tonic-gate else if (cpi->cpi_family == 5) { 23117c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 23127c478bd9Sstevel@tonic-gate case 2: 23137c478bd9Sstevel@tonic-gate return ("Cyrix 6x86"); /* Cyrix M1 */ 23147c478bd9Sstevel@tonic-gate case 4: 23157c478bd9Sstevel@tonic-gate return ("Cyrix MediaGX"); 23167c478bd9Sstevel@tonic-gate default: 23177c478bd9Sstevel@tonic-gate break; 23187c478bd9Sstevel@tonic-gate } 23197c478bd9Sstevel@tonic-gate } else if (cpi->cpi_family == 6) { 23207c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 23217c478bd9Sstevel@tonic-gate case 0: 23227c478bd9Sstevel@tonic-gate return ("Cyrix 6x86MX"); /* Cyrix M2? */ 23237c478bd9Sstevel@tonic-gate case 5: 23247c478bd9Sstevel@tonic-gate case 6: 23257c478bd9Sstevel@tonic-gate case 7: 23267c478bd9Sstevel@tonic-gate case 8: 23277c478bd9Sstevel@tonic-gate case 9: 23287c478bd9Sstevel@tonic-gate return ("VIA C3"); 23297c478bd9Sstevel@tonic-gate default: 23307c478bd9Sstevel@tonic-gate break; 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate } 23337c478bd9Sstevel@tonic-gate break; 23347c478bd9Sstevel@tonic-gate } 23357c478bd9Sstevel@tonic-gate return (NULL); 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate /* 23397c478bd9Sstevel@tonic-gate * This only gets called in the case that the CPU extended 23407c478bd9Sstevel@tonic-gate * feature brand string (0x80000002, 0x80000003, 0x80000004) 23417c478bd9Sstevel@tonic-gate * aren't available, or contain null bytes for some reason. 23427c478bd9Sstevel@tonic-gate */ 23437c478bd9Sstevel@tonic-gate static void 23447c478bd9Sstevel@tonic-gate fabricate_brandstr(struct cpuid_info *cpi) 23457c478bd9Sstevel@tonic-gate { 23467c478bd9Sstevel@tonic-gate const char *brand = NULL; 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 23497c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 23507c478bd9Sstevel@tonic-gate brand = intel_cpubrand(cpi); 23517c478bd9Sstevel@tonic-gate break; 23527c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 23537c478bd9Sstevel@tonic-gate brand = amd_cpubrand(cpi); 23547c478bd9Sstevel@tonic-gate break; 23557c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 23567c478bd9Sstevel@tonic-gate brand = cyrix_cpubrand(cpi, x86_type); 23577c478bd9Sstevel@tonic-gate break; 23587c478bd9Sstevel@tonic-gate case X86_VENDOR_NexGen: 23597c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 0) 23607c478bd9Sstevel@tonic-gate brand = "NexGen Nx586"; 23617c478bd9Sstevel@tonic-gate break; 23627c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 23637c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) 23647c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 23657c478bd9Sstevel@tonic-gate case 4: 23667c478bd9Sstevel@tonic-gate brand = "Centaur C6"; 23677c478bd9Sstevel@tonic-gate break; 23687c478bd9Sstevel@tonic-gate case 8: 23697c478bd9Sstevel@tonic-gate brand = "Centaur C2"; 23707c478bd9Sstevel@tonic-gate break; 23717c478bd9Sstevel@tonic-gate case 9: 23727c478bd9Sstevel@tonic-gate brand = "Centaur C3"; 23737c478bd9Sstevel@tonic-gate break; 23747c478bd9Sstevel@tonic-gate default: 23757c478bd9Sstevel@tonic-gate break; 23767c478bd9Sstevel@tonic-gate } 23777c478bd9Sstevel@tonic-gate break; 23787c478bd9Sstevel@tonic-gate case X86_VENDOR_Rise: 23797c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && 23807c478bd9Sstevel@tonic-gate (cpi->cpi_model == 0 || cpi->cpi_model == 2)) 23817c478bd9Sstevel@tonic-gate brand = "Rise mP6"; 23827c478bd9Sstevel@tonic-gate break; 23837c478bd9Sstevel@tonic-gate case X86_VENDOR_SiS: 23847c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 0) 23857c478bd9Sstevel@tonic-gate brand = "SiS 55x"; 23867c478bd9Sstevel@tonic-gate break; 23877c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 23887c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 4) 23897c478bd9Sstevel@tonic-gate brand = "Transmeta Crusoe TM3x00 or TM5x00"; 23907c478bd9Sstevel@tonic-gate break; 23917c478bd9Sstevel@tonic-gate case X86_VENDOR_NSC: 23927c478bd9Sstevel@tonic-gate case X86_VENDOR_UMC: 23937c478bd9Sstevel@tonic-gate default: 23947c478bd9Sstevel@tonic-gate break; 23957c478bd9Sstevel@tonic-gate } 23967c478bd9Sstevel@tonic-gate if (brand) { 23977c478bd9Sstevel@tonic-gate (void) strcpy((char *)cpi->cpi_brandstr, brand); 23987c478bd9Sstevel@tonic-gate return; 23997c478bd9Sstevel@tonic-gate } 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate /* 24027c478bd9Sstevel@tonic-gate * If all else fails ... 24037c478bd9Sstevel@tonic-gate */ 24047c478bd9Sstevel@tonic-gate (void) snprintf(cpi->cpi_brandstr, sizeof (cpi->cpi_brandstr), 24057c478bd9Sstevel@tonic-gate "%s %d.%d.%d", cpi->cpi_vendorstr, cpi->cpi_family, 24067c478bd9Sstevel@tonic-gate cpi->cpi_model, cpi->cpi_step); 24077c478bd9Sstevel@tonic-gate } 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate /* 24107c478bd9Sstevel@tonic-gate * This routine is called just after kernel memory allocation 24117c478bd9Sstevel@tonic-gate * becomes available on cpu0, and as part of mp_startup() on 24127c478bd9Sstevel@tonic-gate * the other cpus. 24137c478bd9Sstevel@tonic-gate * 2414d129bde2Sesaxe * Fixup the brand string, and collect any information from cpuid 241579ec9da8SYuri Pankov * that requires dynamically allocated storage to represent. 24167c478bd9Sstevel@tonic-gate */ 24177c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 24187c478bd9Sstevel@tonic-gate void 24197c478bd9Sstevel@tonic-gate cpuid_pass3(cpu_t *cpu) 24207c478bd9Sstevel@tonic-gate { 2421d129bde2Sesaxe int i, max, shft, level, size; 2422d129bde2Sesaxe struct cpuid_regs regs; 2423d129bde2Sesaxe struct cpuid_regs *cp; 24247c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 2); 24277c478bd9Sstevel@tonic-gate 2428d129bde2Sesaxe /* 2429d129bde2Sesaxe * Function 4: Deterministic cache parameters 2430d129bde2Sesaxe * 2431d129bde2Sesaxe * Take this opportunity to detect the number of threads 2432d129bde2Sesaxe * sharing the last level cache, and construct a corresponding 2433d129bde2Sesaxe * cache id. The respective cpuid_info members are initialized 2434d129bde2Sesaxe * to the default case of "no last level cache sharing". 2435d129bde2Sesaxe */ 2436d129bde2Sesaxe cpi->cpi_ncpu_shr_last_cache = 1; 2437d129bde2Sesaxe cpi->cpi_last_lvl_cacheid = cpu->cpu_id; 2438d129bde2Sesaxe 2439d129bde2Sesaxe if (cpi->cpi_maxeax >= 4 && cpi->cpi_vendor == X86_VENDOR_Intel) { 2440d129bde2Sesaxe 2441d129bde2Sesaxe /* 2442d129bde2Sesaxe * Find the # of elements (size) returned by fn 4, and along 2443d129bde2Sesaxe * the way detect last level cache sharing details. 2444d129bde2Sesaxe */ 2445d129bde2Sesaxe bzero(®s, sizeof (regs)); 2446d129bde2Sesaxe cp = ®s; 2447d129bde2Sesaxe for (i = 0, max = 0; i < CPI_FN4_ECX_MAX; i++) { 2448d129bde2Sesaxe cp->cp_eax = 4; 2449d129bde2Sesaxe cp->cp_ecx = i; 2450d129bde2Sesaxe 2451d129bde2Sesaxe (void) __cpuid_insn(cp); 2452d129bde2Sesaxe 2453d129bde2Sesaxe if (CPI_CACHE_TYPE(cp) == 0) 2454d129bde2Sesaxe break; 2455d129bde2Sesaxe level = CPI_CACHE_LVL(cp); 2456d129bde2Sesaxe if (level > max) { 2457d129bde2Sesaxe max = level; 2458d129bde2Sesaxe cpi->cpi_ncpu_shr_last_cache = 2459d129bde2Sesaxe CPI_NTHR_SHR_CACHE(cp) + 1; 2460d129bde2Sesaxe } 2461d129bde2Sesaxe } 2462d129bde2Sesaxe cpi->cpi_std_4_size = size = i; 2463d129bde2Sesaxe 2464d129bde2Sesaxe /* 2465d129bde2Sesaxe * Allocate the cpi_std_4 array. The first element 2466d129bde2Sesaxe * references the regs for fn 4, %ecx == 0, which 2467d129bde2Sesaxe * cpuid_pass2() stashed in cpi->cpi_std[4]. 2468d129bde2Sesaxe */ 2469d129bde2Sesaxe if (size > 0) { 2470d129bde2Sesaxe cpi->cpi_std_4 = 2471d129bde2Sesaxe kmem_alloc(size * sizeof (cp), KM_SLEEP); 2472d129bde2Sesaxe cpi->cpi_std_4[0] = &cpi->cpi_std[4]; 2473d129bde2Sesaxe 2474d129bde2Sesaxe /* 2475d129bde2Sesaxe * Allocate storage to hold the additional regs 2476d129bde2Sesaxe * for function 4, %ecx == 1 .. cpi_std_4_size. 2477d129bde2Sesaxe * 2478d129bde2Sesaxe * The regs for fn 4, %ecx == 0 has already 2479d129bde2Sesaxe * been allocated as indicated above. 2480d129bde2Sesaxe */ 2481d129bde2Sesaxe for (i = 1; i < size; i++) { 2482d129bde2Sesaxe cp = cpi->cpi_std_4[i] = 2483d129bde2Sesaxe kmem_zalloc(sizeof (regs), KM_SLEEP); 2484d129bde2Sesaxe cp->cp_eax = 4; 2485d129bde2Sesaxe cp->cp_ecx = i; 2486d129bde2Sesaxe 2487d129bde2Sesaxe (void) __cpuid_insn(cp); 2488d129bde2Sesaxe } 2489d129bde2Sesaxe } 2490d129bde2Sesaxe /* 2491d129bde2Sesaxe * Determine the number of bits needed to represent 2492d129bde2Sesaxe * the number of CPUs sharing the last level cache. 2493d129bde2Sesaxe * 2494d129bde2Sesaxe * Shift off that number of bits from the APIC id to 2495d129bde2Sesaxe * derive the cache id. 2496d129bde2Sesaxe */ 2497d129bde2Sesaxe shft = 0; 2498d129bde2Sesaxe for (i = 1; i < cpi->cpi_ncpu_shr_last_cache; i <<= 1) 2499d129bde2Sesaxe shft++; 2500b6917abeSmishra cpi->cpi_last_lvl_cacheid = cpi->cpi_apicid >> shft; 2501d129bde2Sesaxe } 2502d129bde2Sesaxe 2503d129bde2Sesaxe /* 2504d129bde2Sesaxe * Now fixup the brand string 2505d129bde2Sesaxe */ 25067c478bd9Sstevel@tonic-gate if ((cpi->cpi_xmaxeax & 0x80000000) == 0) { 25077c478bd9Sstevel@tonic-gate fabricate_brandstr(cpi); 2508d129bde2Sesaxe } else { 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate /* 25117c478bd9Sstevel@tonic-gate * If we successfully extracted a brand string from the cpuid 25127c478bd9Sstevel@tonic-gate * instruction, clean it up by removing leading spaces and 25137c478bd9Sstevel@tonic-gate * similar junk. 25147c478bd9Sstevel@tonic-gate */ 25157c478bd9Sstevel@tonic-gate if (cpi->cpi_brandstr[0]) { 25167c478bd9Sstevel@tonic-gate size_t maxlen = sizeof (cpi->cpi_brandstr); 25177c478bd9Sstevel@tonic-gate char *src, *dst; 25187c478bd9Sstevel@tonic-gate 25197c478bd9Sstevel@tonic-gate dst = src = (char *)cpi->cpi_brandstr; 25207c478bd9Sstevel@tonic-gate src[maxlen - 1] = '\0'; 25217c478bd9Sstevel@tonic-gate /* 25227c478bd9Sstevel@tonic-gate * strip leading spaces 25237c478bd9Sstevel@tonic-gate */ 25247c478bd9Sstevel@tonic-gate while (*src == ' ') 25257c478bd9Sstevel@tonic-gate src++; 25267c478bd9Sstevel@tonic-gate /* 25277c478bd9Sstevel@tonic-gate * Remove any 'Genuine' or "Authentic" prefixes 25287c478bd9Sstevel@tonic-gate */ 25297c478bd9Sstevel@tonic-gate if (strncmp(src, "Genuine ", 8) == 0) 25307c478bd9Sstevel@tonic-gate src += 8; 25317c478bd9Sstevel@tonic-gate if (strncmp(src, "Authentic ", 10) == 0) 25327c478bd9Sstevel@tonic-gate src += 10; 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate /* 25357c478bd9Sstevel@tonic-gate * Now do an in-place copy. 25367c478bd9Sstevel@tonic-gate * Map (R) to (r) and (TM) to (tm). 25377c478bd9Sstevel@tonic-gate * The era of teletypes is long gone, and there's 25387c478bd9Sstevel@tonic-gate * -really- no need to shout. 25397c478bd9Sstevel@tonic-gate */ 25407c478bd9Sstevel@tonic-gate while (*src != '\0') { 25417c478bd9Sstevel@tonic-gate if (src[0] == '(') { 25427c478bd9Sstevel@tonic-gate if (strncmp(src + 1, "R)", 2) == 0) { 25437c478bd9Sstevel@tonic-gate (void) strncpy(dst, "(r)", 3); 25447c478bd9Sstevel@tonic-gate src += 3; 25457c478bd9Sstevel@tonic-gate dst += 3; 25467c478bd9Sstevel@tonic-gate continue; 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate if (strncmp(src + 1, "TM)", 3) == 0) { 25497c478bd9Sstevel@tonic-gate (void) strncpy(dst, "(tm)", 4); 25507c478bd9Sstevel@tonic-gate src += 4; 25517c478bd9Sstevel@tonic-gate dst += 4; 25527c478bd9Sstevel@tonic-gate continue; 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate } 25557c478bd9Sstevel@tonic-gate *dst++ = *src++; 25567c478bd9Sstevel@tonic-gate } 25577c478bd9Sstevel@tonic-gate *dst = '\0'; 25587c478bd9Sstevel@tonic-gate 25597c478bd9Sstevel@tonic-gate /* 25607c478bd9Sstevel@tonic-gate * Finally, remove any trailing spaces 25617c478bd9Sstevel@tonic-gate */ 25627c478bd9Sstevel@tonic-gate while (--dst > cpi->cpi_brandstr) 25637c478bd9Sstevel@tonic-gate if (*dst == ' ') 25647c478bd9Sstevel@tonic-gate *dst = '\0'; 25657c478bd9Sstevel@tonic-gate else 25667c478bd9Sstevel@tonic-gate break; 25677c478bd9Sstevel@tonic-gate } else 25687c478bd9Sstevel@tonic-gate fabricate_brandstr(cpi); 2569d129bde2Sesaxe } 25707c478bd9Sstevel@tonic-gate cpi->cpi_pass = 3; 25717c478bd9Sstevel@tonic-gate } 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate /* 25747c478bd9Sstevel@tonic-gate * This routine is called out of bind_hwcap() much later in the life 25757c478bd9Sstevel@tonic-gate * of the kernel (post_startup()). The job of this routine is to resolve 25767c478bd9Sstevel@tonic-gate * the hardware feature support and kernel support for those features into 25777c478bd9Sstevel@tonic-gate * what we're actually going to tell applications via the aux vector. 25787c478bd9Sstevel@tonic-gate */ 2579ebb8ac07SRobert Mustacchi void 2580ebb8ac07SRobert Mustacchi cpuid_pass4(cpu_t *cpu, uint_t *hwcap_out) 25817c478bd9Sstevel@tonic-gate { 25827c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 2583ebb8ac07SRobert Mustacchi uint_t hwcap_flags = 0, hwcap_flags_2 = 0; 25847c478bd9Sstevel@tonic-gate 25857c478bd9Sstevel@tonic-gate if (cpu == NULL) 25867c478bd9Sstevel@tonic-gate cpu = CPU; 25877c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 3); 25907c478bd9Sstevel@tonic-gate 25917c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax >= 1) { 25927c478bd9Sstevel@tonic-gate uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES]; 25937c478bd9Sstevel@tonic-gate uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES]; 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate *edx = CPI_FEATURES_EDX(cpi); 25967c478bd9Sstevel@tonic-gate *ecx = CPI_FEATURES_ECX(cpi); 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate /* 25997c478bd9Sstevel@tonic-gate * [these require explicit kernel support] 26007c478bd9Sstevel@tonic-gate */ 26017417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SEP)) 26027c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_SEP; 26037c478bd9Sstevel@tonic-gate 26047417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE)) 26057c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE); 26067417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE2)) 26077c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_SSE2; 26087c478bd9Sstevel@tonic-gate 26097417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_HTT)) 26107c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_HTT; 26117c478bd9Sstevel@tonic-gate 26127417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE3)) 26137c478bd9Sstevel@tonic-gate *ecx &= ~CPUID_INTC_ECX_SSE3; 26147c478bd9Sstevel@tonic-gate 26157417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSSE3)) 2616d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSSE3; 26177417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1)) 2618d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSE4_1; 26197417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2)) 2620d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSE4_2; 26217417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_AES)) 2622a50a8b93SKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_AES; 26237417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ)) 26247417cfdeSKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_PCLMULQDQ; 26257af88ac7SKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_XSAVE)) 26267af88ac7SKuriakose Kuruvilla *ecx &= ~(CPUID_INTC_ECX_XSAVE | 26277af88ac7SKuriakose Kuruvilla CPUID_INTC_ECX_OSXSAVE); 26287af88ac7SKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_AVX)) 26297af88ac7SKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_AVX; 2630ebb8ac07SRobert Mustacchi if (!is_x86_feature(x86_featureset, X86FSET_F16C)) 2631ebb8ac07SRobert Mustacchi *ecx &= ~CPUID_INTC_ECX_F16C; 2632d0f8ff6eSkk208521 26337c478bd9Sstevel@tonic-gate /* 26347c478bd9Sstevel@tonic-gate * [no explicit support required beyond x87 fp context] 26357c478bd9Sstevel@tonic-gate */ 26367c478bd9Sstevel@tonic-gate if (!fpu_exists) 26377c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_INTC_EDX_FPU | CPUID_INTC_EDX_MMX); 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate /* 26407c478bd9Sstevel@tonic-gate * Now map the supported feature vector to things that we 26417c478bd9Sstevel@tonic-gate * think userland will care about. 26427c478bd9Sstevel@tonic-gate */ 26437c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SEP) 26447c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SEP; 26457c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SSE) 26467c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_FXSR | AV_386_SSE; 26477c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SSE2) 26487c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SSE2; 26497c478bd9Sstevel@tonic-gate if (*ecx & CPUID_INTC_ECX_SSE3) 26507c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SSE3; 2651d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSSE3) 2652d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSSE3; 2653d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSE4_1) 2654d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSE4_1; 2655d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSE4_2) 2656d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSE4_2; 26575087e485SKrishnendu Sadhukhan - Sun Microsystems if (*ecx & CPUID_INTC_ECX_MOVBE) 26585087e485SKrishnendu Sadhukhan - Sun Microsystems hwcap_flags |= AV_386_MOVBE; 2659a50a8b93SKuriakose Kuruvilla if (*ecx & CPUID_INTC_ECX_AES) 2660a50a8b93SKuriakose Kuruvilla hwcap_flags |= AV_386_AES; 2661a50a8b93SKuriakose Kuruvilla if (*ecx & CPUID_INTC_ECX_PCLMULQDQ) 2662a50a8b93SKuriakose Kuruvilla hwcap_flags |= AV_386_PCLMULQDQ; 26637af88ac7SKuriakose Kuruvilla if ((*ecx & CPUID_INTC_ECX_XSAVE) && 2664f3390f39SRobert Mustacchi (*ecx & CPUID_INTC_ECX_OSXSAVE)) { 26657af88ac7SKuriakose Kuruvilla hwcap_flags |= AV_386_XSAVE; 2666f3390f39SRobert Mustacchi 2667ebb8ac07SRobert Mustacchi if (*ecx & CPUID_INTC_ECX_AVX) { 2668f3390f39SRobert Mustacchi hwcap_flags |= AV_386_AVX; 2669ebb8ac07SRobert Mustacchi if (*ecx & CPUID_INTC_ECX_F16C) 2670ebb8ac07SRobert Mustacchi hwcap_flags_2 |= AV_386_2_F16C; 2671ebb8ac07SRobert Mustacchi } 2672f3390f39SRobert Mustacchi } 2673faa20166SBryan Cantrill if (*ecx & CPUID_INTC_ECX_VMX) 2674faa20166SBryan Cantrill hwcap_flags |= AV_386_VMX; 2675f8801251Skk208521 if (*ecx & CPUID_INTC_ECX_POPCNT) 2676f8801251Skk208521 hwcap_flags |= AV_386_POPCNT; 26777c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_FPU) 26787c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_FPU; 26797c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_MMX) 26807c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_MMX; 26817c478bd9Sstevel@tonic-gate 26827c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_TSC) 26837c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_TSC; 26847c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_CX8) 26857c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CX8; 26867c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_CMOV) 26877c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CMOV; 26887c478bd9Sstevel@tonic-gate if (*ecx & CPUID_INTC_ECX_CX16) 26897c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CX16; 2690ebb8ac07SRobert Mustacchi 2691ebb8ac07SRobert Mustacchi if (*ecx & CPUID_INTC_ECX_RDRAND) 2692ebb8ac07SRobert Mustacchi hwcap_flags_2 |= AV_386_2_RDRAND; 26937c478bd9Sstevel@tonic-gate } 26947c478bd9Sstevel@tonic-gate 26957c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000001) 26967c478bd9Sstevel@tonic-gate goto pass4_done; 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 26998949bcd6Sandrei struct cpuid_regs cp; 2700ae115bc7Smrj uint32_t *edx, *ecx; 27017c478bd9Sstevel@tonic-gate 2702ae115bc7Smrj case X86_VENDOR_Intel: 2703ae115bc7Smrj /* 2704ae115bc7Smrj * Seems like Intel duplicated what we necessary 2705ae115bc7Smrj * here to make the initial crop of 64-bit OS's work. 2706ae115bc7Smrj * Hopefully, those are the only "extended" bits 2707ae115bc7Smrj * they'll add. 2708ae115bc7Smrj */ 2709ae115bc7Smrj /*FALLTHROUGH*/ 2710ae115bc7Smrj 27117c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 27127c478bd9Sstevel@tonic-gate edx = &cpi->cpi_support[AMD_EDX_FEATURES]; 2713ae115bc7Smrj ecx = &cpi->cpi_support[AMD_ECX_FEATURES]; 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate *edx = CPI_FEATURES_XTD_EDX(cpi); 2716ae115bc7Smrj *ecx = CPI_FEATURES_XTD_ECX(cpi); 2717ae115bc7Smrj 2718ae115bc7Smrj /* 2719ae115bc7Smrj * [these features require explicit kernel support] 2720ae115bc7Smrj */ 2721ae115bc7Smrj switch (cpi->cpi_vendor) { 2722ae115bc7Smrj case X86_VENDOR_Intel: 27237417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_TSCP)) 2724d36ea5d8Ssudheer *edx &= ~CPUID_AMD_EDX_TSCP; 2725ae115bc7Smrj break; 2726ae115bc7Smrj 2727ae115bc7Smrj case X86_VENDOR_AMD: 27287417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_TSCP)) 2729ae115bc7Smrj *edx &= ~CPUID_AMD_EDX_TSCP; 27307417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4A)) 2731f8801251Skk208521 *ecx &= ~CPUID_AMD_ECX_SSE4A; 2732ae115bc7Smrj break; 2733ae115bc7Smrj 2734ae115bc7Smrj default: 2735ae115bc7Smrj break; 2736ae115bc7Smrj } 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate /* 27397c478bd9Sstevel@tonic-gate * [no explicit support required beyond 27407c478bd9Sstevel@tonic-gate * x87 fp context and exception handlers] 27417c478bd9Sstevel@tonic-gate */ 27427c478bd9Sstevel@tonic-gate if (!fpu_exists) 27437c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_AMD_EDX_MMXamd | 27447c478bd9Sstevel@tonic-gate CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx); 27457c478bd9Sstevel@tonic-gate 27467417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_NX)) 27477c478bd9Sstevel@tonic-gate *edx &= ~CPUID_AMD_EDX_NX; 2748ae115bc7Smrj #if !defined(__amd64) 27497c478bd9Sstevel@tonic-gate *edx &= ~CPUID_AMD_EDX_LM; 27507c478bd9Sstevel@tonic-gate #endif 27517c478bd9Sstevel@tonic-gate /* 27527c478bd9Sstevel@tonic-gate * Now map the supported feature vector to 27537c478bd9Sstevel@tonic-gate * things that we think userland will care about. 27547c478bd9Sstevel@tonic-gate */ 2755ae115bc7Smrj #if defined(__amd64) 27567c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_SYSC) 27577c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_SYSC; 2758ae115bc7Smrj #endif 27597c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_MMXamd) 27607c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_MMX; 27617c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_3DNow) 27627c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_3DNow; 27637c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_3DNowx) 27647c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_3DNowx; 2765faa20166SBryan Cantrill if (*ecx & CPUID_AMD_ECX_SVM) 2766faa20166SBryan Cantrill hwcap_flags |= AV_386_AMD_SVM; 2767ae115bc7Smrj 2768ae115bc7Smrj switch (cpi->cpi_vendor) { 2769ae115bc7Smrj case X86_VENDOR_AMD: 2770ae115bc7Smrj if (*edx & CPUID_AMD_EDX_TSCP) 2771ae115bc7Smrj hwcap_flags |= AV_386_TSCP; 2772ae115bc7Smrj if (*ecx & CPUID_AMD_ECX_AHF64) 2773ae115bc7Smrj hwcap_flags |= AV_386_AHF; 2774f8801251Skk208521 if (*ecx & CPUID_AMD_ECX_SSE4A) 2775f8801251Skk208521 hwcap_flags |= AV_386_AMD_SSE4A; 2776f8801251Skk208521 if (*ecx & CPUID_AMD_ECX_LZCNT) 2777f8801251Skk208521 hwcap_flags |= AV_386_AMD_LZCNT; 2778ae115bc7Smrj break; 2779ae115bc7Smrj 2780ae115bc7Smrj case X86_VENDOR_Intel: 2781d36ea5d8Ssudheer if (*edx & CPUID_AMD_EDX_TSCP) 2782d36ea5d8Ssudheer hwcap_flags |= AV_386_TSCP; 2783ae115bc7Smrj /* 2784ae115bc7Smrj * Aarrgh. 2785ae115bc7Smrj * Intel uses a different bit in the same word. 2786ae115bc7Smrj */ 2787ae115bc7Smrj if (*ecx & CPUID_INTC_ECX_AHF64) 2788ae115bc7Smrj hwcap_flags |= AV_386_AHF; 2789ae115bc7Smrj break; 2790ae115bc7Smrj 2791ae115bc7Smrj default: 2792ae115bc7Smrj break; 2793ae115bc7Smrj } 27947c478bd9Sstevel@tonic-gate break; 27957c478bd9Sstevel@tonic-gate 27967c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 27978949bcd6Sandrei cp.cp_eax = 0x80860001; 27988949bcd6Sandrei (void) __cpuid_insn(&cp); 27998949bcd6Sandrei cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx; 28007c478bd9Sstevel@tonic-gate break; 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate default: 28037c478bd9Sstevel@tonic-gate break; 28047c478bd9Sstevel@tonic-gate } 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate pass4_done: 28077c478bd9Sstevel@tonic-gate cpi->cpi_pass = 4; 2808ebb8ac07SRobert Mustacchi if (hwcap_out != NULL) { 2809ebb8ac07SRobert Mustacchi hwcap_out[0] = hwcap_flags; 2810ebb8ac07SRobert Mustacchi hwcap_out[1] = hwcap_flags_2; 2811ebb8ac07SRobert Mustacchi } 28127c478bd9Sstevel@tonic-gate } 28137c478bd9Sstevel@tonic-gate 28147c478bd9Sstevel@tonic-gate 28157c478bd9Sstevel@tonic-gate /* 28167c478bd9Sstevel@tonic-gate * Simulate the cpuid instruction using the data we previously 28177c478bd9Sstevel@tonic-gate * captured about this CPU. We try our best to return the truth 28187c478bd9Sstevel@tonic-gate * about the hardware, independently of kernel support. 28197c478bd9Sstevel@tonic-gate */ 28207c478bd9Sstevel@tonic-gate uint32_t 28218949bcd6Sandrei cpuid_insn(cpu_t *cpu, struct cpuid_regs *cp) 28227c478bd9Sstevel@tonic-gate { 28237c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 28248949bcd6Sandrei struct cpuid_regs *xcp; 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate if (cpu == NULL) 28277c478bd9Sstevel@tonic-gate cpu = CPU; 28287c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 3)); 28317c478bd9Sstevel@tonic-gate 28327c478bd9Sstevel@tonic-gate /* 28337c478bd9Sstevel@tonic-gate * CPUID data is cached in two separate places: cpi_std for standard 28347c478bd9Sstevel@tonic-gate * CPUID functions, and cpi_extd for extended CPUID functions. 28357c478bd9Sstevel@tonic-gate */ 28368949bcd6Sandrei if (cp->cp_eax <= cpi->cpi_maxeax && cp->cp_eax < NMAX_CPI_STD) 28378949bcd6Sandrei xcp = &cpi->cpi_std[cp->cp_eax]; 28388949bcd6Sandrei else if (cp->cp_eax >= 0x80000000 && cp->cp_eax <= cpi->cpi_xmaxeax && 28398949bcd6Sandrei cp->cp_eax < 0x80000000 + NMAX_CPI_EXTD) 28408949bcd6Sandrei xcp = &cpi->cpi_extd[cp->cp_eax - 0x80000000]; 28417c478bd9Sstevel@tonic-gate else 28427c478bd9Sstevel@tonic-gate /* 28437c478bd9Sstevel@tonic-gate * The caller is asking for data from an input parameter which 28447c478bd9Sstevel@tonic-gate * the kernel has not cached. In this case we go fetch from 28457c478bd9Sstevel@tonic-gate * the hardware and return the data directly to the user. 28467c478bd9Sstevel@tonic-gate */ 28478949bcd6Sandrei return (__cpuid_insn(cp)); 28488949bcd6Sandrei 28498949bcd6Sandrei cp->cp_eax = xcp->cp_eax; 28508949bcd6Sandrei cp->cp_ebx = xcp->cp_ebx; 28518949bcd6Sandrei cp->cp_ecx = xcp->cp_ecx; 28528949bcd6Sandrei cp->cp_edx = xcp->cp_edx; 28537c478bd9Sstevel@tonic-gate return (cp->cp_eax); 28547c478bd9Sstevel@tonic-gate } 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate int 28577c478bd9Sstevel@tonic-gate cpuid_checkpass(cpu_t *cpu, int pass) 28587c478bd9Sstevel@tonic-gate { 28597c478bd9Sstevel@tonic-gate return (cpu != NULL && cpu->cpu_m.mcpu_cpi != NULL && 28607c478bd9Sstevel@tonic-gate cpu->cpu_m.mcpu_cpi->cpi_pass >= pass); 28617c478bd9Sstevel@tonic-gate } 28627c478bd9Sstevel@tonic-gate 28637c478bd9Sstevel@tonic-gate int 28647c478bd9Sstevel@tonic-gate cpuid_getbrandstr(cpu_t *cpu, char *s, size_t n) 28657c478bd9Sstevel@tonic-gate { 28667c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 3)); 28677c478bd9Sstevel@tonic-gate 28687c478bd9Sstevel@tonic-gate return (snprintf(s, n, "%s", cpu->cpu_m.mcpu_cpi->cpi_brandstr)); 28697c478bd9Sstevel@tonic-gate } 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate int 28728949bcd6Sandrei cpuid_is_cmt(cpu_t *cpu) 28737c478bd9Sstevel@tonic-gate { 28747c478bd9Sstevel@tonic-gate if (cpu == NULL) 28757c478bd9Sstevel@tonic-gate cpu = CPU; 28767c478bd9Sstevel@tonic-gate 28777c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 28787c478bd9Sstevel@tonic-gate 28797c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_chipid >= 0); 28807c478bd9Sstevel@tonic-gate } 28817c478bd9Sstevel@tonic-gate 28827c478bd9Sstevel@tonic-gate /* 28837c478bd9Sstevel@tonic-gate * AMD and Intel both implement the 64-bit variant of the syscall 28847c478bd9Sstevel@tonic-gate * instruction (syscallq), so if there's -any- support for syscall, 28857c478bd9Sstevel@tonic-gate * cpuid currently says "yes, we support this". 28867c478bd9Sstevel@tonic-gate * 28877c478bd9Sstevel@tonic-gate * However, Intel decided to -not- implement the 32-bit variant of the 28887c478bd9Sstevel@tonic-gate * syscall instruction, so we provide a predicate to allow our caller 28897c478bd9Sstevel@tonic-gate * to test that subtlety here. 2890843e1988Sjohnlev * 2891843e1988Sjohnlev * XXPV Currently, 32-bit syscall instructions don't work via the hypervisor, 2892843e1988Sjohnlev * even in the case where the hardware would in fact support it. 28937c478bd9Sstevel@tonic-gate */ 28947c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28957c478bd9Sstevel@tonic-gate int 28967c478bd9Sstevel@tonic-gate cpuid_syscall32_insn(cpu_t *cpu) 28977c478bd9Sstevel@tonic-gate { 28987c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass((cpu == NULL ? CPU : cpu), 1)); 28997c478bd9Sstevel@tonic-gate 2900843e1988Sjohnlev #if !defined(__xpv) 2901ae115bc7Smrj if (cpu == NULL) 2902ae115bc7Smrj cpu = CPU; 2903ae115bc7Smrj 2904ae115bc7Smrj /*CSTYLED*/ 2905ae115bc7Smrj { 2906ae115bc7Smrj struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 2907ae115bc7Smrj 2908ae115bc7Smrj if (cpi->cpi_vendor == X86_VENDOR_AMD && 2909ae115bc7Smrj cpi->cpi_xmaxeax >= 0x80000001 && 2910ae115bc7Smrj (CPI_FEATURES_XTD_EDX(cpi) & CPUID_AMD_EDX_SYSC)) 2911ae115bc7Smrj return (1); 2912ae115bc7Smrj } 2913843e1988Sjohnlev #endif 29147c478bd9Sstevel@tonic-gate return (0); 29157c478bd9Sstevel@tonic-gate } 29167c478bd9Sstevel@tonic-gate 29177c478bd9Sstevel@tonic-gate int 29187c478bd9Sstevel@tonic-gate cpuid_getidstr(cpu_t *cpu, char *s, size_t n) 29197c478bd9Sstevel@tonic-gate { 29207c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 29217c478bd9Sstevel@tonic-gate 29227c478bd9Sstevel@tonic-gate static const char fmt[] = 2923ecfa43a5Sdmick "x86 (%s %X family %d model %d step %d clock %d MHz)"; 29247c478bd9Sstevel@tonic-gate static const char fmt_ht[] = 2925ecfa43a5Sdmick "x86 (chipid 0x%x %s %X family %d model %d step %d clock %d MHz)"; 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29287c478bd9Sstevel@tonic-gate 29298949bcd6Sandrei if (cpuid_is_cmt(cpu)) 29307c478bd9Sstevel@tonic-gate return (snprintf(s, n, fmt_ht, cpi->cpi_chipid, 2931ecfa43a5Sdmick cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax, 2932ecfa43a5Sdmick cpi->cpi_family, cpi->cpi_model, 29337c478bd9Sstevel@tonic-gate cpi->cpi_step, cpu->cpu_type_info.pi_clock)); 29347c478bd9Sstevel@tonic-gate return (snprintf(s, n, fmt, 2935ecfa43a5Sdmick cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax, 2936ecfa43a5Sdmick cpi->cpi_family, cpi->cpi_model, 29377c478bd9Sstevel@tonic-gate cpi->cpi_step, cpu->cpu_type_info.pi_clock)); 29387c478bd9Sstevel@tonic-gate } 29397c478bd9Sstevel@tonic-gate 29407c478bd9Sstevel@tonic-gate const char * 29417c478bd9Sstevel@tonic-gate cpuid_getvendorstr(cpu_t *cpu) 29427c478bd9Sstevel@tonic-gate { 29437c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29447c478bd9Sstevel@tonic-gate return ((const char *)cpu->cpu_m.mcpu_cpi->cpi_vendorstr); 29457c478bd9Sstevel@tonic-gate } 29467c478bd9Sstevel@tonic-gate 29477c478bd9Sstevel@tonic-gate uint_t 29487c478bd9Sstevel@tonic-gate cpuid_getvendor(cpu_t *cpu) 29497c478bd9Sstevel@tonic-gate { 29507c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29517c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_vendor); 29527c478bd9Sstevel@tonic-gate } 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate uint_t 29557c478bd9Sstevel@tonic-gate cpuid_getfamily(cpu_t *cpu) 29567c478bd9Sstevel@tonic-gate { 29577c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29587c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_family); 29597c478bd9Sstevel@tonic-gate } 29607c478bd9Sstevel@tonic-gate 29617c478bd9Sstevel@tonic-gate uint_t 29627c478bd9Sstevel@tonic-gate cpuid_getmodel(cpu_t *cpu) 29637c478bd9Sstevel@tonic-gate { 29647c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29657c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_model); 29667c478bd9Sstevel@tonic-gate } 29677c478bd9Sstevel@tonic-gate 29687c478bd9Sstevel@tonic-gate uint_t 29697c478bd9Sstevel@tonic-gate cpuid_get_ncpu_per_chip(cpu_t *cpu) 29707c478bd9Sstevel@tonic-gate { 29717c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29727c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_per_chip); 29737c478bd9Sstevel@tonic-gate } 29747c478bd9Sstevel@tonic-gate 29757c478bd9Sstevel@tonic-gate uint_t 29768949bcd6Sandrei cpuid_get_ncore_per_chip(cpu_t *cpu) 29778949bcd6Sandrei { 29788949bcd6Sandrei ASSERT(cpuid_checkpass(cpu, 1)); 29798949bcd6Sandrei return (cpu->cpu_m.mcpu_cpi->cpi_ncore_per_chip); 29808949bcd6Sandrei } 29818949bcd6Sandrei 29828949bcd6Sandrei uint_t 2983d129bde2Sesaxe cpuid_get_ncpu_sharing_last_cache(cpu_t *cpu) 2984d129bde2Sesaxe { 2985d129bde2Sesaxe ASSERT(cpuid_checkpass(cpu, 2)); 2986d129bde2Sesaxe return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_shr_last_cache); 2987d129bde2Sesaxe } 2988d129bde2Sesaxe 2989d129bde2Sesaxe id_t 2990d129bde2Sesaxe cpuid_get_last_lvl_cacheid(cpu_t *cpu) 2991d129bde2Sesaxe { 2992d129bde2Sesaxe ASSERT(cpuid_checkpass(cpu, 2)); 2993d129bde2Sesaxe return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid); 2994d129bde2Sesaxe } 2995d129bde2Sesaxe 2996d129bde2Sesaxe uint_t 29977c478bd9Sstevel@tonic-gate cpuid_getstep(cpu_t *cpu) 29987c478bd9Sstevel@tonic-gate { 29997c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30007c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_step); 30017c478bd9Sstevel@tonic-gate } 30027c478bd9Sstevel@tonic-gate 30032449e17fSsherrym uint_t 30042449e17fSsherrym cpuid_getsig(struct cpu *cpu) 30052449e17fSsherrym { 30062449e17fSsherrym ASSERT(cpuid_checkpass(cpu, 1)); 30072449e17fSsherrym return (cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_eax); 30082449e17fSsherrym } 30092449e17fSsherrym 30108a40a695Sgavinm uint32_t 30118a40a695Sgavinm cpuid_getchiprev(struct cpu *cpu) 30128a40a695Sgavinm { 30138a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 30148a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_chiprev); 30158a40a695Sgavinm } 30168a40a695Sgavinm 30178a40a695Sgavinm const char * 30188a40a695Sgavinm cpuid_getchiprevstr(struct cpu *cpu) 30198a40a695Sgavinm { 30208a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 30218a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_chiprevstr); 30228a40a695Sgavinm } 30238a40a695Sgavinm 30248a40a695Sgavinm uint32_t 30258a40a695Sgavinm cpuid_getsockettype(struct cpu *cpu) 30268a40a695Sgavinm { 30278a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 30288a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_socket); 30298a40a695Sgavinm } 30308a40a695Sgavinm 303189e921d5SKuriakose Kuruvilla const char * 303289e921d5SKuriakose Kuruvilla cpuid_getsocketstr(cpu_t *cpu) 303389e921d5SKuriakose Kuruvilla { 303489e921d5SKuriakose Kuruvilla static const char *socketstr = NULL; 303589e921d5SKuriakose Kuruvilla struct cpuid_info *cpi; 303689e921d5SKuriakose Kuruvilla 303789e921d5SKuriakose Kuruvilla ASSERT(cpuid_checkpass(cpu, 1)); 303889e921d5SKuriakose Kuruvilla cpi = cpu->cpu_m.mcpu_cpi; 303989e921d5SKuriakose Kuruvilla 304089e921d5SKuriakose Kuruvilla /* Assume that socket types are the same across the system */ 304189e921d5SKuriakose Kuruvilla if (socketstr == NULL) 304289e921d5SKuriakose Kuruvilla socketstr = _cpuid_sktstr(cpi->cpi_vendor, cpi->cpi_family, 304389e921d5SKuriakose Kuruvilla cpi->cpi_model, cpi->cpi_step); 304489e921d5SKuriakose Kuruvilla 304589e921d5SKuriakose Kuruvilla 304689e921d5SKuriakose Kuruvilla return (socketstr); 304789e921d5SKuriakose Kuruvilla } 304889e921d5SKuriakose Kuruvilla 3049fb2f18f8Sesaxe int 3050fb2f18f8Sesaxe cpuid_get_chipid(cpu_t *cpu) 30517c478bd9Sstevel@tonic-gate { 30527c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30537c478bd9Sstevel@tonic-gate 30548949bcd6Sandrei if (cpuid_is_cmt(cpu)) 30557c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_chipid); 30567c478bd9Sstevel@tonic-gate return (cpu->cpu_id); 30577c478bd9Sstevel@tonic-gate } 30587c478bd9Sstevel@tonic-gate 30598949bcd6Sandrei id_t 3060fb2f18f8Sesaxe cpuid_get_coreid(cpu_t *cpu) 30618949bcd6Sandrei { 30628949bcd6Sandrei ASSERT(cpuid_checkpass(cpu, 1)); 30638949bcd6Sandrei return (cpu->cpu_m.mcpu_cpi->cpi_coreid); 30648949bcd6Sandrei } 30658949bcd6Sandrei 30667c478bd9Sstevel@tonic-gate int 306710569901Sgavinm cpuid_get_pkgcoreid(cpu_t *cpu) 306810569901Sgavinm { 306910569901Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 307010569901Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_pkgcoreid); 307110569901Sgavinm } 307210569901Sgavinm 307310569901Sgavinm int 3074fb2f18f8Sesaxe cpuid_get_clogid(cpu_t *cpu) 30757c478bd9Sstevel@tonic-gate { 30767c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30777c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_clogid); 30787c478bd9Sstevel@tonic-gate } 30797c478bd9Sstevel@tonic-gate 3080b885580bSAlexander Kolbasov int 3081b885580bSAlexander Kolbasov cpuid_get_cacheid(cpu_t *cpu) 3082b885580bSAlexander Kolbasov { 3083b885580bSAlexander Kolbasov ASSERT(cpuid_checkpass(cpu, 1)); 3084b885580bSAlexander Kolbasov return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid); 3085b885580bSAlexander Kolbasov } 3086b885580bSAlexander Kolbasov 30878031591dSSrihari Venkatesan uint_t 30888031591dSSrihari Venkatesan cpuid_get_procnodeid(cpu_t *cpu) 30898031591dSSrihari Venkatesan { 30908031591dSSrihari Venkatesan ASSERT(cpuid_checkpass(cpu, 1)); 30918031591dSSrihari Venkatesan return (cpu->cpu_m.mcpu_cpi->cpi_procnodeid); 30928031591dSSrihari Venkatesan } 30938031591dSSrihari Venkatesan 30948031591dSSrihari Venkatesan uint_t 30958031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg(cpu_t *cpu) 30968031591dSSrihari Venkatesan { 30978031591dSSrihari Venkatesan ASSERT(cpuid_checkpass(cpu, 1)); 30988031591dSSrihari Venkatesan return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg); 30998031591dSSrihari Venkatesan } 31008031591dSSrihari Venkatesan 31017660e73fSHans Rosenfeld uint_t 31027660e73fSHans Rosenfeld cpuid_get_compunitid(cpu_t *cpu) 31037660e73fSHans Rosenfeld { 31047660e73fSHans Rosenfeld ASSERT(cpuid_checkpass(cpu, 1)); 31057660e73fSHans Rosenfeld return (cpu->cpu_m.mcpu_cpi->cpi_compunitid); 31067660e73fSHans Rosenfeld } 31077660e73fSHans Rosenfeld 31087660e73fSHans Rosenfeld uint_t 31097660e73fSHans Rosenfeld cpuid_get_cores_per_compunit(cpu_t *cpu) 31107660e73fSHans Rosenfeld { 31117660e73fSHans Rosenfeld ASSERT(cpuid_checkpass(cpu, 1)); 31127660e73fSHans Rosenfeld return (cpu->cpu_m.mcpu_cpi->cpi_cores_per_compunit); 31137660e73fSHans Rosenfeld } 31147660e73fSHans Rosenfeld 31152ef50f01SJoe Bonasera /*ARGSUSED*/ 31162ef50f01SJoe Bonasera int 31172ef50f01SJoe Bonasera cpuid_have_cr8access(cpu_t *cpu) 31182ef50f01SJoe Bonasera { 31192ef50f01SJoe Bonasera #if defined(__amd64) 31202ef50f01SJoe Bonasera return (1); 31212ef50f01SJoe Bonasera #else 31222ef50f01SJoe Bonasera struct cpuid_info *cpi; 31232ef50f01SJoe Bonasera 31242ef50f01SJoe Bonasera ASSERT(cpu != NULL); 31252ef50f01SJoe Bonasera cpi = cpu->cpu_m.mcpu_cpi; 31262ef50f01SJoe Bonasera if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 && 31272ef50f01SJoe Bonasera (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0) 31282ef50f01SJoe Bonasera return (1); 31292ef50f01SJoe Bonasera return (0); 31302ef50f01SJoe Bonasera #endif 31312ef50f01SJoe Bonasera } 31322ef50f01SJoe Bonasera 3133fa96bd91SMichael Corcoran uint32_t 3134fa96bd91SMichael Corcoran cpuid_get_apicid(cpu_t *cpu) 3135fa96bd91SMichael Corcoran { 3136fa96bd91SMichael Corcoran ASSERT(cpuid_checkpass(cpu, 1)); 3137fa96bd91SMichael Corcoran if (cpu->cpu_m.mcpu_cpi->cpi_maxeax < 1) { 3138fa96bd91SMichael Corcoran return (UINT32_MAX); 3139fa96bd91SMichael Corcoran } else { 3140fa96bd91SMichael Corcoran return (cpu->cpu_m.mcpu_cpi->cpi_apicid); 3141fa96bd91SMichael Corcoran } 3142fa96bd91SMichael Corcoran } 3143fa96bd91SMichael Corcoran 31447c478bd9Sstevel@tonic-gate void 31457c478bd9Sstevel@tonic-gate cpuid_get_addrsize(cpu_t *cpu, uint_t *pabits, uint_t *vabits) 31467c478bd9Sstevel@tonic-gate { 31477c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 31487c478bd9Sstevel@tonic-gate 31497c478bd9Sstevel@tonic-gate if (cpu == NULL) 31507c478bd9Sstevel@tonic-gate cpu = CPU; 31517c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 31527c478bd9Sstevel@tonic-gate 31537c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 31547c478bd9Sstevel@tonic-gate 31557c478bd9Sstevel@tonic-gate if (pabits) 31567c478bd9Sstevel@tonic-gate *pabits = cpi->cpi_pabits; 31577c478bd9Sstevel@tonic-gate if (vabits) 31587c478bd9Sstevel@tonic-gate *vabits = cpi->cpi_vabits; 31597c478bd9Sstevel@tonic-gate } 31607c478bd9Sstevel@tonic-gate 31617c478bd9Sstevel@tonic-gate /* 31627c478bd9Sstevel@tonic-gate * Returns the number of data TLB entries for a corresponding 31637c478bd9Sstevel@tonic-gate * pagesize. If it can't be computed, or isn't known, the 31647c478bd9Sstevel@tonic-gate * routine returns zero. If you ask about an architecturally 31657c478bd9Sstevel@tonic-gate * impossible pagesize, the routine will panic (so that the 31667c478bd9Sstevel@tonic-gate * hat implementor knows that things are inconsistent.) 31677c478bd9Sstevel@tonic-gate */ 31687c478bd9Sstevel@tonic-gate uint_t 31697c478bd9Sstevel@tonic-gate cpuid_get_dtlb_nent(cpu_t *cpu, size_t pagesize) 31707c478bd9Sstevel@tonic-gate { 31717c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 31727c478bd9Sstevel@tonic-gate uint_t dtlb_nent = 0; 31737c478bd9Sstevel@tonic-gate 31747c478bd9Sstevel@tonic-gate if (cpu == NULL) 31757c478bd9Sstevel@tonic-gate cpu = CPU; 31767c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 31777c478bd9Sstevel@tonic-gate 31787c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 31797c478bd9Sstevel@tonic-gate 31807c478bd9Sstevel@tonic-gate /* 31817c478bd9Sstevel@tonic-gate * Check the L2 TLB info 31827c478bd9Sstevel@tonic-gate */ 31837c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000006) { 31848949bcd6Sandrei struct cpuid_regs *cp = &cpi->cpi_extd[6]; 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate switch (pagesize) { 31877c478bd9Sstevel@tonic-gate 31887c478bd9Sstevel@tonic-gate case 4 * 1024: 31897c478bd9Sstevel@tonic-gate /* 31907c478bd9Sstevel@tonic-gate * All zero in the top 16 bits of the register 31917c478bd9Sstevel@tonic-gate * indicates a unified TLB. Size is in low 16 bits. 31927c478bd9Sstevel@tonic-gate */ 31937c478bd9Sstevel@tonic-gate if ((cp->cp_ebx & 0xffff0000) == 0) 31947c478bd9Sstevel@tonic-gate dtlb_nent = cp->cp_ebx & 0x0000ffff; 31957c478bd9Sstevel@tonic-gate else 31967c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_ebx, 27, 16); 31977c478bd9Sstevel@tonic-gate break; 31987c478bd9Sstevel@tonic-gate 31997c478bd9Sstevel@tonic-gate case 2 * 1024 * 1024: 32007c478bd9Sstevel@tonic-gate if ((cp->cp_eax & 0xffff0000) == 0) 32017c478bd9Sstevel@tonic-gate dtlb_nent = cp->cp_eax & 0x0000ffff; 32027c478bd9Sstevel@tonic-gate else 32037c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_eax, 27, 16); 32047c478bd9Sstevel@tonic-gate break; 32057c478bd9Sstevel@tonic-gate 32067c478bd9Sstevel@tonic-gate default: 32077c478bd9Sstevel@tonic-gate panic("unknown L2 pagesize"); 32087c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 32097c478bd9Sstevel@tonic-gate } 32107c478bd9Sstevel@tonic-gate } 32117c478bd9Sstevel@tonic-gate 32127c478bd9Sstevel@tonic-gate if (dtlb_nent != 0) 32137c478bd9Sstevel@tonic-gate return (dtlb_nent); 32147c478bd9Sstevel@tonic-gate 32157c478bd9Sstevel@tonic-gate /* 32167c478bd9Sstevel@tonic-gate * No L2 TLB support for this size, try L1. 32177c478bd9Sstevel@tonic-gate */ 32187c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000005) { 32198949bcd6Sandrei struct cpuid_regs *cp = &cpi->cpi_extd[5]; 32207c478bd9Sstevel@tonic-gate 32217c478bd9Sstevel@tonic-gate switch (pagesize) { 32227c478bd9Sstevel@tonic-gate case 4 * 1024: 32237c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_ebx, 23, 16); 32247c478bd9Sstevel@tonic-gate break; 32257c478bd9Sstevel@tonic-gate case 2 * 1024 * 1024: 32267c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_eax, 23, 16); 32277c478bd9Sstevel@tonic-gate break; 32287c478bd9Sstevel@tonic-gate default: 32297c478bd9Sstevel@tonic-gate panic("unknown L1 d-TLB pagesize"); 32307c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 32317c478bd9Sstevel@tonic-gate } 32327c478bd9Sstevel@tonic-gate } 32337c478bd9Sstevel@tonic-gate 32347c478bd9Sstevel@tonic-gate return (dtlb_nent); 32357c478bd9Sstevel@tonic-gate } 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate /* 32387c478bd9Sstevel@tonic-gate * Return 0 if the erratum is not present or not applicable, positive 32397c478bd9Sstevel@tonic-gate * if it is, and negative if the status of the erratum is unknown. 32407c478bd9Sstevel@tonic-gate * 32417c478bd9Sstevel@tonic-gate * See "Revision Guide for AMD Athlon(tm) 64 and AMD Opteron(tm) 32422201b277Skucharsk * Processors" #25759, Rev 3.57, August 2005 32437c478bd9Sstevel@tonic-gate */ 32447c478bd9Sstevel@tonic-gate int 32457c478bd9Sstevel@tonic-gate cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum) 32467c478bd9Sstevel@tonic-gate { 32477c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 32488949bcd6Sandrei uint_t eax; 32497c478bd9Sstevel@tonic-gate 3250ea99987eSsethg /* 3251ea99987eSsethg * Bail out if this CPU isn't an AMD CPU, or if it's 3252ea99987eSsethg * a legacy (32-bit) AMD CPU. 3253ea99987eSsethg */ 3254ea99987eSsethg if (cpi->cpi_vendor != X86_VENDOR_AMD || 3255875b116eSkchow cpi->cpi_family == 4 || cpi->cpi_family == 5 || 3256875b116eSkchow cpi->cpi_family == 6) 32578a40a695Sgavinm 32587c478bd9Sstevel@tonic-gate return (0); 32597c478bd9Sstevel@tonic-gate 32607c478bd9Sstevel@tonic-gate eax = cpi->cpi_std[1].cp_eax; 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate #define SH_B0(eax) (eax == 0xf40 || eax == 0xf50) 32637c478bd9Sstevel@tonic-gate #define SH_B3(eax) (eax == 0xf51) 3264ee88d2b9Skchow #define B(eax) (SH_B0(eax) || SH_B3(eax)) 32657c478bd9Sstevel@tonic-gate 32667c478bd9Sstevel@tonic-gate #define SH_C0(eax) (eax == 0xf48 || eax == 0xf58) 32677c478bd9Sstevel@tonic-gate 32687c478bd9Sstevel@tonic-gate #define SH_CG(eax) (eax == 0xf4a || eax == 0xf5a || eax == 0xf7a) 32697c478bd9Sstevel@tonic-gate #define DH_CG(eax) (eax == 0xfc0 || eax == 0xfe0 || eax == 0xff0) 32707c478bd9Sstevel@tonic-gate #define CH_CG(eax) (eax == 0xf82 || eax == 0xfb2) 3271ee88d2b9Skchow #define CG(eax) (SH_CG(eax) || DH_CG(eax) || CH_CG(eax)) 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate #define SH_D0(eax) (eax == 0x10f40 || eax == 0x10f50 || eax == 0x10f70) 32747c478bd9Sstevel@tonic-gate #define DH_D0(eax) (eax == 0x10fc0 || eax == 0x10ff0) 32757c478bd9Sstevel@tonic-gate #define CH_D0(eax) (eax == 0x10f80 || eax == 0x10fb0) 3276ee88d2b9Skchow #define D0(eax) (SH_D0(eax) || DH_D0(eax) || CH_D0(eax)) 32777c478bd9Sstevel@tonic-gate 32787c478bd9Sstevel@tonic-gate #define SH_E0(eax) (eax == 0x20f50 || eax == 0x20f40 || eax == 0x20f70) 32797c478bd9Sstevel@tonic-gate #define JH_E1(eax) (eax == 0x20f10) /* JH8_E0 had 0x20f30 */ 32807c478bd9Sstevel@tonic-gate #define DH_E3(eax) (eax == 0x20fc0 || eax == 0x20ff0) 32817c478bd9Sstevel@tonic-gate #define SH_E4(eax) (eax == 0x20f51 || eax == 0x20f71) 32827c478bd9Sstevel@tonic-gate #define BH_E4(eax) (eax == 0x20fb1) 32837c478bd9Sstevel@tonic-gate #define SH_E5(eax) (eax == 0x20f42) 32847c478bd9Sstevel@tonic-gate #define DH_E6(eax) (eax == 0x20ff2 || eax == 0x20fc2) 32857c478bd9Sstevel@tonic-gate #define JH_E6(eax) (eax == 0x20f12 || eax == 0x20f32) 3286ee88d2b9Skchow #define EX(eax) (SH_E0(eax) || JH_E1(eax) || DH_E3(eax) || \ 3287ee88d2b9Skchow SH_E4(eax) || BH_E4(eax) || SH_E5(eax) || \ 3288ee88d2b9Skchow DH_E6(eax) || JH_E6(eax)) 32897c478bd9Sstevel@tonic-gate 3290512cf780Skchow #define DR_AX(eax) (eax == 0x100f00 || eax == 0x100f01 || eax == 0x100f02) 3291512cf780Skchow #define DR_B0(eax) (eax == 0x100f20) 3292512cf780Skchow #define DR_B1(eax) (eax == 0x100f21) 3293512cf780Skchow #define DR_BA(eax) (eax == 0x100f2a) 3294512cf780Skchow #define DR_B2(eax) (eax == 0x100f22) 3295512cf780Skchow #define DR_B3(eax) (eax == 0x100f23) 3296512cf780Skchow #define RB_C0(eax) (eax == 0x100f40) 3297512cf780Skchow 32987c478bd9Sstevel@tonic-gate switch (erratum) { 32997c478bd9Sstevel@tonic-gate case 1: 3300875b116eSkchow return (cpi->cpi_family < 0x10); 33017c478bd9Sstevel@tonic-gate case 51: /* what does the asterisk mean? */ 33027c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 33037c478bd9Sstevel@tonic-gate case 52: 33047c478bd9Sstevel@tonic-gate return (B(eax)); 33057c478bd9Sstevel@tonic-gate case 57: 3306512cf780Skchow return (cpi->cpi_family <= 0x11); 33077c478bd9Sstevel@tonic-gate case 58: 33087c478bd9Sstevel@tonic-gate return (B(eax)); 33097c478bd9Sstevel@tonic-gate case 60: 3310512cf780Skchow return (cpi->cpi_family <= 0x11); 33117c478bd9Sstevel@tonic-gate case 61: 33127c478bd9Sstevel@tonic-gate case 62: 33137c478bd9Sstevel@tonic-gate case 63: 33147c478bd9Sstevel@tonic-gate case 64: 33157c478bd9Sstevel@tonic-gate case 65: 33167c478bd9Sstevel@tonic-gate case 66: 33177c478bd9Sstevel@tonic-gate case 68: 33187c478bd9Sstevel@tonic-gate case 69: 33197c478bd9Sstevel@tonic-gate case 70: 33207c478bd9Sstevel@tonic-gate case 71: 33217c478bd9Sstevel@tonic-gate return (B(eax)); 33227c478bd9Sstevel@tonic-gate case 72: 33237c478bd9Sstevel@tonic-gate return (SH_B0(eax)); 33247c478bd9Sstevel@tonic-gate case 74: 33257c478bd9Sstevel@tonic-gate return (B(eax)); 33267c478bd9Sstevel@tonic-gate case 75: 3327875b116eSkchow return (cpi->cpi_family < 0x10); 33287c478bd9Sstevel@tonic-gate case 76: 33297c478bd9Sstevel@tonic-gate return (B(eax)); 33307c478bd9Sstevel@tonic-gate case 77: 3331512cf780Skchow return (cpi->cpi_family <= 0x11); 33327c478bd9Sstevel@tonic-gate case 78: 33337c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 33347c478bd9Sstevel@tonic-gate case 79: 33357c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 33367c478bd9Sstevel@tonic-gate case 80: 33377c478bd9Sstevel@tonic-gate case 81: 33387c478bd9Sstevel@tonic-gate case 82: 33397c478bd9Sstevel@tonic-gate return (B(eax)); 33407c478bd9Sstevel@tonic-gate case 83: 33417c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 33427c478bd9Sstevel@tonic-gate case 85: 3343875b116eSkchow return (cpi->cpi_family < 0x10); 33447c478bd9Sstevel@tonic-gate case 86: 33457c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax)); 33467c478bd9Sstevel@tonic-gate case 88: 33477c478bd9Sstevel@tonic-gate #if !defined(__amd64) 33487c478bd9Sstevel@tonic-gate return (0); 33497c478bd9Sstevel@tonic-gate #else 33507c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 33517c478bd9Sstevel@tonic-gate #endif 33527c478bd9Sstevel@tonic-gate case 89: 3353875b116eSkchow return (cpi->cpi_family < 0x10); 33547c478bd9Sstevel@tonic-gate case 90: 33557c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 33567c478bd9Sstevel@tonic-gate case 91: 33577c478bd9Sstevel@tonic-gate case 92: 33587c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 33597c478bd9Sstevel@tonic-gate case 93: 33607c478bd9Sstevel@tonic-gate return (SH_C0(eax)); 33617c478bd9Sstevel@tonic-gate case 94: 33627c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 33637c478bd9Sstevel@tonic-gate case 95: 33647c478bd9Sstevel@tonic-gate #if !defined(__amd64) 33657c478bd9Sstevel@tonic-gate return (0); 33667c478bd9Sstevel@tonic-gate #else 33677c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 33687c478bd9Sstevel@tonic-gate #endif 33697c478bd9Sstevel@tonic-gate case 96: 33707c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 33717c478bd9Sstevel@tonic-gate case 97: 33727c478bd9Sstevel@tonic-gate case 98: 33737c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax)); 33747c478bd9Sstevel@tonic-gate case 99: 33757c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 33767c478bd9Sstevel@tonic-gate case 100: 33777c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 33787c478bd9Sstevel@tonic-gate case 101: 33797c478bd9Sstevel@tonic-gate case 103: 33807c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 33817c478bd9Sstevel@tonic-gate case 104: 33827c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax) || D0(eax)); 33837c478bd9Sstevel@tonic-gate case 105: 33847c478bd9Sstevel@tonic-gate case 106: 33857c478bd9Sstevel@tonic-gate case 107: 33867c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 33877c478bd9Sstevel@tonic-gate case 108: 33887c478bd9Sstevel@tonic-gate return (DH_CG(eax)); 33897c478bd9Sstevel@tonic-gate case 109: 33907c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax) || D0(eax)); 33917c478bd9Sstevel@tonic-gate case 110: 33927c478bd9Sstevel@tonic-gate return (D0(eax) || EX(eax)); 33937c478bd9Sstevel@tonic-gate case 111: 33947c478bd9Sstevel@tonic-gate return (CG(eax)); 33957c478bd9Sstevel@tonic-gate case 112: 33967c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 33977c478bd9Sstevel@tonic-gate case 113: 33987c478bd9Sstevel@tonic-gate return (eax == 0x20fc0); 33997c478bd9Sstevel@tonic-gate case 114: 34007c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax)); 34017c478bd9Sstevel@tonic-gate case 115: 34027c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax)); 34037c478bd9Sstevel@tonic-gate case 116: 34047c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax)); 34057c478bd9Sstevel@tonic-gate case 117: 34067c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 34077c478bd9Sstevel@tonic-gate case 118: 34087c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || SH_E4(eax) || BH_E4(eax) || 34097c478bd9Sstevel@tonic-gate JH_E6(eax)); 34107c478bd9Sstevel@tonic-gate case 121: 34117c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 34127c478bd9Sstevel@tonic-gate case 122: 3413512cf780Skchow return (cpi->cpi_family < 0x10 || cpi->cpi_family == 0x11); 34147c478bd9Sstevel@tonic-gate case 123: 34157c478bd9Sstevel@tonic-gate return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax)); 34162201b277Skucharsk case 131: 3417875b116eSkchow return (cpi->cpi_family < 0x10); 3418ef50d8c0Sesaxe case 6336786: 3419ef50d8c0Sesaxe /* 3420ef50d8c0Sesaxe * Test for AdvPowerMgmtInfo.TscPStateInvariant 3421875b116eSkchow * if this is a K8 family or newer processor 3422ef50d8c0Sesaxe */ 3423ef50d8c0Sesaxe if (CPI_FAMILY(cpi) == 0xf) { 34248949bcd6Sandrei struct cpuid_regs regs; 34258949bcd6Sandrei regs.cp_eax = 0x80000007; 34268949bcd6Sandrei (void) __cpuid_insn(®s); 34278949bcd6Sandrei return (!(regs.cp_edx & 0x100)); 3428ef50d8c0Sesaxe } 3429ef50d8c0Sesaxe return (0); 3430ee88d2b9Skchow case 6323525: 3431ee88d2b9Skchow return (((((eax >> 12) & 0xff00) + (eax & 0xf00)) | 3432ee88d2b9Skchow (((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0))) < 0xf40); 3433ee88d2b9Skchow 3434512cf780Skchow case 6671130: 3435512cf780Skchow /* 3436512cf780Skchow * check for processors (pre-Shanghai) that do not provide 3437512cf780Skchow * optimal management of 1gb ptes in its tlb. 3438512cf780Skchow */ 3439512cf780Skchow return (cpi->cpi_family == 0x10 && cpi->cpi_model < 4); 3440512cf780Skchow 3441512cf780Skchow case 298: 3442512cf780Skchow return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) || 3443512cf780Skchow DR_B2(eax) || RB_C0(eax)); 3444512cf780Skchow 34455e54b56dSHans Rosenfeld case 721: 34465e54b56dSHans Rosenfeld #if defined(__amd64) 34475e54b56dSHans Rosenfeld return (cpi->cpi_family == 0x10 || cpi->cpi_family == 0x12); 34485e54b56dSHans Rosenfeld #else 34495e54b56dSHans Rosenfeld return (0); 34505e54b56dSHans Rosenfeld #endif 34515e54b56dSHans Rosenfeld 3452512cf780Skchow default: 3453512cf780Skchow return (-1); 3454512cf780Skchow 3455512cf780Skchow } 3456512cf780Skchow } 3457512cf780Skchow 3458512cf780Skchow /* 3459512cf780Skchow * Determine if specified erratum is present via OSVW (OS Visible Workaround). 3460512cf780Skchow * Return 1 if erratum is present, 0 if not present and -1 if indeterminate. 3461512cf780Skchow */ 3462512cf780Skchow int 3463512cf780Skchow osvw_opteron_erratum(cpu_t *cpu, uint_t erratum) 3464512cf780Skchow { 3465512cf780Skchow struct cpuid_info *cpi; 3466512cf780Skchow uint_t osvwid; 3467512cf780Skchow static int osvwfeature = -1; 3468512cf780Skchow uint64_t osvwlength; 3469512cf780Skchow 3470512cf780Skchow 3471512cf780Skchow cpi = cpu->cpu_m.mcpu_cpi; 3472512cf780Skchow 3473512cf780Skchow /* confirm OSVW supported */ 3474512cf780Skchow if (osvwfeature == -1) { 3475512cf780Skchow osvwfeature = cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW; 3476512cf780Skchow } else { 3477512cf780Skchow /* assert that osvw feature setting is consistent on all cpus */ 3478512cf780Skchow ASSERT(osvwfeature == 3479512cf780Skchow (cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW)); 3480512cf780Skchow } 3481512cf780Skchow if (!osvwfeature) 3482512cf780Skchow return (-1); 3483512cf780Skchow 3484512cf780Skchow osvwlength = rdmsr(MSR_AMD_OSVW_ID_LEN) & OSVW_ID_LEN_MASK; 3485512cf780Skchow 3486512cf780Skchow switch (erratum) { 3487512cf780Skchow case 298: /* osvwid is 0 */ 3488512cf780Skchow osvwid = 0; 3489512cf780Skchow if (osvwlength <= (uint64_t)osvwid) { 3490512cf780Skchow /* osvwid 0 is unknown */ 3491512cf780Skchow return (-1); 3492512cf780Skchow } 3493512cf780Skchow 3494512cf780Skchow /* 3495512cf780Skchow * Check the OSVW STATUS MSR to determine the state 3496512cf780Skchow * of the erratum where: 3497512cf780Skchow * 0 - fixed by HW 3498512cf780Skchow * 1 - BIOS has applied the workaround when BIOS 3499512cf780Skchow * workaround is available. (Or for other errata, 3500512cf780Skchow * OS workaround is required.) 3501512cf780Skchow * For a value of 1, caller will confirm that the 3502512cf780Skchow * erratum 298 workaround has indeed been applied by BIOS. 3503512cf780Skchow * 3504512cf780Skchow * A 1 may be set in cpus that have a HW fix 3505512cf780Skchow * in a mixed cpu system. Regarding erratum 298: 3506512cf780Skchow * In a multiprocessor platform, the workaround above 3507512cf780Skchow * should be applied to all processors regardless of 3508512cf780Skchow * silicon revision when an affected processor is 3509512cf780Skchow * present. 3510512cf780Skchow */ 3511512cf780Skchow 3512512cf780Skchow return (rdmsr(MSR_AMD_OSVW_STATUS + 3513512cf780Skchow (osvwid / OSVW_ID_CNT_PER_MSR)) & 3514512cf780Skchow (1ULL << (osvwid % OSVW_ID_CNT_PER_MSR))); 3515512cf780Skchow 35167c478bd9Sstevel@tonic-gate default: 35177c478bd9Sstevel@tonic-gate return (-1); 35187c478bd9Sstevel@tonic-gate } 35197c478bd9Sstevel@tonic-gate } 35207c478bd9Sstevel@tonic-gate 35217c478bd9Sstevel@tonic-gate static const char assoc_str[] = "associativity"; 35227c478bd9Sstevel@tonic-gate static const char line_str[] = "line-size"; 35237c478bd9Sstevel@tonic-gate static const char size_str[] = "size"; 35247c478bd9Sstevel@tonic-gate 35257c478bd9Sstevel@tonic-gate static void 35267c478bd9Sstevel@tonic-gate add_cache_prop(dev_info_t *devi, const char *label, const char *type, 35277c478bd9Sstevel@tonic-gate uint32_t val) 35287c478bd9Sstevel@tonic-gate { 35297c478bd9Sstevel@tonic-gate char buf[128]; 35307c478bd9Sstevel@tonic-gate 35317c478bd9Sstevel@tonic-gate /* 35327c478bd9Sstevel@tonic-gate * ndi_prop_update_int() is used because it is desirable for 35337c478bd9Sstevel@tonic-gate * DDI_PROP_HW_DEF and DDI_PROP_DONTSLEEP to be set. 35347c478bd9Sstevel@tonic-gate */ 35357c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "%s-%s", label, type) < sizeof (buf)) 35367c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, buf, val); 35377c478bd9Sstevel@tonic-gate } 35387c478bd9Sstevel@tonic-gate 35397c478bd9Sstevel@tonic-gate /* 35407c478bd9Sstevel@tonic-gate * Intel-style cache/tlb description 35417c478bd9Sstevel@tonic-gate * 35427c478bd9Sstevel@tonic-gate * Standard cpuid level 2 gives a randomly ordered 35437c478bd9Sstevel@tonic-gate * selection of tags that index into a table that describes 35447c478bd9Sstevel@tonic-gate * cache and tlb properties. 35457c478bd9Sstevel@tonic-gate */ 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate static const char l1_icache_str[] = "l1-icache"; 35487c478bd9Sstevel@tonic-gate static const char l1_dcache_str[] = "l1-dcache"; 35497c478bd9Sstevel@tonic-gate static const char l2_cache_str[] = "l2-cache"; 3550ae115bc7Smrj static const char l3_cache_str[] = "l3-cache"; 35517c478bd9Sstevel@tonic-gate static const char itlb4k_str[] = "itlb-4K"; 35527c478bd9Sstevel@tonic-gate static const char dtlb4k_str[] = "dtlb-4K"; 3553824e4fecSvd224797 static const char itlb2M_str[] = "itlb-2M"; 35547c478bd9Sstevel@tonic-gate static const char itlb4M_str[] = "itlb-4M"; 35557c478bd9Sstevel@tonic-gate static const char dtlb4M_str[] = "dtlb-4M"; 355625dfb062Sksadhukh static const char dtlb24_str[] = "dtlb0-2M-4M"; 35577c478bd9Sstevel@tonic-gate static const char itlb424_str[] = "itlb-4K-2M-4M"; 355825dfb062Sksadhukh static const char itlb24_str[] = "itlb-2M-4M"; 35597c478bd9Sstevel@tonic-gate static const char dtlb44_str[] = "dtlb-4K-4M"; 35607c478bd9Sstevel@tonic-gate static const char sl1_dcache_str[] = "sectored-l1-dcache"; 35617c478bd9Sstevel@tonic-gate static const char sl2_cache_str[] = "sectored-l2-cache"; 35627c478bd9Sstevel@tonic-gate static const char itrace_str[] = "itrace-cache"; 35637c478bd9Sstevel@tonic-gate static const char sl3_cache_str[] = "sectored-l3-cache"; 356425dfb062Sksadhukh static const char sh_l2_tlb4k_str[] = "shared-l2-tlb-4k"; 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate static const struct cachetab { 35677c478bd9Sstevel@tonic-gate uint8_t ct_code; 35687c478bd9Sstevel@tonic-gate uint8_t ct_assoc; 35697c478bd9Sstevel@tonic-gate uint16_t ct_line_size; 35707c478bd9Sstevel@tonic-gate size_t ct_size; 35717c478bd9Sstevel@tonic-gate const char *ct_label; 35727c478bd9Sstevel@tonic-gate } intel_ctab[] = { 3573824e4fecSvd224797 /* 3574824e4fecSvd224797 * maintain descending order! 3575824e4fecSvd224797 * 3576824e4fecSvd224797 * Codes ignored - Reason 3577824e4fecSvd224797 * ---------------------- 3578824e4fecSvd224797 * 40H - intel_cpuid_4_cache_info() disambiguates l2/l3 cache 3579824e4fecSvd224797 * f0H/f1H - Currently we do not interpret prefetch size by design 3580824e4fecSvd224797 */ 358125dfb062Sksadhukh { 0xe4, 16, 64, 8*1024*1024, l3_cache_str}, 358225dfb062Sksadhukh { 0xe3, 16, 64, 4*1024*1024, l3_cache_str}, 358325dfb062Sksadhukh { 0xe2, 16, 64, 2*1024*1024, l3_cache_str}, 358425dfb062Sksadhukh { 0xde, 12, 64, 6*1024*1024, l3_cache_str}, 358525dfb062Sksadhukh { 0xdd, 12, 64, 3*1024*1024, l3_cache_str}, 358625dfb062Sksadhukh { 0xdc, 12, 64, ((1*1024*1024)+(512*1024)), l3_cache_str}, 358725dfb062Sksadhukh { 0xd8, 8, 64, 4*1024*1024, l3_cache_str}, 358825dfb062Sksadhukh { 0xd7, 8, 64, 2*1024*1024, l3_cache_str}, 358925dfb062Sksadhukh { 0xd6, 8, 64, 1*1024*1024, l3_cache_str}, 359025dfb062Sksadhukh { 0xd2, 4, 64, 2*1024*1024, l3_cache_str}, 359125dfb062Sksadhukh { 0xd1, 4, 64, 1*1024*1024, l3_cache_str}, 359225dfb062Sksadhukh { 0xd0, 4, 64, 512*1024, l3_cache_str}, 359325dfb062Sksadhukh { 0xca, 4, 0, 512, sh_l2_tlb4k_str}, 3594824e4fecSvd224797 { 0xc0, 4, 0, 8, dtlb44_str }, 3595824e4fecSvd224797 { 0xba, 4, 0, 64, dtlb4k_str }, 3596ae115bc7Smrj { 0xb4, 4, 0, 256, dtlb4k_str }, 35977c478bd9Sstevel@tonic-gate { 0xb3, 4, 0, 128, dtlb4k_str }, 359825dfb062Sksadhukh { 0xb2, 4, 0, 64, itlb4k_str }, 35997c478bd9Sstevel@tonic-gate { 0xb0, 4, 0, 128, itlb4k_str }, 36007c478bd9Sstevel@tonic-gate { 0x87, 8, 64, 1024*1024, l2_cache_str}, 36017c478bd9Sstevel@tonic-gate { 0x86, 4, 64, 512*1024, l2_cache_str}, 36027c478bd9Sstevel@tonic-gate { 0x85, 8, 32, 2*1024*1024, l2_cache_str}, 36037c478bd9Sstevel@tonic-gate { 0x84, 8, 32, 1024*1024, l2_cache_str}, 36047c478bd9Sstevel@tonic-gate { 0x83, 8, 32, 512*1024, l2_cache_str}, 36057c478bd9Sstevel@tonic-gate { 0x82, 8, 32, 256*1024, l2_cache_str}, 3606824e4fecSvd224797 { 0x80, 8, 64, 512*1024, l2_cache_str}, 36077c478bd9Sstevel@tonic-gate { 0x7f, 2, 64, 512*1024, l2_cache_str}, 36087c478bd9Sstevel@tonic-gate { 0x7d, 8, 64, 2*1024*1024, sl2_cache_str}, 36097c478bd9Sstevel@tonic-gate { 0x7c, 8, 64, 1024*1024, sl2_cache_str}, 36107c478bd9Sstevel@tonic-gate { 0x7b, 8, 64, 512*1024, sl2_cache_str}, 36117c478bd9Sstevel@tonic-gate { 0x7a, 8, 64, 256*1024, sl2_cache_str}, 36127c478bd9Sstevel@tonic-gate { 0x79, 8, 64, 128*1024, sl2_cache_str}, 36137c478bd9Sstevel@tonic-gate { 0x78, 8, 64, 1024*1024, l2_cache_str}, 3614ae115bc7Smrj { 0x73, 8, 0, 64*1024, itrace_str}, 36157c478bd9Sstevel@tonic-gate { 0x72, 8, 0, 32*1024, itrace_str}, 36167c478bd9Sstevel@tonic-gate { 0x71, 8, 0, 16*1024, itrace_str}, 36177c478bd9Sstevel@tonic-gate { 0x70, 8, 0, 12*1024, itrace_str}, 36187c478bd9Sstevel@tonic-gate { 0x68, 4, 64, 32*1024, sl1_dcache_str}, 36197c478bd9Sstevel@tonic-gate { 0x67, 4, 64, 16*1024, sl1_dcache_str}, 36207c478bd9Sstevel@tonic-gate { 0x66, 4, 64, 8*1024, sl1_dcache_str}, 36217c478bd9Sstevel@tonic-gate { 0x60, 8, 64, 16*1024, sl1_dcache_str}, 36227c478bd9Sstevel@tonic-gate { 0x5d, 0, 0, 256, dtlb44_str}, 36237c478bd9Sstevel@tonic-gate { 0x5c, 0, 0, 128, dtlb44_str}, 36247c478bd9Sstevel@tonic-gate { 0x5b, 0, 0, 64, dtlb44_str}, 362525dfb062Sksadhukh { 0x5a, 4, 0, 32, dtlb24_str}, 3626824e4fecSvd224797 { 0x59, 0, 0, 16, dtlb4k_str}, 3627824e4fecSvd224797 { 0x57, 4, 0, 16, dtlb4k_str}, 3628824e4fecSvd224797 { 0x56, 4, 0, 16, dtlb4M_str}, 362925dfb062Sksadhukh { 0x55, 0, 0, 7, itlb24_str}, 36307c478bd9Sstevel@tonic-gate { 0x52, 0, 0, 256, itlb424_str}, 36317c478bd9Sstevel@tonic-gate { 0x51, 0, 0, 128, itlb424_str}, 36327c478bd9Sstevel@tonic-gate { 0x50, 0, 0, 64, itlb424_str}, 3633824e4fecSvd224797 { 0x4f, 0, 0, 32, itlb4k_str}, 3634824e4fecSvd224797 { 0x4e, 24, 64, 6*1024*1024, l2_cache_str}, 3635ae115bc7Smrj { 0x4d, 16, 64, 16*1024*1024, l3_cache_str}, 3636ae115bc7Smrj { 0x4c, 12, 64, 12*1024*1024, l3_cache_str}, 3637ae115bc7Smrj { 0x4b, 16, 64, 8*1024*1024, l3_cache_str}, 3638ae115bc7Smrj { 0x4a, 12, 64, 6*1024*1024, l3_cache_str}, 3639ae115bc7Smrj { 0x49, 16, 64, 4*1024*1024, l3_cache_str}, 3640824e4fecSvd224797 { 0x48, 12, 64, 3*1024*1024, l2_cache_str}, 3641ae115bc7Smrj { 0x47, 8, 64, 8*1024*1024, l3_cache_str}, 3642ae115bc7Smrj { 0x46, 4, 64, 4*1024*1024, l3_cache_str}, 36437c478bd9Sstevel@tonic-gate { 0x45, 4, 32, 2*1024*1024, l2_cache_str}, 36447c478bd9Sstevel@tonic-gate { 0x44, 4, 32, 1024*1024, l2_cache_str}, 36457c478bd9Sstevel@tonic-gate { 0x43, 4, 32, 512*1024, l2_cache_str}, 36467c478bd9Sstevel@tonic-gate { 0x42, 4, 32, 256*1024, l2_cache_str}, 36477c478bd9Sstevel@tonic-gate { 0x41, 4, 32, 128*1024, l2_cache_str}, 3648ae115bc7Smrj { 0x3e, 4, 64, 512*1024, sl2_cache_str}, 3649ae115bc7Smrj { 0x3d, 6, 64, 384*1024, sl2_cache_str}, 36507c478bd9Sstevel@tonic-gate { 0x3c, 4, 64, 256*1024, sl2_cache_str}, 36517c478bd9Sstevel@tonic-gate { 0x3b, 2, 64, 128*1024, sl2_cache_str}, 3652ae115bc7Smrj { 0x3a, 6, 64, 192*1024, sl2_cache_str}, 36537c478bd9Sstevel@tonic-gate { 0x39, 4, 64, 128*1024, sl2_cache_str}, 36547c478bd9Sstevel@tonic-gate { 0x30, 8, 64, 32*1024, l1_icache_str}, 36557c478bd9Sstevel@tonic-gate { 0x2c, 8, 64, 32*1024, l1_dcache_str}, 36567c478bd9Sstevel@tonic-gate { 0x29, 8, 64, 4096*1024, sl3_cache_str}, 36577c478bd9Sstevel@tonic-gate { 0x25, 8, 64, 2048*1024, sl3_cache_str}, 36587c478bd9Sstevel@tonic-gate { 0x23, 8, 64, 1024*1024, sl3_cache_str}, 36597c478bd9Sstevel@tonic-gate { 0x22, 4, 64, 512*1024, sl3_cache_str}, 3660824e4fecSvd224797 { 0x0e, 6, 64, 24*1024, l1_dcache_str}, 366125dfb062Sksadhukh { 0x0d, 4, 32, 16*1024, l1_dcache_str}, 36627c478bd9Sstevel@tonic-gate { 0x0c, 4, 32, 16*1024, l1_dcache_str}, 3663ae115bc7Smrj { 0x0b, 4, 0, 4, itlb4M_str}, 36647c478bd9Sstevel@tonic-gate { 0x0a, 2, 32, 8*1024, l1_dcache_str}, 36657c478bd9Sstevel@tonic-gate { 0x08, 4, 32, 16*1024, l1_icache_str}, 36667c478bd9Sstevel@tonic-gate { 0x06, 4, 32, 8*1024, l1_icache_str}, 3667824e4fecSvd224797 { 0x05, 4, 0, 32, dtlb4M_str}, 36687c478bd9Sstevel@tonic-gate { 0x04, 4, 0, 8, dtlb4M_str}, 36697c478bd9Sstevel@tonic-gate { 0x03, 4, 0, 64, dtlb4k_str}, 36707c478bd9Sstevel@tonic-gate { 0x02, 4, 0, 2, itlb4M_str}, 36717c478bd9Sstevel@tonic-gate { 0x01, 4, 0, 32, itlb4k_str}, 36727c478bd9Sstevel@tonic-gate { 0 } 36737c478bd9Sstevel@tonic-gate }; 36747c478bd9Sstevel@tonic-gate 36757c478bd9Sstevel@tonic-gate static const struct cachetab cyrix_ctab[] = { 36767c478bd9Sstevel@tonic-gate { 0x70, 4, 0, 32, "tlb-4K" }, 36777c478bd9Sstevel@tonic-gate { 0x80, 4, 16, 16*1024, "l1-cache" }, 36787c478bd9Sstevel@tonic-gate { 0 } 36797c478bd9Sstevel@tonic-gate }; 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate /* 36827c478bd9Sstevel@tonic-gate * Search a cache table for a matching entry 36837c478bd9Sstevel@tonic-gate */ 36847c478bd9Sstevel@tonic-gate static const struct cachetab * 36857c478bd9Sstevel@tonic-gate find_cacheent(const struct cachetab *ct, uint_t code) 36867c478bd9Sstevel@tonic-gate { 36877c478bd9Sstevel@tonic-gate if (code != 0) { 36887c478bd9Sstevel@tonic-gate for (; ct->ct_code != 0; ct++) 36897c478bd9Sstevel@tonic-gate if (ct->ct_code <= code) 36907c478bd9Sstevel@tonic-gate break; 36917c478bd9Sstevel@tonic-gate if (ct->ct_code == code) 36927c478bd9Sstevel@tonic-gate return (ct); 36937c478bd9Sstevel@tonic-gate } 36947c478bd9Sstevel@tonic-gate return (NULL); 36957c478bd9Sstevel@tonic-gate } 36967c478bd9Sstevel@tonic-gate 36977c478bd9Sstevel@tonic-gate /* 36987dee861bSksadhukh * Populate cachetab entry with L2 or L3 cache-information using 36997dee861bSksadhukh * cpuid function 4. This function is called from intel_walk_cacheinfo() 37007dee861bSksadhukh * when descriptor 0x49 is encountered. It returns 0 if no such cache 37017dee861bSksadhukh * information is found. 37027dee861bSksadhukh */ 37037dee861bSksadhukh static int 37047dee861bSksadhukh intel_cpuid_4_cache_info(struct cachetab *ct, struct cpuid_info *cpi) 37057dee861bSksadhukh { 37067dee861bSksadhukh uint32_t level, i; 37077dee861bSksadhukh int ret = 0; 37087dee861bSksadhukh 37097dee861bSksadhukh for (i = 0; i < cpi->cpi_std_4_size; i++) { 37107dee861bSksadhukh level = CPI_CACHE_LVL(cpi->cpi_std_4[i]); 37117dee861bSksadhukh 37127dee861bSksadhukh if (level == 2 || level == 3) { 37137dee861bSksadhukh ct->ct_assoc = CPI_CACHE_WAYS(cpi->cpi_std_4[i]) + 1; 37147dee861bSksadhukh ct->ct_line_size = 37157dee861bSksadhukh CPI_CACHE_COH_LN_SZ(cpi->cpi_std_4[i]) + 1; 37167dee861bSksadhukh ct->ct_size = ct->ct_assoc * 37177dee861bSksadhukh (CPI_CACHE_PARTS(cpi->cpi_std_4[i]) + 1) * 37187dee861bSksadhukh ct->ct_line_size * 37197dee861bSksadhukh (cpi->cpi_std_4[i]->cp_ecx + 1); 37207dee861bSksadhukh 37217dee861bSksadhukh if (level == 2) { 37227dee861bSksadhukh ct->ct_label = l2_cache_str; 37237dee861bSksadhukh } else if (level == 3) { 37247dee861bSksadhukh ct->ct_label = l3_cache_str; 37257dee861bSksadhukh } 37267dee861bSksadhukh ret = 1; 37277dee861bSksadhukh } 37287dee861bSksadhukh } 37297dee861bSksadhukh 37307dee861bSksadhukh return (ret); 37317dee861bSksadhukh } 37327dee861bSksadhukh 37337dee861bSksadhukh /* 37347c478bd9Sstevel@tonic-gate * Walk the cacheinfo descriptor, applying 'func' to every valid element 37357c478bd9Sstevel@tonic-gate * The walk is terminated if the walker returns non-zero. 37367c478bd9Sstevel@tonic-gate */ 37377c478bd9Sstevel@tonic-gate static void 37387c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(struct cpuid_info *cpi, 37397c478bd9Sstevel@tonic-gate void *arg, int (*func)(void *, const struct cachetab *)) 37407c478bd9Sstevel@tonic-gate { 37417c478bd9Sstevel@tonic-gate const struct cachetab *ct; 3742824e4fecSvd224797 struct cachetab des_49_ct, des_b1_ct; 37437c478bd9Sstevel@tonic-gate uint8_t *dp; 37447c478bd9Sstevel@tonic-gate int i; 37457c478bd9Sstevel@tonic-gate 37467c478bd9Sstevel@tonic-gate if ((dp = cpi->cpi_cacheinfo) == NULL) 37477c478bd9Sstevel@tonic-gate return; 3748f1d742a9Sksadhukh for (i = 0; i < cpi->cpi_ncache; i++, dp++) { 3749f1d742a9Sksadhukh /* 3750f1d742a9Sksadhukh * For overloaded descriptor 0x49 we use cpuid function 4 37517dee861bSksadhukh * if supported by the current processor, to create 3752f1d742a9Sksadhukh * cache information. 3753824e4fecSvd224797 * For overloaded descriptor 0xb1 we use X86_PAE flag 3754824e4fecSvd224797 * to disambiguate the cache information. 3755f1d742a9Sksadhukh */ 37567dee861bSksadhukh if (*dp == 0x49 && cpi->cpi_maxeax >= 0x4 && 37577dee861bSksadhukh intel_cpuid_4_cache_info(&des_49_ct, cpi) == 1) { 37587dee861bSksadhukh ct = &des_49_ct; 3759824e4fecSvd224797 } else if (*dp == 0xb1) { 3760824e4fecSvd224797 des_b1_ct.ct_code = 0xb1; 3761824e4fecSvd224797 des_b1_ct.ct_assoc = 4; 3762824e4fecSvd224797 des_b1_ct.ct_line_size = 0; 37637417cfdeSKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_PAE)) { 3764824e4fecSvd224797 des_b1_ct.ct_size = 8; 3765824e4fecSvd224797 des_b1_ct.ct_label = itlb2M_str; 3766824e4fecSvd224797 } else { 3767824e4fecSvd224797 des_b1_ct.ct_size = 4; 3768824e4fecSvd224797 des_b1_ct.ct_label = itlb4M_str; 3769824e4fecSvd224797 } 3770824e4fecSvd224797 ct = &des_b1_ct; 37717dee861bSksadhukh } else { 37727dee861bSksadhukh if ((ct = find_cacheent(intel_ctab, *dp)) == NULL) { 3773f1d742a9Sksadhukh continue; 3774f1d742a9Sksadhukh } 37757dee861bSksadhukh } 3776f1d742a9Sksadhukh 37777dee861bSksadhukh if (func(arg, ct) != 0) { 37787c478bd9Sstevel@tonic-gate break; 37797c478bd9Sstevel@tonic-gate } 37807c478bd9Sstevel@tonic-gate } 3781f1d742a9Sksadhukh } 37827c478bd9Sstevel@tonic-gate 37837c478bd9Sstevel@tonic-gate /* 37847c478bd9Sstevel@tonic-gate * (Like the Intel one, except for Cyrix CPUs) 37857c478bd9Sstevel@tonic-gate */ 37867c478bd9Sstevel@tonic-gate static void 37877c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(struct cpuid_info *cpi, 37887c478bd9Sstevel@tonic-gate void *arg, int (*func)(void *, const struct cachetab *)) 37897c478bd9Sstevel@tonic-gate { 37907c478bd9Sstevel@tonic-gate const struct cachetab *ct; 37917c478bd9Sstevel@tonic-gate uint8_t *dp; 37927c478bd9Sstevel@tonic-gate int i; 37937c478bd9Sstevel@tonic-gate 37947c478bd9Sstevel@tonic-gate if ((dp = cpi->cpi_cacheinfo) == NULL) 37957c478bd9Sstevel@tonic-gate return; 37967c478bd9Sstevel@tonic-gate for (i = 0; i < cpi->cpi_ncache; i++, dp++) { 37977c478bd9Sstevel@tonic-gate /* 37987c478bd9Sstevel@tonic-gate * Search Cyrix-specific descriptor table first .. 37997c478bd9Sstevel@tonic-gate */ 38007c478bd9Sstevel@tonic-gate if ((ct = find_cacheent(cyrix_ctab, *dp)) != NULL) { 38017c478bd9Sstevel@tonic-gate if (func(arg, ct) != 0) 38027c478bd9Sstevel@tonic-gate break; 38037c478bd9Sstevel@tonic-gate continue; 38047c478bd9Sstevel@tonic-gate } 38057c478bd9Sstevel@tonic-gate /* 38067c478bd9Sstevel@tonic-gate * .. else fall back to the Intel one 38077c478bd9Sstevel@tonic-gate */ 38087c478bd9Sstevel@tonic-gate if ((ct = find_cacheent(intel_ctab, *dp)) != NULL) { 38097c478bd9Sstevel@tonic-gate if (func(arg, ct) != 0) 38107c478bd9Sstevel@tonic-gate break; 38117c478bd9Sstevel@tonic-gate continue; 38127c478bd9Sstevel@tonic-gate } 38137c478bd9Sstevel@tonic-gate } 38147c478bd9Sstevel@tonic-gate } 38157c478bd9Sstevel@tonic-gate 38167c478bd9Sstevel@tonic-gate /* 38177c478bd9Sstevel@tonic-gate * A cacheinfo walker that adds associativity, line-size, and size properties 38187c478bd9Sstevel@tonic-gate * to the devinfo node it is passed as an argument. 38197c478bd9Sstevel@tonic-gate */ 38207c478bd9Sstevel@tonic-gate static int 38217c478bd9Sstevel@tonic-gate add_cacheent_props(void *arg, const struct cachetab *ct) 38227c478bd9Sstevel@tonic-gate { 38237c478bd9Sstevel@tonic-gate dev_info_t *devi = arg; 38247c478bd9Sstevel@tonic-gate 38257c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, assoc_str, ct->ct_assoc); 38267c478bd9Sstevel@tonic-gate if (ct->ct_line_size != 0) 38277c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, line_str, 38287c478bd9Sstevel@tonic-gate ct->ct_line_size); 38297c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, size_str, ct->ct_size); 38307c478bd9Sstevel@tonic-gate return (0); 38317c478bd9Sstevel@tonic-gate } 38327c478bd9Sstevel@tonic-gate 3833f1d742a9Sksadhukh 38347c478bd9Sstevel@tonic-gate static const char fully_assoc[] = "fully-associative?"; 38357c478bd9Sstevel@tonic-gate 38367c478bd9Sstevel@tonic-gate /* 38377c478bd9Sstevel@tonic-gate * AMD style cache/tlb description 38387c478bd9Sstevel@tonic-gate * 38397c478bd9Sstevel@tonic-gate * Extended functions 5 and 6 directly describe properties of 38407c478bd9Sstevel@tonic-gate * tlbs and various cache levels. 38417c478bd9Sstevel@tonic-gate */ 38427c478bd9Sstevel@tonic-gate static void 38437c478bd9Sstevel@tonic-gate add_amd_assoc(dev_info_t *devi, const char *label, uint_t assoc) 38447c478bd9Sstevel@tonic-gate { 38457c478bd9Sstevel@tonic-gate switch (assoc) { 38467c478bd9Sstevel@tonic-gate case 0: /* reserved; ignore */ 38477c478bd9Sstevel@tonic-gate break; 38487c478bd9Sstevel@tonic-gate default: 38497c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, assoc); 38507c478bd9Sstevel@tonic-gate break; 38517c478bd9Sstevel@tonic-gate case 0xff: 38527c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, fully_assoc, 1); 38537c478bd9Sstevel@tonic-gate break; 38547c478bd9Sstevel@tonic-gate } 38557c478bd9Sstevel@tonic-gate } 38567c478bd9Sstevel@tonic-gate 38577c478bd9Sstevel@tonic-gate static void 38587c478bd9Sstevel@tonic-gate add_amd_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size) 38597c478bd9Sstevel@tonic-gate { 38607c478bd9Sstevel@tonic-gate if (size == 0) 38617c478bd9Sstevel@tonic-gate return; 38627c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size); 38637c478bd9Sstevel@tonic-gate add_amd_assoc(devi, label, assoc); 38647c478bd9Sstevel@tonic-gate } 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate static void 38677c478bd9Sstevel@tonic-gate add_amd_cache(dev_info_t *devi, const char *label, 38687c478bd9Sstevel@tonic-gate uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size) 38697c478bd9Sstevel@tonic-gate { 38707c478bd9Sstevel@tonic-gate if (size == 0 || line_size == 0) 38717c478bd9Sstevel@tonic-gate return; 38727c478bd9Sstevel@tonic-gate add_amd_assoc(devi, label, assoc); 38737c478bd9Sstevel@tonic-gate /* 38747c478bd9Sstevel@tonic-gate * Most AMD parts have a sectored cache. Multiple cache lines are 38757c478bd9Sstevel@tonic-gate * associated with each tag. A sector consists of all cache lines 38767c478bd9Sstevel@tonic-gate * associated with a tag. For example, the AMD K6-III has a sector 38777c478bd9Sstevel@tonic-gate * size of 2 cache lines per tag. 38787c478bd9Sstevel@tonic-gate */ 38797c478bd9Sstevel@tonic-gate if (lines_per_tag != 0) 38807c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, "lines-per-tag", lines_per_tag); 38817c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, line_str, line_size); 38827c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size * 1024); 38837c478bd9Sstevel@tonic-gate } 38847c478bd9Sstevel@tonic-gate 38857c478bd9Sstevel@tonic-gate static void 38867c478bd9Sstevel@tonic-gate add_amd_l2_assoc(dev_info_t *devi, const char *label, uint_t assoc) 38877c478bd9Sstevel@tonic-gate { 38887c478bd9Sstevel@tonic-gate switch (assoc) { 38897c478bd9Sstevel@tonic-gate case 0: /* off */ 38907c478bd9Sstevel@tonic-gate break; 38917c478bd9Sstevel@tonic-gate case 1: 38927c478bd9Sstevel@tonic-gate case 2: 38937c478bd9Sstevel@tonic-gate case 4: 38947c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, assoc); 38957c478bd9Sstevel@tonic-gate break; 38967c478bd9Sstevel@tonic-gate case 6: 38977c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, 8); 38987c478bd9Sstevel@tonic-gate break; 38997c478bd9Sstevel@tonic-gate case 8: 39007c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, 16); 39017c478bd9Sstevel@tonic-gate break; 39027c478bd9Sstevel@tonic-gate case 0xf: 39037c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, fully_assoc, 1); 39047c478bd9Sstevel@tonic-gate break; 39057c478bd9Sstevel@tonic-gate default: /* reserved; ignore */ 39067c478bd9Sstevel@tonic-gate break; 39077c478bd9Sstevel@tonic-gate } 39087c478bd9Sstevel@tonic-gate } 39097c478bd9Sstevel@tonic-gate 39107c478bd9Sstevel@tonic-gate static void 39117c478bd9Sstevel@tonic-gate add_amd_l2_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size) 39127c478bd9Sstevel@tonic-gate { 39137c478bd9Sstevel@tonic-gate if (size == 0 || assoc == 0) 39147c478bd9Sstevel@tonic-gate return; 39157c478bd9Sstevel@tonic-gate add_amd_l2_assoc(devi, label, assoc); 39167c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size); 39177c478bd9Sstevel@tonic-gate } 39187c478bd9Sstevel@tonic-gate 39197c478bd9Sstevel@tonic-gate static void 39207c478bd9Sstevel@tonic-gate add_amd_l2_cache(dev_info_t *devi, const char *label, 39217c478bd9Sstevel@tonic-gate uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size) 39227c478bd9Sstevel@tonic-gate { 39237c478bd9Sstevel@tonic-gate if (size == 0 || assoc == 0 || line_size == 0) 39247c478bd9Sstevel@tonic-gate return; 39257c478bd9Sstevel@tonic-gate add_amd_l2_assoc(devi, label, assoc); 39267c478bd9Sstevel@tonic-gate if (lines_per_tag != 0) 39277c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, "lines-per-tag", lines_per_tag); 39287c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, line_str, line_size); 39297c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size * 1024); 39307c478bd9Sstevel@tonic-gate } 39317c478bd9Sstevel@tonic-gate 39327c478bd9Sstevel@tonic-gate static void 39337c478bd9Sstevel@tonic-gate amd_cache_info(struct cpuid_info *cpi, dev_info_t *devi) 39347c478bd9Sstevel@tonic-gate { 39358949bcd6Sandrei struct cpuid_regs *cp; 39367c478bd9Sstevel@tonic-gate 39377c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000005) 39387c478bd9Sstevel@tonic-gate return; 39397c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[5]; 39407c478bd9Sstevel@tonic-gate 39417c478bd9Sstevel@tonic-gate /* 39427c478bd9Sstevel@tonic-gate * 4M/2M L1 TLB configuration 39437c478bd9Sstevel@tonic-gate * 39447c478bd9Sstevel@tonic-gate * We report the size for 2M pages because AMD uses two 39457c478bd9Sstevel@tonic-gate * TLB entries for one 4M page. 39467c478bd9Sstevel@tonic-gate */ 39477c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "dtlb-2M", 39487c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 24), BITX(cp->cp_eax, 23, 16)); 39497c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "itlb-2M", 39507c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 8), BITX(cp->cp_eax, 7, 0)); 39517c478bd9Sstevel@tonic-gate 39527c478bd9Sstevel@tonic-gate /* 39537c478bd9Sstevel@tonic-gate * 4K L1 TLB configuration 39547c478bd9Sstevel@tonic-gate */ 39557c478bd9Sstevel@tonic-gate 39567c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 39577c478bd9Sstevel@tonic-gate uint_t nentries; 39587c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 39597c478bd9Sstevel@tonic-gate if (cpi->cpi_family >= 5) { 39607c478bd9Sstevel@tonic-gate /* 39617c478bd9Sstevel@tonic-gate * Crusoe processors have 256 TLB entries, but 39627c478bd9Sstevel@tonic-gate * cpuid data format constrains them to only 39637c478bd9Sstevel@tonic-gate * reporting 255 of them. 39647c478bd9Sstevel@tonic-gate */ 39657c478bd9Sstevel@tonic-gate if ((nentries = BITX(cp->cp_ebx, 23, 16)) == 255) 39667c478bd9Sstevel@tonic-gate nentries = 256; 39677c478bd9Sstevel@tonic-gate /* 39687c478bd9Sstevel@tonic-gate * Crusoe processors also have a unified TLB 39697c478bd9Sstevel@tonic-gate */ 39707c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "tlb-4K", BITX(cp->cp_ebx, 31, 24), 39717c478bd9Sstevel@tonic-gate nentries); 39727c478bd9Sstevel@tonic-gate break; 39737c478bd9Sstevel@tonic-gate } 39747c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 39757c478bd9Sstevel@tonic-gate default: 39767c478bd9Sstevel@tonic-gate add_amd_tlb(devi, itlb4k_str, 39777c478bd9Sstevel@tonic-gate BITX(cp->cp_ebx, 31, 24), BITX(cp->cp_ebx, 23, 16)); 39787c478bd9Sstevel@tonic-gate add_amd_tlb(devi, dtlb4k_str, 39797c478bd9Sstevel@tonic-gate BITX(cp->cp_ebx, 15, 8), BITX(cp->cp_ebx, 7, 0)); 39807c478bd9Sstevel@tonic-gate break; 39817c478bd9Sstevel@tonic-gate } 39827c478bd9Sstevel@tonic-gate 39837c478bd9Sstevel@tonic-gate /* 39847c478bd9Sstevel@tonic-gate * data L1 cache configuration 39857c478bd9Sstevel@tonic-gate */ 39867c478bd9Sstevel@tonic-gate 39877c478bd9Sstevel@tonic-gate add_amd_cache(devi, l1_dcache_str, 39887c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 24), BITX(cp->cp_ecx, 23, 16), 39897c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 15, 8), BITX(cp->cp_ecx, 7, 0)); 39907c478bd9Sstevel@tonic-gate 39917c478bd9Sstevel@tonic-gate /* 39927c478bd9Sstevel@tonic-gate * code L1 cache configuration 39937c478bd9Sstevel@tonic-gate */ 39947c478bd9Sstevel@tonic-gate 39957c478bd9Sstevel@tonic-gate add_amd_cache(devi, l1_icache_str, 39967c478bd9Sstevel@tonic-gate BITX(cp->cp_edx, 31, 24), BITX(cp->cp_edx, 23, 16), 39977c478bd9Sstevel@tonic-gate BITX(cp->cp_edx, 15, 8), BITX(cp->cp_edx, 7, 0)); 39987c478bd9Sstevel@tonic-gate 39997c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000006) 40007c478bd9Sstevel@tonic-gate return; 40017c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[6]; 40027c478bd9Sstevel@tonic-gate 40037c478bd9Sstevel@tonic-gate /* Check for a unified L2 TLB for large pages */ 40047c478bd9Sstevel@tonic-gate 40057c478bd9Sstevel@tonic-gate if (BITX(cp->cp_eax, 31, 16) == 0) 40067c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-tlb-2M", 40077c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 40087c478bd9Sstevel@tonic-gate else { 40097c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-dtlb-2M", 40107c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16)); 40117c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-itlb-2M", 40127c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 40137c478bd9Sstevel@tonic-gate } 40147c478bd9Sstevel@tonic-gate 40157c478bd9Sstevel@tonic-gate /* Check for a unified L2 TLB for 4K pages */ 40167c478bd9Sstevel@tonic-gate 40177c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ebx, 31, 16) == 0) { 40187c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-tlb-4K", 40197c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 40207c478bd9Sstevel@tonic-gate } else { 40217c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-dtlb-4K", 40227c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16)); 40237c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-itlb-4K", 40247c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 40257c478bd9Sstevel@tonic-gate } 40267c478bd9Sstevel@tonic-gate 40277c478bd9Sstevel@tonic-gate add_amd_l2_cache(devi, l2_cache_str, 40287c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 16), BITX(cp->cp_ecx, 15, 12), 40297c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 11, 8), BITX(cp->cp_ecx, 7, 0)); 40307c478bd9Sstevel@tonic-gate } 40317c478bd9Sstevel@tonic-gate 40327c478bd9Sstevel@tonic-gate /* 40337c478bd9Sstevel@tonic-gate * There are two basic ways that the x86 world describes it cache 40347c478bd9Sstevel@tonic-gate * and tlb architecture - Intel's way and AMD's way. 40357c478bd9Sstevel@tonic-gate * 40367c478bd9Sstevel@tonic-gate * Return which flavor of cache architecture we should use 40377c478bd9Sstevel@tonic-gate */ 40387c478bd9Sstevel@tonic-gate static int 40397c478bd9Sstevel@tonic-gate x86_which_cacheinfo(struct cpuid_info *cpi) 40407c478bd9Sstevel@tonic-gate { 40417c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 40427c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 40437c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax >= 2) 40447c478bd9Sstevel@tonic-gate return (X86_VENDOR_Intel); 40457c478bd9Sstevel@tonic-gate break; 40467c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 40477c478bd9Sstevel@tonic-gate /* 40487c478bd9Sstevel@tonic-gate * The K5 model 1 was the first part from AMD that reported 40497c478bd9Sstevel@tonic-gate * cache sizes via extended cpuid functions. 40507c478bd9Sstevel@tonic-gate */ 40517c478bd9Sstevel@tonic-gate if (cpi->cpi_family > 5 || 40527c478bd9Sstevel@tonic-gate (cpi->cpi_family == 5 && cpi->cpi_model >= 1)) 40537c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 40547c478bd9Sstevel@tonic-gate break; 40557c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 40567c478bd9Sstevel@tonic-gate if (cpi->cpi_family >= 5) 40577c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 40587c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 40597c478bd9Sstevel@tonic-gate default: 40607c478bd9Sstevel@tonic-gate /* 40617c478bd9Sstevel@tonic-gate * If they have extended CPU data for 0x80000005 40627c478bd9Sstevel@tonic-gate * then we assume they have AMD-format cache 40637c478bd9Sstevel@tonic-gate * information. 40647c478bd9Sstevel@tonic-gate * 40657c478bd9Sstevel@tonic-gate * If not, and the vendor happens to be Cyrix, 40667c478bd9Sstevel@tonic-gate * then try our-Cyrix specific handler. 40677c478bd9Sstevel@tonic-gate * 40687c478bd9Sstevel@tonic-gate * If we're not Cyrix, then assume we're using Intel's 40697c478bd9Sstevel@tonic-gate * table-driven format instead. 40707c478bd9Sstevel@tonic-gate */ 40717c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000005) 40727c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 40737c478bd9Sstevel@tonic-gate else if (cpi->cpi_vendor == X86_VENDOR_Cyrix) 40747c478bd9Sstevel@tonic-gate return (X86_VENDOR_Cyrix); 40757c478bd9Sstevel@tonic-gate else if (cpi->cpi_maxeax >= 2) 40767c478bd9Sstevel@tonic-gate return (X86_VENDOR_Intel); 40777c478bd9Sstevel@tonic-gate break; 40787c478bd9Sstevel@tonic-gate } 40797c478bd9Sstevel@tonic-gate return (-1); 40807c478bd9Sstevel@tonic-gate } 40817c478bd9Sstevel@tonic-gate 40827c478bd9Sstevel@tonic-gate void 4083fa96bd91SMichael Corcoran cpuid_set_cpu_properties(void *dip, processorid_t cpu_id, 4084fa96bd91SMichael Corcoran struct cpuid_info *cpi) 40857c478bd9Sstevel@tonic-gate { 40867c478bd9Sstevel@tonic-gate dev_info_t *cpu_devi; 40877c478bd9Sstevel@tonic-gate int create; 40887c478bd9Sstevel@tonic-gate 4089fa96bd91SMichael Corcoran cpu_devi = (dev_info_t *)dip; 40907c478bd9Sstevel@tonic-gate 40917c478bd9Sstevel@tonic-gate /* device_type */ 40927c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 40937c478bd9Sstevel@tonic-gate "device_type", "cpu"); 40947c478bd9Sstevel@tonic-gate 40957c478bd9Sstevel@tonic-gate /* reg */ 40967c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 40977c478bd9Sstevel@tonic-gate "reg", cpu_id); 40987c478bd9Sstevel@tonic-gate 40997c478bd9Sstevel@tonic-gate /* cpu-mhz, and clock-frequency */ 41007c478bd9Sstevel@tonic-gate if (cpu_freq > 0) { 41017c478bd9Sstevel@tonic-gate long long mul; 41027c478bd9Sstevel@tonic-gate 41037c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41047c478bd9Sstevel@tonic-gate "cpu-mhz", cpu_freq); 41057c478bd9Sstevel@tonic-gate if ((mul = cpu_freq * 1000000LL) <= INT_MAX) 41067c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41077c478bd9Sstevel@tonic-gate "clock-frequency", (int)mul); 41087c478bd9Sstevel@tonic-gate } 41097c478bd9Sstevel@tonic-gate 41107417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) { 41117c478bd9Sstevel@tonic-gate return; 41127c478bd9Sstevel@tonic-gate } 41137c478bd9Sstevel@tonic-gate 41147c478bd9Sstevel@tonic-gate /* vendor-id */ 41157c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 41167c478bd9Sstevel@tonic-gate "vendor-id", cpi->cpi_vendorstr); 41177c478bd9Sstevel@tonic-gate 41187c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax == 0) { 41197c478bd9Sstevel@tonic-gate return; 41207c478bd9Sstevel@tonic-gate } 41217c478bd9Sstevel@tonic-gate 41227c478bd9Sstevel@tonic-gate /* 41237c478bd9Sstevel@tonic-gate * family, model, and step 41247c478bd9Sstevel@tonic-gate */ 41257c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41267c478bd9Sstevel@tonic-gate "family", CPI_FAMILY(cpi)); 41277c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41287c478bd9Sstevel@tonic-gate "cpu-model", CPI_MODEL(cpi)); 41297c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41307c478bd9Sstevel@tonic-gate "stepping-id", CPI_STEP(cpi)); 41317c478bd9Sstevel@tonic-gate 41327c478bd9Sstevel@tonic-gate /* type */ 41337c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41347c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 41357c478bd9Sstevel@tonic-gate create = 1; 41367c478bd9Sstevel@tonic-gate break; 41377c478bd9Sstevel@tonic-gate default: 41387c478bd9Sstevel@tonic-gate create = 0; 41397c478bd9Sstevel@tonic-gate break; 41407c478bd9Sstevel@tonic-gate } 41417c478bd9Sstevel@tonic-gate if (create) 41427c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41437c478bd9Sstevel@tonic-gate "type", CPI_TYPE(cpi)); 41447c478bd9Sstevel@tonic-gate 41457c478bd9Sstevel@tonic-gate /* ext-family */ 41467c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41477c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 41487c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 41497c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 41507c478bd9Sstevel@tonic-gate break; 41517c478bd9Sstevel@tonic-gate default: 41527c478bd9Sstevel@tonic-gate create = 0; 41537c478bd9Sstevel@tonic-gate break; 41547c478bd9Sstevel@tonic-gate } 41557c478bd9Sstevel@tonic-gate if (create) 41567c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41577c478bd9Sstevel@tonic-gate "ext-family", CPI_FAMILY_XTD(cpi)); 41587c478bd9Sstevel@tonic-gate 41597c478bd9Sstevel@tonic-gate /* ext-model */ 41607c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41617c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 416263d3f7dfSkk208521 create = IS_EXTENDED_MODEL_INTEL(cpi); 416368c91426Sdmick break; 41647c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 4165ee88d2b9Skchow create = CPI_FAMILY(cpi) == 0xf; 41667c478bd9Sstevel@tonic-gate break; 41677c478bd9Sstevel@tonic-gate default: 41687c478bd9Sstevel@tonic-gate create = 0; 41697c478bd9Sstevel@tonic-gate break; 41707c478bd9Sstevel@tonic-gate } 41717c478bd9Sstevel@tonic-gate if (create) 41727c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41737c478bd9Sstevel@tonic-gate "ext-model", CPI_MODEL_XTD(cpi)); 41747c478bd9Sstevel@tonic-gate 41757c478bd9Sstevel@tonic-gate /* generation */ 41767c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41777c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 41787c478bd9Sstevel@tonic-gate /* 41797c478bd9Sstevel@tonic-gate * AMD K5 model 1 was the first part to support this 41807c478bd9Sstevel@tonic-gate */ 41817c478bd9Sstevel@tonic-gate create = cpi->cpi_xmaxeax >= 0x80000001; 41827c478bd9Sstevel@tonic-gate break; 41837c478bd9Sstevel@tonic-gate default: 41847c478bd9Sstevel@tonic-gate create = 0; 41857c478bd9Sstevel@tonic-gate break; 41867c478bd9Sstevel@tonic-gate } 41877c478bd9Sstevel@tonic-gate if (create) 41887c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41897c478bd9Sstevel@tonic-gate "generation", BITX((cpi)->cpi_extd[1].cp_eax, 11, 8)); 41907c478bd9Sstevel@tonic-gate 41917c478bd9Sstevel@tonic-gate /* brand-id */ 41927c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41937c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 41947c478bd9Sstevel@tonic-gate /* 41957c478bd9Sstevel@tonic-gate * brand id first appeared on Pentium III Xeon model 8, 41967c478bd9Sstevel@tonic-gate * and Celeron model 8 processors and Opteron 41977c478bd9Sstevel@tonic-gate */ 41987c478bd9Sstevel@tonic-gate create = cpi->cpi_family > 6 || 41997c478bd9Sstevel@tonic-gate (cpi->cpi_family == 6 && cpi->cpi_model >= 8); 42007c478bd9Sstevel@tonic-gate break; 42017c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 42027c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 42037c478bd9Sstevel@tonic-gate break; 42047c478bd9Sstevel@tonic-gate default: 42057c478bd9Sstevel@tonic-gate create = 0; 42067c478bd9Sstevel@tonic-gate break; 42077c478bd9Sstevel@tonic-gate } 42087c478bd9Sstevel@tonic-gate if (create && cpi->cpi_brandid != 0) { 42097c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42107c478bd9Sstevel@tonic-gate "brand-id", cpi->cpi_brandid); 42117c478bd9Sstevel@tonic-gate } 42127c478bd9Sstevel@tonic-gate 42137c478bd9Sstevel@tonic-gate /* chunks, and apic-id */ 42147c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 42157c478bd9Sstevel@tonic-gate /* 42167c478bd9Sstevel@tonic-gate * first available on Pentium IV and Opteron (K8) 42177c478bd9Sstevel@tonic-gate */ 42185ff02082Sdmick case X86_VENDOR_Intel: 42195ff02082Sdmick create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf; 42205ff02082Sdmick break; 42215ff02082Sdmick case X86_VENDOR_AMD: 42227c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 42237c478bd9Sstevel@tonic-gate break; 42247c478bd9Sstevel@tonic-gate default: 42257c478bd9Sstevel@tonic-gate create = 0; 42267c478bd9Sstevel@tonic-gate break; 42277c478bd9Sstevel@tonic-gate } 42287c478bd9Sstevel@tonic-gate if (create) { 42297c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42307c478bd9Sstevel@tonic-gate "chunks", CPI_CHUNKS(cpi)); 42317c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 4232b6917abeSmishra "apic-id", cpi->cpi_apicid); 42337aec1d6eScindi if (cpi->cpi_chipid >= 0) { 42347c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42357c478bd9Sstevel@tonic-gate "chip#", cpi->cpi_chipid); 42367aec1d6eScindi (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42377aec1d6eScindi "clog#", cpi->cpi_clogid); 42387aec1d6eScindi } 42397c478bd9Sstevel@tonic-gate } 42407c478bd9Sstevel@tonic-gate 42417c478bd9Sstevel@tonic-gate /* cpuid-features */ 42427c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42437c478bd9Sstevel@tonic-gate "cpuid-features", CPI_FEATURES_EDX(cpi)); 42447c478bd9Sstevel@tonic-gate 42457c478bd9Sstevel@tonic-gate 42467c478bd9Sstevel@tonic-gate /* cpuid-features-ecx */ 42477c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 42487c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 42495ff02082Sdmick create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf; 42507c478bd9Sstevel@tonic-gate break; 425163408480SHans Rosenfeld case X86_VENDOR_AMD: 425263408480SHans Rosenfeld create = cpi->cpi_family >= 0xf; 425363408480SHans Rosenfeld break; 42547c478bd9Sstevel@tonic-gate default: 42557c478bd9Sstevel@tonic-gate create = 0; 42567c478bd9Sstevel@tonic-gate break; 42577c478bd9Sstevel@tonic-gate } 42587c478bd9Sstevel@tonic-gate if (create) 42597c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42607c478bd9Sstevel@tonic-gate "cpuid-features-ecx", CPI_FEATURES_ECX(cpi)); 42617c478bd9Sstevel@tonic-gate 42627c478bd9Sstevel@tonic-gate /* ext-cpuid-features */ 42637c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 42645ff02082Sdmick case X86_VENDOR_Intel: 42657c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 42667c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 42677c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 42687c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 42697c478bd9Sstevel@tonic-gate create = cpi->cpi_xmaxeax >= 0x80000001; 42707c478bd9Sstevel@tonic-gate break; 42717c478bd9Sstevel@tonic-gate default: 42727c478bd9Sstevel@tonic-gate create = 0; 42737c478bd9Sstevel@tonic-gate break; 42747c478bd9Sstevel@tonic-gate } 42755ff02082Sdmick if (create) { 42767c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42777c478bd9Sstevel@tonic-gate "ext-cpuid-features", CPI_FEATURES_XTD_EDX(cpi)); 42785ff02082Sdmick (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42795ff02082Sdmick "ext-cpuid-features-ecx", CPI_FEATURES_XTD_ECX(cpi)); 42805ff02082Sdmick } 42817c478bd9Sstevel@tonic-gate 42827c478bd9Sstevel@tonic-gate /* 42837c478bd9Sstevel@tonic-gate * Brand String first appeared in Intel Pentium IV, AMD K5 42847c478bd9Sstevel@tonic-gate * model 1, and Cyrix GXm. On earlier models we try and 42857c478bd9Sstevel@tonic-gate * simulate something similar .. so this string should always 42867c478bd9Sstevel@tonic-gate * same -something- about the processor, however lame. 42877c478bd9Sstevel@tonic-gate */ 42887c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 42897c478bd9Sstevel@tonic-gate "brand-string", cpi->cpi_brandstr); 42907c478bd9Sstevel@tonic-gate 42917c478bd9Sstevel@tonic-gate /* 42927c478bd9Sstevel@tonic-gate * Finally, cache and tlb information 42937c478bd9Sstevel@tonic-gate */ 42947c478bd9Sstevel@tonic-gate switch (x86_which_cacheinfo(cpi)) { 42957c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 42967c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props); 42977c478bd9Sstevel@tonic-gate break; 42987c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 42997c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props); 43007c478bd9Sstevel@tonic-gate break; 43017c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 43027c478bd9Sstevel@tonic-gate amd_cache_info(cpi, cpu_devi); 43037c478bd9Sstevel@tonic-gate break; 43047c478bd9Sstevel@tonic-gate default: 43057c478bd9Sstevel@tonic-gate break; 43067c478bd9Sstevel@tonic-gate } 43077c478bd9Sstevel@tonic-gate } 43087c478bd9Sstevel@tonic-gate 43097c478bd9Sstevel@tonic-gate struct l2info { 43107c478bd9Sstevel@tonic-gate int *l2i_csz; 43117c478bd9Sstevel@tonic-gate int *l2i_lsz; 43127c478bd9Sstevel@tonic-gate int *l2i_assoc; 43137c478bd9Sstevel@tonic-gate int l2i_ret; 43147c478bd9Sstevel@tonic-gate }; 43157c478bd9Sstevel@tonic-gate 43167c478bd9Sstevel@tonic-gate /* 43177c478bd9Sstevel@tonic-gate * A cacheinfo walker that fetches the size, line-size and associativity 43187c478bd9Sstevel@tonic-gate * of the L2 cache 43197c478bd9Sstevel@tonic-gate */ 43207c478bd9Sstevel@tonic-gate static int 43217c478bd9Sstevel@tonic-gate intel_l2cinfo(void *arg, const struct cachetab *ct) 43227c478bd9Sstevel@tonic-gate { 43237c478bd9Sstevel@tonic-gate struct l2info *l2i = arg; 43247c478bd9Sstevel@tonic-gate int *ip; 43257c478bd9Sstevel@tonic-gate 43267c478bd9Sstevel@tonic-gate if (ct->ct_label != l2_cache_str && 43277c478bd9Sstevel@tonic-gate ct->ct_label != sl2_cache_str) 43287c478bd9Sstevel@tonic-gate return (0); /* not an L2 -- keep walking */ 43297c478bd9Sstevel@tonic-gate 43307c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_csz) != NULL) 43317c478bd9Sstevel@tonic-gate *ip = ct->ct_size; 43327c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_lsz) != NULL) 43337c478bd9Sstevel@tonic-gate *ip = ct->ct_line_size; 43347c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_assoc) != NULL) 43357c478bd9Sstevel@tonic-gate *ip = ct->ct_assoc; 43367c478bd9Sstevel@tonic-gate l2i->l2i_ret = ct->ct_size; 43377c478bd9Sstevel@tonic-gate return (1); /* was an L2 -- terminate walk */ 43387c478bd9Sstevel@tonic-gate } 43397c478bd9Sstevel@tonic-gate 4340606303c9Skchow /* 4341606303c9Skchow * AMD L2/L3 Cache and TLB Associativity Field Definition: 4342606303c9Skchow * 4343606303c9Skchow * Unlike the associativity for the L1 cache and tlb where the 8 bit 4344606303c9Skchow * value is the associativity, the associativity for the L2 cache and 4345606303c9Skchow * tlb is encoded in the following table. The 4 bit L2 value serves as 4346606303c9Skchow * an index into the amd_afd[] array to determine the associativity. 4347606303c9Skchow * -1 is undefined. 0 is fully associative. 4348606303c9Skchow */ 4349606303c9Skchow 4350606303c9Skchow static int amd_afd[] = 4351606303c9Skchow {-1, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, 0}; 4352606303c9Skchow 43537c478bd9Sstevel@tonic-gate static void 43547c478bd9Sstevel@tonic-gate amd_l2cacheinfo(struct cpuid_info *cpi, struct l2info *l2i) 43557c478bd9Sstevel@tonic-gate { 43568949bcd6Sandrei struct cpuid_regs *cp; 43577c478bd9Sstevel@tonic-gate uint_t size, assoc; 4358606303c9Skchow int i; 43597c478bd9Sstevel@tonic-gate int *ip; 43607c478bd9Sstevel@tonic-gate 43617c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000006) 43627c478bd9Sstevel@tonic-gate return; 43637c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[6]; 43647c478bd9Sstevel@tonic-gate 4365606303c9Skchow if ((i = BITX(cp->cp_ecx, 15, 12)) != 0 && 43667c478bd9Sstevel@tonic-gate (size = BITX(cp->cp_ecx, 31, 16)) != 0) { 43677c478bd9Sstevel@tonic-gate uint_t cachesz = size * 1024; 4368606303c9Skchow assoc = amd_afd[i]; 43697c478bd9Sstevel@tonic-gate 4370606303c9Skchow ASSERT(assoc != -1); 43717c478bd9Sstevel@tonic-gate 43727c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_csz) != NULL) 43737c478bd9Sstevel@tonic-gate *ip = cachesz; 43747c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_lsz) != NULL) 43757c478bd9Sstevel@tonic-gate *ip = BITX(cp->cp_ecx, 7, 0); 43767c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_assoc) != NULL) 43777c478bd9Sstevel@tonic-gate *ip = assoc; 43787c478bd9Sstevel@tonic-gate l2i->l2i_ret = cachesz; 43797c478bd9Sstevel@tonic-gate } 43807c478bd9Sstevel@tonic-gate } 43817c478bd9Sstevel@tonic-gate 43827c478bd9Sstevel@tonic-gate int 43837c478bd9Sstevel@tonic-gate getl2cacheinfo(cpu_t *cpu, int *csz, int *lsz, int *assoc) 43847c478bd9Sstevel@tonic-gate { 43857c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 43867c478bd9Sstevel@tonic-gate struct l2info __l2info, *l2i = &__l2info; 43877c478bd9Sstevel@tonic-gate 43887c478bd9Sstevel@tonic-gate l2i->l2i_csz = csz; 43897c478bd9Sstevel@tonic-gate l2i->l2i_lsz = lsz; 43907c478bd9Sstevel@tonic-gate l2i->l2i_assoc = assoc; 43917c478bd9Sstevel@tonic-gate l2i->l2i_ret = -1; 43927c478bd9Sstevel@tonic-gate 43937c478bd9Sstevel@tonic-gate switch (x86_which_cacheinfo(cpi)) { 43947c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 43957c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(cpi, l2i, intel_l2cinfo); 43967c478bd9Sstevel@tonic-gate break; 43977c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 43987c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(cpi, l2i, intel_l2cinfo); 43997c478bd9Sstevel@tonic-gate break; 44007c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 44017c478bd9Sstevel@tonic-gate amd_l2cacheinfo(cpi, l2i); 44027c478bd9Sstevel@tonic-gate break; 44037c478bd9Sstevel@tonic-gate default: 44047c478bd9Sstevel@tonic-gate break; 44057c478bd9Sstevel@tonic-gate } 44067c478bd9Sstevel@tonic-gate return (l2i->l2i_ret); 44077c478bd9Sstevel@tonic-gate } 4408f98fbcecSbholler 4409843e1988Sjohnlev #if !defined(__xpv) 4410843e1988Sjohnlev 44115b8a6efeSbholler uint32_t * 44125b8a6efeSbholler cpuid_mwait_alloc(cpu_t *cpu) 44135b8a6efeSbholler { 44145b8a6efeSbholler uint32_t *ret; 44155b8a6efeSbholler size_t mwait_size; 44165b8a6efeSbholler 4417a3114836SGerry Liu ASSERT(cpuid_checkpass(CPU, 2)); 44185b8a6efeSbholler 4419a3114836SGerry Liu mwait_size = CPU->cpu_m.mcpu_cpi->cpi_mwait.mon_max; 44205b8a6efeSbholler if (mwait_size == 0) 44215b8a6efeSbholler return (NULL); 44225b8a6efeSbholler 44235b8a6efeSbholler /* 44245b8a6efeSbholler * kmem_alloc() returns cache line size aligned data for mwait_size 44255b8a6efeSbholler * allocations. mwait_size is currently cache line sized. Neither 44265b8a6efeSbholler * of these implementation details are guarantied to be true in the 44275b8a6efeSbholler * future. 44285b8a6efeSbholler * 44295b8a6efeSbholler * First try allocating mwait_size as kmem_alloc() currently returns 44305b8a6efeSbholler * correctly aligned memory. If kmem_alloc() does not return 44315b8a6efeSbholler * mwait_size aligned memory, then use mwait_size ROUNDUP. 44325b8a6efeSbholler * 44335b8a6efeSbholler * Set cpi_mwait.buf_actual and cpi_mwait.size_actual in case we 44345b8a6efeSbholler * decide to free this memory. 44355b8a6efeSbholler */ 44365b8a6efeSbholler ret = kmem_zalloc(mwait_size, KM_SLEEP); 44375b8a6efeSbholler if (ret == (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size)) { 44385b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret; 44395b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size; 44405b8a6efeSbholler *ret = MWAIT_RUNNING; 44415b8a6efeSbholler return (ret); 44425b8a6efeSbholler } else { 44435b8a6efeSbholler kmem_free(ret, mwait_size); 44445b8a6efeSbholler ret = kmem_zalloc(mwait_size * 2, KM_SLEEP); 44455b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret; 44465b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size * 2; 44475b8a6efeSbholler ret = (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size); 44485b8a6efeSbholler *ret = MWAIT_RUNNING; 44495b8a6efeSbholler return (ret); 44505b8a6efeSbholler } 44515b8a6efeSbholler } 44525b8a6efeSbholler 44535b8a6efeSbholler void 44545b8a6efeSbholler cpuid_mwait_free(cpu_t *cpu) 4455f98fbcecSbholler { 4456a3114836SGerry Liu if (cpu->cpu_m.mcpu_cpi == NULL) { 4457a3114836SGerry Liu return; 4458a3114836SGerry Liu } 44595b8a6efeSbholler 44605b8a6efeSbholler if (cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual != NULL && 44615b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual > 0) { 44625b8a6efeSbholler kmem_free(cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual, 44635b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual); 44645b8a6efeSbholler } 44655b8a6efeSbholler 44665b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = NULL; 44675b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = 0; 4468f98fbcecSbholler } 4469843e1988Sjohnlev 4470247dbb3dSsudheer void 4471247dbb3dSsudheer patch_tsc_read(int flag) 4472247dbb3dSsudheer { 4473247dbb3dSsudheer size_t cnt; 4474e4b86885SCheng Sean Ye 4475247dbb3dSsudheer switch (flag) { 4476247dbb3dSsudheer case X86_NO_TSC: 4477247dbb3dSsudheer cnt = &_no_rdtsc_end - &_no_rdtsc_start; 44782b0bcb26Ssudheer (void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt); 4479247dbb3dSsudheer break; 4480247dbb3dSsudheer case X86_HAVE_TSCP: 4481247dbb3dSsudheer cnt = &_tscp_end - &_tscp_start; 44822b0bcb26Ssudheer (void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt); 4483247dbb3dSsudheer break; 4484247dbb3dSsudheer case X86_TSC_MFENCE: 4485247dbb3dSsudheer cnt = &_tsc_mfence_end - &_tsc_mfence_start; 44862b0bcb26Ssudheer (void) memcpy((void *)tsc_read, 44872b0bcb26Ssudheer (void *)&_tsc_mfence_start, cnt); 4488247dbb3dSsudheer break; 448915363b27Ssudheer case X86_TSC_LFENCE: 449015363b27Ssudheer cnt = &_tsc_lfence_end - &_tsc_lfence_start; 449115363b27Ssudheer (void) memcpy((void *)tsc_read, 449215363b27Ssudheer (void *)&_tsc_lfence_start, cnt); 449315363b27Ssudheer break; 4494247dbb3dSsudheer default: 4495247dbb3dSsudheer break; 4496247dbb3dSsudheer } 4497247dbb3dSsudheer } 4498247dbb3dSsudheer 44990e751525SEric Saxe int 45000e751525SEric Saxe cpuid_deep_cstates_supported(void) 45010e751525SEric Saxe { 45020e751525SEric Saxe struct cpuid_info *cpi; 45030e751525SEric Saxe struct cpuid_regs regs; 45040e751525SEric Saxe 45050e751525SEric Saxe ASSERT(cpuid_checkpass(CPU, 1)); 45060e751525SEric Saxe 45070e751525SEric Saxe cpi = CPU->cpu_m.mcpu_cpi; 45080e751525SEric Saxe 45097417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) 45100e751525SEric Saxe return (0); 45110e751525SEric Saxe 45120e751525SEric Saxe switch (cpi->cpi_vendor) { 45130e751525SEric Saxe case X86_VENDOR_Intel: 45140e751525SEric Saxe if (cpi->cpi_xmaxeax < 0x80000007) 45150e751525SEric Saxe return (0); 45160e751525SEric Saxe 45170e751525SEric Saxe /* 45180e751525SEric Saxe * TSC run at a constant rate in all ACPI C-states? 45190e751525SEric Saxe */ 45200e751525SEric Saxe regs.cp_eax = 0x80000007; 45210e751525SEric Saxe (void) __cpuid_insn(®s); 45220e751525SEric Saxe return (regs.cp_edx & CPUID_TSC_CSTATE_INVARIANCE); 45230e751525SEric Saxe 45240e751525SEric Saxe default: 45250e751525SEric Saxe return (0); 45260e751525SEric Saxe } 45270e751525SEric Saxe } 45280e751525SEric Saxe 4529e774b42bSBill Holler #endif /* !__xpv */ 4530e774b42bSBill Holler 4531e774b42bSBill Holler void 4532e774b42bSBill Holler post_startup_cpu_fixups(void) 4533e774b42bSBill Holler { 4534e774b42bSBill Holler #ifndef __xpv 4535e774b42bSBill Holler /* 4536e774b42bSBill Holler * Some AMD processors support C1E state. Entering this state will 4537e774b42bSBill Holler * cause the local APIC timer to stop, which we can't deal with at 4538e774b42bSBill Holler * this time. 4539e774b42bSBill Holler */ 4540e774b42bSBill Holler if (cpuid_getvendor(CPU) == X86_VENDOR_AMD) { 4541e774b42bSBill Holler on_trap_data_t otd; 4542e774b42bSBill Holler uint64_t reg; 4543e774b42bSBill Holler 4544e774b42bSBill Holler if (!on_trap(&otd, OT_DATA_ACCESS)) { 4545e774b42bSBill Holler reg = rdmsr(MSR_AMD_INT_PENDING_CMP_HALT); 4546e774b42bSBill Holler /* Disable C1E state if it is enabled by BIOS */ 4547e774b42bSBill Holler if ((reg >> AMD_ACTONCMPHALT_SHIFT) & 4548e774b42bSBill Holler AMD_ACTONCMPHALT_MASK) { 4549e774b42bSBill Holler reg &= ~(AMD_ACTONCMPHALT_MASK << 4550e774b42bSBill Holler AMD_ACTONCMPHALT_SHIFT); 4551e774b42bSBill Holler wrmsr(MSR_AMD_INT_PENDING_CMP_HALT, reg); 4552e774b42bSBill Holler } 4553e774b42bSBill Holler } 4554e774b42bSBill Holler no_trap(); 4555e774b42bSBill Holler } 4556e774b42bSBill Holler #endif /* !__xpv */ 4557e774b42bSBill Holler } 4558e774b42bSBill Holler 4559cef70d2cSBill Holler /* 45607af88ac7SKuriakose Kuruvilla * Setup necessary registers to enable XSAVE feature on this processor. 45617af88ac7SKuriakose Kuruvilla * This function needs to be called early enough, so that no xsave/xrstor 45627af88ac7SKuriakose Kuruvilla * ops will execute on the processor before the MSRs are properly set up. 45637af88ac7SKuriakose Kuruvilla * 45647af88ac7SKuriakose Kuruvilla * Current implementation has the following assumption: 45657af88ac7SKuriakose Kuruvilla * - cpuid_pass1() is done, so that X86 features are known. 45667af88ac7SKuriakose Kuruvilla * - fpu_probe() is done, so that fp_save_mech is chosen. 45677af88ac7SKuriakose Kuruvilla */ 45687af88ac7SKuriakose Kuruvilla void 45697af88ac7SKuriakose Kuruvilla xsave_setup_msr(cpu_t *cpu) 45707af88ac7SKuriakose Kuruvilla { 45717af88ac7SKuriakose Kuruvilla ASSERT(fp_save_mech == FP_XSAVE); 45727af88ac7SKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE)); 45737af88ac7SKuriakose Kuruvilla 45747af88ac7SKuriakose Kuruvilla /* Enable OSXSAVE in CR4. */ 45757af88ac7SKuriakose Kuruvilla setcr4(getcr4() | CR4_OSXSAVE); 45767af88ac7SKuriakose Kuruvilla /* 45777af88ac7SKuriakose Kuruvilla * Update SW copy of ECX, so that /dev/cpu/self/cpuid will report 45787af88ac7SKuriakose Kuruvilla * correct value. 45797af88ac7SKuriakose Kuruvilla */ 45807af88ac7SKuriakose Kuruvilla cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_ecx |= CPUID_INTC_ECX_OSXSAVE; 45817af88ac7SKuriakose Kuruvilla setup_xfem(); 45827af88ac7SKuriakose Kuruvilla } 45837af88ac7SKuriakose Kuruvilla 45847af88ac7SKuriakose Kuruvilla /* 4585cef70d2cSBill Holler * Starting with the Westmere processor the local 4586cef70d2cSBill Holler * APIC timer will continue running in all C-states, 4587cef70d2cSBill Holler * including the deepest C-states. 4588cef70d2cSBill Holler */ 4589cef70d2cSBill Holler int 4590cef70d2cSBill Holler cpuid_arat_supported(void) 4591cef70d2cSBill Holler { 4592cef70d2cSBill Holler struct cpuid_info *cpi; 4593cef70d2cSBill Holler struct cpuid_regs regs; 4594cef70d2cSBill Holler 4595cef70d2cSBill Holler ASSERT(cpuid_checkpass(CPU, 1)); 45967417cfdeSKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID)); 4597cef70d2cSBill Holler 4598cef70d2cSBill Holler cpi = CPU->cpu_m.mcpu_cpi; 4599cef70d2cSBill Holler 4600cef70d2cSBill Holler switch (cpi->cpi_vendor) { 4601cef70d2cSBill Holler case X86_VENDOR_Intel: 4602cef70d2cSBill Holler /* 4603cef70d2cSBill Holler * Always-running Local APIC Timer is 4604cef70d2cSBill Holler * indicated by CPUID.6.EAX[2]. 4605cef70d2cSBill Holler */ 4606cef70d2cSBill Holler if (cpi->cpi_maxeax >= 6) { 4607cef70d2cSBill Holler regs.cp_eax = 6; 4608cef70d2cSBill Holler (void) cpuid_insn(NULL, ®s); 4609cef70d2cSBill Holler return (regs.cp_eax & CPUID_CSTATE_ARAT); 4610cef70d2cSBill Holler } else { 4611cef70d2cSBill Holler return (0); 4612cef70d2cSBill Holler } 4613cef70d2cSBill Holler default: 4614cef70d2cSBill Holler return (0); 4615cef70d2cSBill Holler } 4616cef70d2cSBill Holler } 4617cef70d2cSBill Holler 4618f21ed392Saubrey.li@intel.com /* 4619f21ed392Saubrey.li@intel.com * Check support for Intel ENERGY_PERF_BIAS feature 4620f21ed392Saubrey.li@intel.com */ 4621f21ed392Saubrey.li@intel.com int 4622f21ed392Saubrey.li@intel.com cpuid_iepb_supported(struct cpu *cp) 4623f21ed392Saubrey.li@intel.com { 4624f21ed392Saubrey.li@intel.com struct cpuid_info *cpi = cp->cpu_m.mcpu_cpi; 4625f21ed392Saubrey.li@intel.com struct cpuid_regs regs; 4626f21ed392Saubrey.li@intel.com 4627f21ed392Saubrey.li@intel.com ASSERT(cpuid_checkpass(cp, 1)); 4628f21ed392Saubrey.li@intel.com 46297417cfdeSKuriakose Kuruvilla if (!(is_x86_feature(x86_featureset, X86FSET_CPUID)) || 46307417cfdeSKuriakose Kuruvilla !(is_x86_feature(x86_featureset, X86FSET_MSR))) { 4631f21ed392Saubrey.li@intel.com return (0); 4632f21ed392Saubrey.li@intel.com } 4633f21ed392Saubrey.li@intel.com 4634f21ed392Saubrey.li@intel.com /* 4635f21ed392Saubrey.li@intel.com * Intel ENERGY_PERF_BIAS MSR is indicated by 4636f21ed392Saubrey.li@intel.com * capability bit CPUID.6.ECX.3 4637f21ed392Saubrey.li@intel.com */ 4638f21ed392Saubrey.li@intel.com if ((cpi->cpi_vendor != X86_VENDOR_Intel) || (cpi->cpi_maxeax < 6)) 4639f21ed392Saubrey.li@intel.com return (0); 4640f21ed392Saubrey.li@intel.com 4641f21ed392Saubrey.li@intel.com regs.cp_eax = 0x6; 4642f21ed392Saubrey.li@intel.com (void) cpuid_insn(NULL, ®s); 4643f21ed392Saubrey.li@intel.com return (regs.cp_ecx & CPUID_EPB_SUPPORT); 4644f21ed392Saubrey.li@intel.com } 4645f21ed392Saubrey.li@intel.com 464641afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 464741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Check support for TSC deadline timer 464841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 464941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * TSC deadline timer provides a superior software programming 465041afdfa7SKrishnendu Sadhukhan - Sun Microsystems * model over local APIC timer that eliminates "time drifts". 465141afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Instead of specifying a relative time, software specifies an 465241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * absolute time as the target at which the processor should 465341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * generate a timer event. 465441afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 465541afdfa7SKrishnendu Sadhukhan - Sun Microsystems int 465641afdfa7SKrishnendu Sadhukhan - Sun Microsystems cpuid_deadline_tsc_supported(void) 465741afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 465841afdfa7SKrishnendu Sadhukhan - Sun Microsystems struct cpuid_info *cpi = CPU->cpu_m.mcpu_cpi; 465941afdfa7SKrishnendu Sadhukhan - Sun Microsystems struct cpuid_regs regs; 466041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 466141afdfa7SKrishnendu Sadhukhan - Sun Microsystems ASSERT(cpuid_checkpass(CPU, 1)); 466241afdfa7SKrishnendu Sadhukhan - Sun Microsystems ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID)); 466341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 466441afdfa7SKrishnendu Sadhukhan - Sun Microsystems switch (cpi->cpi_vendor) { 466541afdfa7SKrishnendu Sadhukhan - Sun Microsystems case X86_VENDOR_Intel: 466641afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (cpi->cpi_maxeax >= 1) { 466741afdfa7SKrishnendu Sadhukhan - Sun Microsystems regs.cp_eax = 1; 466841afdfa7SKrishnendu Sadhukhan - Sun Microsystems (void) cpuid_insn(NULL, ®s); 466941afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (regs.cp_ecx & CPUID_DEADLINE_TSC); 467041afdfa7SKrishnendu Sadhukhan - Sun Microsystems } else { 467141afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (0); 467241afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 467341afdfa7SKrishnendu Sadhukhan - Sun Microsystems default: 467441afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (0); 467541afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 467641afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 467741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 467822cc0e45SBill Holler #if defined(__amd64) && !defined(__xpv) 467922cc0e45SBill Holler /* 468022cc0e45SBill Holler * Patch in versions of bcopy for high performance Intel Nhm processors 468122cc0e45SBill Holler * and later... 468222cc0e45SBill Holler */ 468322cc0e45SBill Holler void 468422cc0e45SBill Holler patch_memops(uint_t vendor) 468522cc0e45SBill Holler { 468622cc0e45SBill Holler size_t cnt, i; 468722cc0e45SBill Holler caddr_t to, from; 468822cc0e45SBill Holler 46897417cfdeSKuriakose Kuruvilla if ((vendor == X86_VENDOR_Intel) && 46907417cfdeSKuriakose Kuruvilla is_x86_feature(x86_featureset, X86FSET_SSE4_2)) { 469122cc0e45SBill Holler cnt = &bcopy_patch_end - &bcopy_patch_start; 469222cc0e45SBill Holler to = &bcopy_ck_size; 469322cc0e45SBill Holler from = &bcopy_patch_start; 469422cc0e45SBill Holler for (i = 0; i < cnt; i++) { 469522cc0e45SBill Holler *to++ = *from++; 469622cc0e45SBill Holler } 469722cc0e45SBill Holler } 469822cc0e45SBill Holler } 469922cc0e45SBill Holler #endif /* __amd64 && !__xpv */ 47002d2efdc6SVuong Nguyen 47012d2efdc6SVuong Nguyen /* 47022d2efdc6SVuong Nguyen * This function finds the number of bits to represent the number of cores per 47032d2efdc6SVuong Nguyen * chip and the number of strands per core for the Intel platforms. 47042d2efdc6SVuong Nguyen * It re-uses the x2APIC cpuid code of the cpuid_pass2(). 47052d2efdc6SVuong Nguyen */ 47062d2efdc6SVuong Nguyen void 47072d2efdc6SVuong Nguyen cpuid_get_ext_topo(uint_t vendor, uint_t *core_nbits, uint_t *strand_nbits) 47082d2efdc6SVuong Nguyen { 47092d2efdc6SVuong Nguyen struct cpuid_regs regs; 47102d2efdc6SVuong Nguyen struct cpuid_regs *cp = ®s; 47112d2efdc6SVuong Nguyen 47122d2efdc6SVuong Nguyen if (vendor != X86_VENDOR_Intel) { 47132d2efdc6SVuong Nguyen return; 47142d2efdc6SVuong Nguyen } 47152d2efdc6SVuong Nguyen 47162d2efdc6SVuong Nguyen /* if the cpuid level is 0xB, extended topo is available. */ 47172d2efdc6SVuong Nguyen cp->cp_eax = 0; 47182d2efdc6SVuong Nguyen if (__cpuid_insn(cp) >= 0xB) { 47192d2efdc6SVuong Nguyen 47202d2efdc6SVuong Nguyen cp->cp_eax = 0xB; 47212d2efdc6SVuong Nguyen cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 47222d2efdc6SVuong Nguyen (void) __cpuid_insn(cp); 47232d2efdc6SVuong Nguyen 47242d2efdc6SVuong Nguyen /* 47252d2efdc6SVuong Nguyen * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which 47262d2efdc6SVuong Nguyen * indicates that the extended topology enumeration leaf is 47272d2efdc6SVuong Nguyen * available. 47282d2efdc6SVuong Nguyen */ 47292d2efdc6SVuong Nguyen if (cp->cp_ebx) { 47302d2efdc6SVuong Nguyen uint_t coreid_shift = 0; 47312d2efdc6SVuong Nguyen uint_t chipid_shift = 0; 47322d2efdc6SVuong Nguyen uint_t i; 47332d2efdc6SVuong Nguyen uint_t level; 47342d2efdc6SVuong Nguyen 47352d2efdc6SVuong Nguyen for (i = 0; i < CPI_FNB_ECX_MAX; i++) { 47362d2efdc6SVuong Nguyen cp->cp_eax = 0xB; 47372d2efdc6SVuong Nguyen cp->cp_ecx = i; 47382d2efdc6SVuong Nguyen 47392d2efdc6SVuong Nguyen (void) __cpuid_insn(cp); 47402d2efdc6SVuong Nguyen level = CPI_CPU_LEVEL_TYPE(cp); 47412d2efdc6SVuong Nguyen 47422d2efdc6SVuong Nguyen if (level == 1) { 47432d2efdc6SVuong Nguyen /* 47442d2efdc6SVuong Nguyen * Thread level processor topology 47452d2efdc6SVuong Nguyen * Number of bits shift right APIC ID 47462d2efdc6SVuong Nguyen * to get the coreid. 47472d2efdc6SVuong Nguyen */ 47482d2efdc6SVuong Nguyen coreid_shift = BITX(cp->cp_eax, 4, 0); 47492d2efdc6SVuong Nguyen } else if (level == 2) { 47502d2efdc6SVuong Nguyen /* 47512d2efdc6SVuong Nguyen * Core level processor topology 47522d2efdc6SVuong Nguyen * Number of bits shift right APIC ID 47532d2efdc6SVuong Nguyen * to get the chipid. 47542d2efdc6SVuong Nguyen */ 47552d2efdc6SVuong Nguyen chipid_shift = BITX(cp->cp_eax, 4, 0); 47562d2efdc6SVuong Nguyen } 47572d2efdc6SVuong Nguyen } 47582d2efdc6SVuong Nguyen 47592d2efdc6SVuong Nguyen if (coreid_shift > 0 && chipid_shift > coreid_shift) { 47602d2efdc6SVuong Nguyen *strand_nbits = coreid_shift; 47612d2efdc6SVuong Nguyen *core_nbits = chipid_shift - coreid_shift; 47622d2efdc6SVuong Nguyen } 47632d2efdc6SVuong Nguyen } 47642d2efdc6SVuong Nguyen } 47652d2efdc6SVuong Nguyen } 4766