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
get_intel_cache_info(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
get_amd_cache_info(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
__proc64id(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