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