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.
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.
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]
23 * Copyright (c) 2009, Intel Corporation.
24 * All rights reserved.
28 * Portions Copyright 2009 Advanced Micro Devices, Inc.
31 #include <sys/types.h>
32 #include "proc64_id.h"
35 * Intel cpuid eax=4 Cache Types
37 #define NULL_CACHE 0x0
38 #define DATA_CACHE 0x1
39 #define INSTRUCTION_CACHE 0x2
40 #define UNIFIED_CACHE 0x3
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.
55 get_intel_cache_info(void)
58 int largest_cache_level
= 0;
61 int line_size
, partitions
, ways
, sets
;
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
;
69 __libc_get_cpuid(4, (uint_t
*)&cpuid_info
, cache_index
);
71 cache_type
= cpuid_info
.eax
& 0x1f;
72 if (cache_type
== NULL_CACHE
) {
80 if (cache_type
== INSTRUCTION_CACHE
) {
82 * Don't care for memops
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
;
94 if (cache_level
== 1) {
95 l1_cache_size
= cache_size
;
97 if (cache_level
== 2) {
98 l2_cache_size
= cache_size
;
100 if (cache_level
> largest_cache_level
) {
101 largest_cache_level
= cache_level
;
102 largest_level_cache
= cache_size
;
106 __set_cache_sizes(l1_cache_size
, l2_cache_size
, largest_level_cache
);
110 * get_amd_cache_info()
111 * Same as get_intel_cache_info() but for AMD processors
114 get_amd_cache_info(void)
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
;
125 __libc_get_cpuid(0x80000000, (uint_t
*)&cpuid_info
, -1);
126 maxeax
= cpuid_info
.eax
;
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;
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;
140 * L3 cache is shared between cores on the processor
142 if (maxeax
>= 0x80000008 && l3_cache_size
!= 0) {
143 largest_level_cache
= l3_cache_size
;
146 * Divide by number of cores on the processor
148 __libc_get_cpuid(0x80000008, (uint_t
*)&cpuid_info
, -1);
149 ncores
= (cpuid_info
.ecx
& 0xff) + 1;
151 largest_level_cache
/= ncores
;
154 * L3 is a victim cache for L2
156 largest_level_cache
+= l2_cache_size
;
158 largest_level_cache
= l2_cache_size
;
161 __set_cache_sizes(l1_cache_size
, l2_cache_size
,
162 largest_level_cache
);
167 * Determine cache and SSE level to use for memops and strops specific to
173 int use_sse
= NO_SSE
;
174 struct cpuid_values cpuid_info
;
176 __libc_get_cpuid(0, &cpuid_info
, 0);
179 * Check for AuthenticAMD
181 if ((cpuid_info
.ebx
== 0x68747541) && /* Auth */
182 (cpuid_info
.edx
== 0x69746e65) && /* enti */
183 (cpuid_info
.ecx
== 0x444d4163)) { /* cAMD */
184 get_amd_cache_info();
189 * Check for GenuineIntel
191 if ((cpuid_info
.ebx
!= 0x756e6547) || /* Genu */
192 (cpuid_info
.edx
!= 0x49656e69) || /* ineI */
193 (cpuid_info
.ecx
!= 0x6c65746e)) { /* ntel */
195 * Not Intel - use defaults.
205 * Look for CPUID function 4 support - Deterministic Cache Parameters.
206 * Otherwise use default cache sizes.
208 if (cpuid_info
.eax
>= 4) {
209 get_intel_cache_info();
212 * Check what SSE versions are supported.
214 __libc_get_cpuid(1, &cpuid_info
, 0);
215 if (cpuid_info
.ecx
& CPUID_INTC_ECX_SSE4_2
) {
216 use_sse
|= USE_SSE4_2
;
218 if (cpuid_info
.ecx
& CPUID_INTC_ECX_SSE4_1
) {
219 use_sse
|= USE_SSE4_1
;
221 if (cpuid_info
.ecx
& CPUID_INTC_ECX_SSSE3
) {
222 use_sse
|= USE_SSSE3
;
224 if (cpuid_info
.ecx
& CPUID_INTC_ECX_SSE3
) {
227 if (cpuid_info
.edx
& CPUID_INTC_EDX_SSE2
) {
231 __intel_set_memops_method(use_sse
);
233 __set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE
,
234 INTEL_DFLT_L2_CACHE_SIZE
,
235 INTEL_DFLT_LARGEST_CACHE_SIZE
);
236 __intel_set_memops_method(use_sse
);