1d0b3732eSbholler /* 2d0b3732eSbholler * CDDL HEADER START 3d0b3732eSbholler * 4d0b3732eSbholler * The contents of this file are subject to the terms of the 5d0b3732eSbholler * Common Development and Distribution License (the "License"). 6d0b3732eSbholler * You may not use this file except in compliance with the License. 7d0b3732eSbholler * 8d0b3732eSbholler * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d0b3732eSbholler * or http://www.opensolaris.org/os/licensing. 10d0b3732eSbholler * See the License for the specific language governing permissions 11d0b3732eSbholler * and limitations under the License. 12d0b3732eSbholler * 13d0b3732eSbholler * When distributing Covered Code, include this CDDL HEADER in each 14d0b3732eSbholler * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d0b3732eSbholler * If applicable, add the following below this CDDL HEADER, with the 16d0b3732eSbholler * fields enclosed by brackets "[]" replaced with your own identifying 17d0b3732eSbholler * information: Portions Copyright [yyyy] [name of copyright owner] 18d0b3732eSbholler * 19d0b3732eSbholler * CDDL HEADER END 20d0b3732eSbholler */ 21d0b3732eSbholler 22d0b3732eSbholler /* 23*533d3a49SEdward Gillett * Copyright (c) 2009, Intel Corporation. 24d0b3732eSbholler * All rights reserved. 25d0b3732eSbholler */ 26d0b3732eSbholler 27fad5204eSbostrovs /* 28fad5204eSbostrovs * Portions Copyright 2009 Advanced Micro Devices, Inc. 29fad5204eSbostrovs */ 30d0b3732eSbholler 31d0b3732eSbholler #include <sys/types.h> 32d0b3732eSbholler #include "proc64_id.h" 33d0b3732eSbholler 34d0b3732eSbholler /* 35d0b3732eSbholler * Intel cpuid eax=4 Cache Types 36d0b3732eSbholler */ 37d0b3732eSbholler #define NULL_CACHE 0x0 38d0b3732eSbholler #define DATA_CACHE 0x1 39d0b3732eSbholler #define INSTRUCTION_CACHE 0x2 40d0b3732eSbholler #define UNIFIED_CACHE 0x3 41d0b3732eSbholler 42d0b3732eSbholler struct cpuid_values { 43d0b3732eSbholler uint_t eax; 44d0b3732eSbholler uint_t ebx; 45d0b3732eSbholler uint_t ecx; 46d0b3732eSbholler uint_t edx; 47d0b3732eSbholler }; 48d0b3732eSbholler 49d0b3732eSbholler /* 50d0b3732eSbholler * get_intel_cache_info() 51d0b3732eSbholler * Get cpu cache sizes for optimized 64-bit libc functions mem* and str*. 52d0b3732eSbholler * Find the sizes of the 1st, 2nd and largest level caches. 53d0b3732eSbholler */ 54d0b3732eSbholler static void 55d0b3732eSbholler get_intel_cache_info(void) 56d0b3732eSbholler { 57d0b3732eSbholler int cache_level; 58d0b3732eSbholler int largest_cache_level = 0; 59d0b3732eSbholler int cache_index = 0; 60d0b3732eSbholler int cache_type; 61d0b3732eSbholler int line_size, partitions, ways, sets; 62d0b3732eSbholler uint_t cache_size; 63d0b3732eSbholler uint_t l1_cache_size = 0; 64d0b3732eSbholler uint_t l2_cache_size = 0; 65d0b3732eSbholler uint_t largest_level_cache = 0; 66d0b3732eSbholler struct cpuid_values cpuid_info; 67d0b3732eSbholler 68d0b3732eSbholler while (1) { 69d0b3732eSbholler __libc_get_cpuid(4, (uint_t *)&cpuid_info, cache_index); 70d0b3732eSbholler 71d0b3732eSbholler cache_type = cpuid_info.eax & 0x1f; 72d0b3732eSbholler if (cache_type == NULL_CACHE) { 73d0b3732eSbholler /* 74d0b3732eSbholler * No more caches. 75d0b3732eSbholler */ 76d0b3732eSbholler break; 77d0b3732eSbholler } 78d0b3732eSbholler cache_index += 1; 79d0b3732eSbholler 80d0b3732eSbholler if (cache_type == INSTRUCTION_CACHE) { 81d0b3732eSbholler /* 82d0b3732eSbholler * Don't care for memops 83d0b3732eSbholler */ 84d0b3732eSbholler continue; 85d0b3732eSbholler } 86d0b3732eSbholler 87d0b3732eSbholler cache_level = (cpuid_info.eax >> 0x5) & 0x7; 88d0b3732eSbholler line_size = (cpuid_info.ebx & 0xfff) + 1; 89d0b3732eSbholler partitions = ((cpuid_info.ebx >> 12) & 0x3ff) + 1; 90d0b3732eSbholler ways = ((cpuid_info.ebx >> 22) & 0x3ff) + 1; 91d0b3732eSbholler sets = cpuid_info.ecx + 1; 92d0b3732eSbholler cache_size = ways * partitions * line_size * sets; 93d0b3732eSbholler 94d0b3732eSbholler if (cache_level == 1) { 95d0b3732eSbholler l1_cache_size = cache_size; 96d0b3732eSbholler } 97d0b3732eSbholler if (cache_level == 2) { 98d0b3732eSbholler l2_cache_size = cache_size; 99d0b3732eSbholler } 100d0b3732eSbholler if (cache_level > largest_cache_level) { 101d0b3732eSbholler largest_cache_level = cache_level; 102d0b3732eSbholler largest_level_cache = cache_size; 103d0b3732eSbholler } 104d0b3732eSbholler } 105d0b3732eSbholler 106fad5204eSbostrovs __set_cache_sizes(l1_cache_size, l2_cache_size, largest_level_cache); 107fad5204eSbostrovs } 108fad5204eSbostrovs 109fad5204eSbostrovs /* 110fad5204eSbostrovs * get_amd_cache_info() 111fad5204eSbostrovs * Same as get_intel_cache_info() but for AMD processors 112fad5204eSbostrovs */ 113fad5204eSbostrovs static void 114fad5204eSbostrovs get_amd_cache_info(void) 115fad5204eSbostrovs { 116fad5204eSbostrovs uint_t l1_cache_size = AMD_DFLT_L1_CACHE_SIZE; 117fad5204eSbostrovs uint_t l2_cache_size = AMD_DFLT_L2_CACHE_SIZE; 118fad5204eSbostrovs uint_t l3_cache_size = 0; 119fad5204eSbostrovs uint_t largest_level_cache = 0; 120fad5204eSbostrovs struct cpuid_values cpuid_info; 121fad5204eSbostrovs uint_t maxeax; 122fad5204eSbostrovs int ncores; 123fad5204eSbostrovs 124fad5204eSbostrovs cpuid_info.eax = 0; 125fad5204eSbostrovs __libc_get_cpuid(0x80000000, (uint_t *)&cpuid_info, -1); 126fad5204eSbostrovs maxeax = cpuid_info.eax; 127fad5204eSbostrovs 128fad5204eSbostrovs if (maxeax >= 0x80000005) { /* We have L1D info */ 129fad5204eSbostrovs __libc_get_cpuid(0x80000005, (uint_t *)&cpuid_info, -1); 130fad5204eSbostrovs l1_cache_size = ((cpuid_info.ecx >> 24) & 0xff) * 1024; 131fad5204eSbostrovs } 132fad5204eSbostrovs 133fad5204eSbostrovs if (maxeax >= 0x80000006) { /* We have L2 and L3 info */ 134fad5204eSbostrovs __libc_get_cpuid(0x80000006, (uint_t *)&cpuid_info, -1); 135fad5204eSbostrovs l2_cache_size = ((cpuid_info.ecx >> 16) & 0xffff) * 1024; 136fad5204eSbostrovs l3_cache_size = ((cpuid_info.edx >> 18) & 0x3fff) * 512 * 1024; 137fad5204eSbostrovs } 138fad5204eSbostrovs 139fad5204eSbostrovs /* 140fad5204eSbostrovs * L3 cache is shared between cores on the processor 141fad5204eSbostrovs */ 142fad5204eSbostrovs if (maxeax >= 0x80000008 && l3_cache_size != 0) { 143fad5204eSbostrovs largest_level_cache = l3_cache_size; 144fad5204eSbostrovs 145fad5204eSbostrovs /* 146fad5204eSbostrovs * Divide by number of cores on the processor 147fad5204eSbostrovs */ 148fad5204eSbostrovs __libc_get_cpuid(0x80000008, (uint_t *)&cpuid_info, -1); 149fad5204eSbostrovs ncores = (cpuid_info.ecx & 0xff) + 1; 150fad5204eSbostrovs if (ncores > 1) 151fad5204eSbostrovs largest_level_cache /= ncores; 152fad5204eSbostrovs 153fad5204eSbostrovs /* 154fad5204eSbostrovs * L3 is a victim cache for L2 155fad5204eSbostrovs */ 156fad5204eSbostrovs largest_level_cache += l2_cache_size; 157fad5204eSbostrovs } else 158fad5204eSbostrovs largest_level_cache = l2_cache_size; 159fad5204eSbostrovs 160fad5204eSbostrovs __set_cache_sizes(l1_cache_size, l2_cache_size, 161d0b3732eSbholler largest_level_cache); 162d0b3732eSbholler } 163d0b3732eSbholler 164d0b3732eSbholler /* 165d0b3732eSbholler * proc64_id() 166d0b3732eSbholler * Determine cache and SSE level to use for memops and strops specific to 167d0b3732eSbholler * processor type. 168d0b3732eSbholler */ 169d0b3732eSbholler void 170d0b3732eSbholler __proc64id(void) 171d0b3732eSbholler { 172d0b3732eSbholler int use_sse = NO_SSE; 173d0b3732eSbholler struct cpuid_values cpuid_info; 174d0b3732eSbholler 175d0b3732eSbholler __libc_get_cpuid(0, &cpuid_info, 0); 176d0b3732eSbholler 177d0b3732eSbholler /* 178d0b3732eSbholler * Check for AuthenticAMD 179d0b3732eSbholler */ 180d0b3732eSbholler if ((cpuid_info.ebx == 0x68747541) && /* Auth */ 181d0b3732eSbholler (cpuid_info.edx == 0x69746e65) && /* enti */ 182d0b3732eSbholler (cpuid_info.ecx == 0x444d4163)) { /* cAMD */ 183fad5204eSbostrovs get_amd_cache_info(); 184d0b3732eSbholler return; 185d0b3732eSbholler } 186d0b3732eSbholler 187d0b3732eSbholler /* 188d0b3732eSbholler * Check for GenuineIntel 189d0b3732eSbholler */ 190d0b3732eSbholler if ((cpuid_info.ebx != 0x756e6547) || /* Genu */ 191d0b3732eSbholler (cpuid_info.edx != 0x49656e69) || /* ineI */ 192d0b3732eSbholler (cpuid_info.ecx != 0x6c65746e)) { /* ntel */ 193d0b3732eSbholler /* 194d0b3732eSbholler * Not Intel - use defaults. 195d0b3732eSbholler */ 196d0b3732eSbholler return; 197d0b3732eSbholler } 198d0b3732eSbholler 199d0b3732eSbholler /* 200d0b3732eSbholler * Genuine Intel 201d0b3732eSbholler */ 202d0b3732eSbholler 203d0b3732eSbholler /* 204d0b3732eSbholler * Look for CPUID function 4 support - Deterministic Cache Parameters. 205d0b3732eSbholler * Otherwise use default cache sizes. 206d0b3732eSbholler */ 207d0b3732eSbholler if (cpuid_info.eax >= 4) { 208d0b3732eSbholler get_intel_cache_info(); 209d0b3732eSbholler 210d0b3732eSbholler /* 211d0b3732eSbholler * Check what SSE versions are supported. 212d0b3732eSbholler */ 213d0b3732eSbholler __libc_get_cpuid(1, &cpuid_info, 0); 214d0b3732eSbholler if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_2) { 215d0b3732eSbholler use_sse |= USE_SSE4_2; 216d0b3732eSbholler } 217d0b3732eSbholler if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_1) { 218d0b3732eSbholler use_sse |= USE_SSE4_1; 219d0b3732eSbholler } 220d0b3732eSbholler if (cpuid_info.ecx & CPUID_INTC_ECX_SSSE3) { 221d0b3732eSbholler use_sse |= USE_SSSE3; 222d0b3732eSbholler } 223d0b3732eSbholler if (cpuid_info.ecx & CPUID_INTC_ECX_SSE3) { 224d0b3732eSbholler use_sse |= USE_SSE3; 225d0b3732eSbholler } 226d0b3732eSbholler if (cpuid_info.edx & CPUID_INTC_EDX_SSE2) { 227d0b3732eSbholler use_sse |= USE_SSE2; 228d0b3732eSbholler } 229*533d3a49SEdward Gillett use_sse |= USE_BSF; 230d0b3732eSbholler __intel_set_memops_method(use_sse); 231d0b3732eSbholler } else { 232fad5204eSbostrovs __set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE, 233d0b3732eSbholler INTEL_DFLT_L2_CACHE_SIZE, 234d0b3732eSbholler INTEL_DFLT_LARGEST_CACHE_SIZE); 235d0b3732eSbholler __intel_set_memops_method(use_sse); 236d0b3732eSbholler } 237d0b3732eSbholler } 238