xref: /illumos-gate/usr/src/lib/libc/amd64/gen/proc64_id.c (revision 533d3a49)
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
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
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,
161fad5204eSbostrovs 		    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
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