xref: /illumos-gate/usr/src/lib/libc/amd64/gen/proc64_id.c (revision 54034eb2d6e7d811adf4a1fe5105eac6fea6b0b5)
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