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