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