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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include "proc64_id.h" 31 32 /* 33 * Intel cpuid eax=4 Cache Types 34 */ 35 #define NULL_CACHE 0x0 36 #define DATA_CACHE 0x1 37 #define INSTRUCTION_CACHE 0x2 38 #define UNIFIED_CACHE 0x3 39 40 struct cpuid_values { 41 uint_t eax; 42 uint_t ebx; 43 uint_t ecx; 44 uint_t edx; 45 }; 46 47 extern void __amd64id(void); 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 __intel_set_cache_sizes(l1_cache_size, l2_cache_size, 107 largest_level_cache); 108 } 109 110 /* 111 * proc64_id() 112 * Determine cache and SSE level to use for memops and strops specific to 113 * processor type. 114 */ 115 void 116 __proc64id(void) 117 { 118 int use_sse = NO_SSE; 119 struct cpuid_values cpuid_info; 120 121 __libc_get_cpuid(0, &cpuid_info, 0); 122 123 /* 124 * Check for AuthenticAMD 125 */ 126 if ((cpuid_info.ebx == 0x68747541) && /* Auth */ 127 (cpuid_info.edx == 0x69746e65) && /* enti */ 128 (cpuid_info.ecx == 0x444d4163)) { /* cAMD */ 129 __amd64id(); 130 return; 131 } 132 133 /* 134 * Check for GenuineIntel 135 */ 136 if ((cpuid_info.ebx != 0x756e6547) || /* Genu */ 137 (cpuid_info.edx != 0x49656e69) || /* ineI */ 138 (cpuid_info.ecx != 0x6c65746e)) { /* ntel */ 139 /* 140 * Not Intel - use defaults. 141 */ 142 return; 143 } 144 145 /* 146 * Genuine Intel 147 */ 148 149 /* 150 * Look for CPUID function 4 support - Deterministic Cache Parameters. 151 * Otherwise use default cache sizes. 152 */ 153 if (cpuid_info.eax >= 4) { 154 get_intel_cache_info(); 155 156 /* 157 * Check what SSE versions are supported. 158 */ 159 __libc_get_cpuid(1, &cpuid_info, 0); 160 if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_2) { 161 use_sse |= USE_SSE4_2; 162 } 163 if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_1) { 164 use_sse |= USE_SSE4_1; 165 } 166 if (cpuid_info.ecx & CPUID_INTC_ECX_SSSE3) { 167 use_sse |= USE_SSSE3; 168 } 169 if (cpuid_info.ecx & CPUID_INTC_ECX_SSE3) { 170 use_sse |= USE_SSE3; 171 } 172 if (cpuid_info.edx & CPUID_INTC_EDX_SSE2) { 173 use_sse |= USE_SSE2; 174 } 175 __intel_set_memops_method(use_sse); 176 } else { 177 __intel_set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE, 178 INTEL_DFLT_L2_CACHE_SIZE, 179 INTEL_DFLT_LARGEST_CACHE_SIZE); 180 __intel_set_memops_method(use_sse); 181 } 182 } 183