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) 2009, 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
get_intel_cache_info(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
get_amd_cache_info(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
__proc64id(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 use_sse |= USE_BSF;
230 __intel_set_memops_method(use_sse);
231 } else {
232 __set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE,
233 INTEL_DFLT_L2_CACHE_SIZE,
234 INTEL_DFLT_LARGEST_CACHE_SIZE);
235 __intel_set_memops_method(use_sse);
236 }
237 }
238