xref: /illumos-gate/usr/src/lib/libc/amd64/gen/proc64_id.c (revision d0b3732e)
1*d0b3732eSbholler /*
2*d0b3732eSbholler  * CDDL HEADER START
3*d0b3732eSbholler  *
4*d0b3732eSbholler  * The contents of this file are subject to the terms of the
5*d0b3732eSbholler  * Common Development and Distribution License (the "License").
6*d0b3732eSbholler  * You may not use this file except in compliance with the License.
7*d0b3732eSbholler  *
8*d0b3732eSbholler  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d0b3732eSbholler  * or http://www.opensolaris.org/os/licensing.
10*d0b3732eSbholler  * See the License for the specific language governing permissions
11*d0b3732eSbholler  * and limitations under the License.
12*d0b3732eSbholler  *
13*d0b3732eSbholler  * When distributing Covered Code, include this CDDL HEADER in each
14*d0b3732eSbholler  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d0b3732eSbholler  * If applicable, add the following below this CDDL HEADER, with the
16*d0b3732eSbholler  * fields enclosed by brackets "[]" replaced with your own identifying
17*d0b3732eSbholler  * information: Portions Copyright [yyyy] [name of copyright owner]
18*d0b3732eSbholler  *
19*d0b3732eSbholler  * CDDL HEADER END
20*d0b3732eSbholler  */
21*d0b3732eSbholler 
22*d0b3732eSbholler /*
23*d0b3732eSbholler  * Copyright (c) 2008, Intel Corporation.
24*d0b3732eSbholler  * All rights reserved.
25*d0b3732eSbholler  */
26*d0b3732eSbholler 
27*d0b3732eSbholler #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*d0b3732eSbholler 
29*d0b3732eSbholler #include <sys/types.h>
30*d0b3732eSbholler #include "proc64_id.h"
31*d0b3732eSbholler 
32*d0b3732eSbholler /*
33*d0b3732eSbholler  * Intel cpuid eax=4 Cache Types
34*d0b3732eSbholler  */
35*d0b3732eSbholler #define	NULL_CACHE		0x0
36*d0b3732eSbholler #define	DATA_CACHE		0x1
37*d0b3732eSbholler #define	INSTRUCTION_CACHE	0x2
38*d0b3732eSbholler #define	UNIFIED_CACHE		0x3
39*d0b3732eSbholler 
40*d0b3732eSbholler struct cpuid_values {
41*d0b3732eSbholler 	uint_t eax;
42*d0b3732eSbholler 	uint_t ebx;
43*d0b3732eSbholler 	uint_t ecx;
44*d0b3732eSbholler 	uint_t edx;
45*d0b3732eSbholler };
46*d0b3732eSbholler 
47*d0b3732eSbholler extern void	__amd64id(void);
48*d0b3732eSbholler 
49*d0b3732eSbholler /*
50*d0b3732eSbholler  * get_intel_cache_info()
51*d0b3732eSbholler  *	Get cpu cache sizes for optimized 64-bit libc functions mem* and str*.
52*d0b3732eSbholler  *	Find the sizes of the 1st, 2nd and largest level caches.
53*d0b3732eSbholler  */
54*d0b3732eSbholler static void
55*d0b3732eSbholler get_intel_cache_info(void)
56*d0b3732eSbholler {
57*d0b3732eSbholler 	int cache_level;
58*d0b3732eSbholler 	int largest_cache_level = 0;
59*d0b3732eSbholler 	int cache_index = 0;
60*d0b3732eSbholler 	int cache_type;
61*d0b3732eSbholler 	int line_size, partitions, ways, sets;
62*d0b3732eSbholler 	uint_t cache_size;
63*d0b3732eSbholler 	uint_t l1_cache_size = 0;
64*d0b3732eSbholler 	uint_t l2_cache_size = 0;
65*d0b3732eSbholler 	uint_t largest_level_cache = 0;
66*d0b3732eSbholler 	struct cpuid_values cpuid_info;
67*d0b3732eSbholler 
68*d0b3732eSbholler 	while (1) {
69*d0b3732eSbholler 		__libc_get_cpuid(4, (uint_t *)&cpuid_info, cache_index);
70*d0b3732eSbholler 
71*d0b3732eSbholler 		cache_type = cpuid_info.eax & 0x1f;
72*d0b3732eSbholler 		if (cache_type == NULL_CACHE) {
73*d0b3732eSbholler 			/*
74*d0b3732eSbholler 			 * No more caches.
75*d0b3732eSbholler 			 */
76*d0b3732eSbholler 			break;
77*d0b3732eSbholler 		}
78*d0b3732eSbholler 		cache_index += 1;
79*d0b3732eSbholler 
80*d0b3732eSbholler 		if (cache_type == INSTRUCTION_CACHE) {
81*d0b3732eSbholler 			/*
82*d0b3732eSbholler 			 * Don't care for memops
83*d0b3732eSbholler 			 */
84*d0b3732eSbholler 			continue;
85*d0b3732eSbholler 		}
86*d0b3732eSbholler 
87*d0b3732eSbholler 		cache_level = (cpuid_info.eax >> 0x5) & 0x7;
88*d0b3732eSbholler 		line_size = (cpuid_info.ebx & 0xfff) + 1;
89*d0b3732eSbholler 		partitions = ((cpuid_info.ebx >> 12) & 0x3ff) + 1;
90*d0b3732eSbholler 		ways = ((cpuid_info.ebx >> 22) & 0x3ff) + 1;
91*d0b3732eSbholler 		sets = cpuid_info.ecx + 1;
92*d0b3732eSbholler 		cache_size = ways * partitions * line_size * sets;
93*d0b3732eSbholler 
94*d0b3732eSbholler 		if (cache_level == 1) {
95*d0b3732eSbholler 			l1_cache_size = cache_size;
96*d0b3732eSbholler 		}
97*d0b3732eSbholler 		if (cache_level == 2) {
98*d0b3732eSbholler 			l2_cache_size = cache_size;
99*d0b3732eSbholler 		}
100*d0b3732eSbholler 		if (cache_level > largest_cache_level) {
101*d0b3732eSbholler 			largest_cache_level = cache_level;
102*d0b3732eSbholler 			largest_level_cache = cache_size;
103*d0b3732eSbholler 		}
104*d0b3732eSbholler 	}
105*d0b3732eSbholler 
106*d0b3732eSbholler 	__intel_set_cache_sizes(l1_cache_size, l2_cache_size,
107*d0b3732eSbholler 	    largest_level_cache);
108*d0b3732eSbholler }
109*d0b3732eSbholler 
110*d0b3732eSbholler /*
111*d0b3732eSbholler  * proc64_id()
112*d0b3732eSbholler  *	Determine cache and SSE level to use for memops and strops specific to
113*d0b3732eSbholler  *	processor type.
114*d0b3732eSbholler  */
115*d0b3732eSbholler void
116*d0b3732eSbholler __proc64id(void)
117*d0b3732eSbholler {
118*d0b3732eSbholler 	int use_sse = NO_SSE;
119*d0b3732eSbholler 	struct cpuid_values cpuid_info;
120*d0b3732eSbholler 
121*d0b3732eSbholler 	__libc_get_cpuid(0, &cpuid_info, 0);
122*d0b3732eSbholler 
123*d0b3732eSbholler 	/*
124*d0b3732eSbholler 	 * Check for AuthenticAMD
125*d0b3732eSbholler 	 */
126*d0b3732eSbholler 	if ((cpuid_info.ebx == 0x68747541) && /* Auth */
127*d0b3732eSbholler 	    (cpuid_info.edx == 0x69746e65) && /* enti */
128*d0b3732eSbholler 	    (cpuid_info.ecx == 0x444d4163)) { /* cAMD */
129*d0b3732eSbholler 		__amd64id();
130*d0b3732eSbholler 		return;
131*d0b3732eSbholler 	}
132*d0b3732eSbholler 
133*d0b3732eSbholler 	/*
134*d0b3732eSbholler 	 * Check for GenuineIntel
135*d0b3732eSbholler 	 */
136*d0b3732eSbholler 	if ((cpuid_info.ebx != 0x756e6547) || /* Genu */
137*d0b3732eSbholler 	    (cpuid_info.edx != 0x49656e69) || /* ineI */
138*d0b3732eSbholler 	    (cpuid_info.ecx != 0x6c65746e)) { /* ntel */
139*d0b3732eSbholler 		/*
140*d0b3732eSbholler 		 * Not Intel - use defaults.
141*d0b3732eSbholler 		 */
142*d0b3732eSbholler 		return;
143*d0b3732eSbholler 	}
144*d0b3732eSbholler 
145*d0b3732eSbholler 	/*
146*d0b3732eSbholler 	 * Genuine Intel
147*d0b3732eSbholler 	 */
148*d0b3732eSbholler 
149*d0b3732eSbholler 	/*
150*d0b3732eSbholler 	 * Look for CPUID function 4 support - Deterministic Cache Parameters.
151*d0b3732eSbholler 	 * Otherwise use default cache sizes.
152*d0b3732eSbholler 	 */
153*d0b3732eSbholler 	if (cpuid_info.eax >= 4) {
154*d0b3732eSbholler 		get_intel_cache_info();
155*d0b3732eSbholler 
156*d0b3732eSbholler 		/*
157*d0b3732eSbholler 		 * Check what SSE versions are supported.
158*d0b3732eSbholler 		 */
159*d0b3732eSbholler 		__libc_get_cpuid(1, &cpuid_info, 0);
160*d0b3732eSbholler 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_2) {
161*d0b3732eSbholler 			use_sse |= USE_SSE4_2;
162*d0b3732eSbholler 		}
163*d0b3732eSbholler 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_1) {
164*d0b3732eSbholler 			use_sse |= USE_SSE4_1;
165*d0b3732eSbholler 		}
166*d0b3732eSbholler 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSSE3) {
167*d0b3732eSbholler 			use_sse |= USE_SSSE3;
168*d0b3732eSbholler 		}
169*d0b3732eSbholler 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE3) {
170*d0b3732eSbholler 			use_sse |= USE_SSE3;
171*d0b3732eSbholler 		}
172*d0b3732eSbholler 		if (cpuid_info.edx & CPUID_INTC_EDX_SSE2) {
173*d0b3732eSbholler 			use_sse |= USE_SSE2;
174*d0b3732eSbholler 		}
175*d0b3732eSbholler 		__intel_set_memops_method(use_sse);
176*d0b3732eSbholler 	} else {
177*d0b3732eSbholler 		__intel_set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE,
178*d0b3732eSbholler 		    INTEL_DFLT_L2_CACHE_SIZE,
179*d0b3732eSbholler 		    INTEL_DFLT_LARGEST_CACHE_SIZE);
180*d0b3732eSbholler 		__intel_set_memops_method(use_sse);
181*d0b3732eSbholler 	}
182*d0b3732eSbholler }
183