1d0b3732bholler/*
2d0b3732bholler * CDDL HEADER START
3d0b3732bholler *
4d0b3732bholler * The contents of this file are subject to the terms of the
5d0b3732bholler * Common Development and Distribution License (the "License").
6d0b3732bholler * You may not use this file except in compliance with the License.
7d0b3732bholler *
8d0b3732bholler * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d0b3732bholler * or http://www.opensolaris.org/os/licensing.
10d0b3732bholler * See the License for the specific language governing permissions
11d0b3732bholler * and limitations under the License.
12d0b3732bholler *
13d0b3732bholler * When distributing Covered Code, include this CDDL HEADER in each
14d0b3732bholler * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d0b3732bholler * If applicable, add the following below this CDDL HEADER, with the
16d0b3732bholler * fields enclosed by brackets "[]" replaced with your own identifying
17d0b3732bholler * information: Portions Copyright [yyyy] [name of copyright owner]
18d0b3732bholler *
19d0b3732bholler * CDDL HEADER END
20d0b3732bholler */
21d0b3732bholler
22d0b3732bholler/*
23533d3a4Edward Gillett * Copyright (c) 2009, Intel Corporation.
24d0b3732bholler * All rights reserved.
25d0b3732bholler */
26d0b3732bholler
27fad5204bostrovs/*
28fad5204bostrovs * Portions Copyright 2009 Advanced Micro Devices, Inc.
29fad5204bostrovs */
30d0b3732bholler
31d0b3732bholler#include <sys/types.h>
32d0b3732bholler#include "proc64_id.h"
33d0b3732bholler
34d0b3732bholler/*
35d0b3732bholler * Intel cpuid eax=4 Cache Types
36d0b3732bholler */
37d0b3732bholler#define	NULL_CACHE		0x0
38d0b3732bholler#define	DATA_CACHE		0x1
39d0b3732bholler#define	INSTRUCTION_CACHE	0x2
40d0b3732bholler#define	UNIFIED_CACHE		0x3
41d0b3732bholler
42d0b3732bhollerstruct cpuid_values {
43d0b3732bholler	uint_t eax;
44d0b3732bholler	uint_t ebx;
45d0b3732bholler	uint_t ecx;
46d0b3732bholler	uint_t edx;
47d0b3732bholler};
48d0b3732bholler
49d0b3732bholler/*
50d0b3732bholler * get_intel_cache_info()
51d0b3732bholler *	Get cpu cache sizes for optimized 64-bit libc functions mem* and str*.
52d0b3732bholler *	Find the sizes of the 1st, 2nd and largest level caches.
53d0b3732bholler */
54d0b3732bhollerstatic void
55d0b3732bhollerget_intel_cache_info(void)
56d0b3732bholler{
57d0b3732bholler	int cache_level;
58d0b3732bholler	int largest_cache_level = 0;
59d0b3732bholler	int cache_index = 0;
60d0b3732bholler	int cache_type;
61d0b3732bholler	int line_size, partitions, ways, sets;
62d0b3732bholler	uint_t cache_size;
63d0b3732bholler	uint_t l1_cache_size = 0;
64d0b3732bholler	uint_t l2_cache_size = 0;
65d0b3732bholler	uint_t largest_level_cache = 0;
66d0b3732bholler	struct cpuid_values cpuid_info;
67d0b3732bholler
68d0b3732bholler	while (1) {
69d0b3732bholler		__libc_get_cpuid(4, (uint_t *)&cpuid_info, cache_index);
70d0b3732bholler
71d0b3732bholler		cache_type = cpuid_info.eax & 0x1f;
72d0b3732bholler		if (cache_type == NULL_CACHE) {
73d0b3732bholler			/*
74d0b3732bholler			 * No more caches.
75d0b3732bholler			 */
76d0b3732bholler			break;
77d0b3732bholler		}
78d0b3732bholler		cache_index += 1;
79d0b3732bholler
80d0b3732bholler		if (cache_type == INSTRUCTION_CACHE) {
81d0b3732bholler			/*
82d0b3732bholler			 * Don't care for memops
83d0b3732bholler			 */
84d0b3732bholler			continue;
85d0b3732bholler		}
86d0b3732bholler
87d0b3732bholler		cache_level = (cpuid_info.eax >> 0x5) & 0x7;
88d0b3732bholler		line_size = (cpuid_info.ebx & 0xfff) + 1;
89d0b3732bholler		partitions = ((cpuid_info.ebx >> 12) & 0x3ff) + 1;
90d0b3732bholler		ways = ((cpuid_info.ebx >> 22) & 0x3ff) + 1;
91d0b3732bholler		sets = cpuid_info.ecx + 1;
92d0b3732bholler		cache_size = ways * partitions * line_size * sets;
93d0b3732bholler
94d0b3732bholler		if (cache_level == 1) {
95d0b3732bholler			l1_cache_size = cache_size;
96d0b3732bholler		}
97d0b3732bholler		if (cache_level == 2) {
98d0b3732bholler			l2_cache_size = cache_size;
99d0b3732bholler		}
100d0b3732bholler		if (cache_level > largest_cache_level) {
101d0b3732bholler			largest_cache_level = cache_level;
102d0b3732bholler			largest_level_cache = cache_size;
103d0b3732bholler		}
104d0b3732bholler	}
105d0b3732bholler
106fad5204bostrovs	__set_cache_sizes(l1_cache_size, l2_cache_size, largest_level_cache);
107fad5204bostrovs}
108fad5204bostrovs
109fad5204bostrovs/*
110fad5204bostrovs * get_amd_cache_info()
111fad5204bostrovs *      Same as get_intel_cache_info() but for AMD processors
112fad5204bostrovs */
113fad5204bostrovsstatic void
114fad5204bostrovsget_amd_cache_info(void)
115fad5204bostrovs{
116fad5204bostrovs	uint_t l1_cache_size = AMD_DFLT_L1_CACHE_SIZE;
117fad5204bostrovs	uint_t l2_cache_size = AMD_DFLT_L2_CACHE_SIZE;
118fad5204bostrovs	uint_t l3_cache_size = 0;
119fad5204bostrovs	uint_t largest_level_cache = 0;
120fad5204bostrovs	struct cpuid_values cpuid_info;
121fad5204bostrovs	uint_t maxeax;
122fad5204bostrovs	int ncores;
123fad5204bostrovs
124fad5204bostrovs	cpuid_info.eax = 0;
125fad5204bostrovs	__libc_get_cpuid(0x80000000, (uint_t *)&cpuid_info, -1);
126fad5204bostrovs	maxeax = cpuid_info.eax;
127fad5204bostrovs
128fad5204bostrovs	if (maxeax >= 0x80000005) {	/* We have L1D info */
129fad5204bostrovs		__libc_get_cpuid(0x80000005, (uint_t *)&cpuid_info, -1);
130fad5204bostrovs		l1_cache_size = ((cpuid_info.ecx >> 24) & 0xff) * 1024;
131fad5204bostrovs	}
132fad5204bostrovs
133fad5204bostrovs	if (maxeax >= 0x80000006) {	/* We have L2 and L3 info */
134fad5204bostrovs		__libc_get_cpuid(0x80000006, (uint_t *)&cpuid_info, -1);
135fad5204bostrovs		l2_cache_size = ((cpuid_info.ecx >> 16) & 0xffff) * 1024;
136fad5204bostrovs		l3_cache_size = ((cpuid_info.edx >> 18) & 0x3fff) * 512 * 1024;
137fad5204bostrovs	}
138fad5204bostrovs
139fad5204bostrovs	/*
140fad5204bostrovs	 * L3 cache is shared between cores on the processor
141fad5204bostrovs	 */
142fad5204bostrovs	if (maxeax >= 0x80000008 && l3_cache_size != 0) {
143fad5204bostrovs		largest_level_cache = l3_cache_size;
144fad5204bostrovs
145fad5204bostrovs		/*
146fad5204bostrovs		 * Divide by number of cores on the processor
147fad5204bostrovs		 */
148fad5204bostrovs		__libc_get_cpuid(0x80000008, (uint_t *)&cpuid_info, -1);
149fad5204bostrovs		ncores = (cpuid_info.ecx & 0xff) + 1;
150fad5204bostrovs		if (ncores > 1)
151fad5204bostrovs			largest_level_cache /= ncores;
152fad5204bostrovs
153fad5204bostrovs		/*
154fad5204bostrovs		 * L3 is a victim cache for L2
155fad5204bostrovs		 */
156fad5204bostrovs		largest_level_cache += l2_cache_size;
157f24aa11Toomas Soome	} else {
158fad5204bostrovs		largest_level_cache = l2_cache_size;
159f24aa11Toomas Soome	}
160fad5204bostrovs
161f24aa11Toomas Soome	__set_cache_sizes(l1_cache_size, l2_cache_size,
162f24aa11Toomas Soome	    largest_level_cache);
163d0b3732bholler}
164d0b3732bholler
165d0b3732bholler/*
166d0b3732bholler * proc64_id()
167d0b3732bholler *	Determine cache and SSE level to use for memops and strops specific to
168d0b3732bholler *	processor type.
169d0b3732bholler */
170d0b3732bhollervoid
171d0b3732bholler__proc64id(void)
172d0b3732bholler{
173d0b3732bholler	int use_sse = NO_SSE;
174d0b3732bholler	struct cpuid_values cpuid_info;
175d0b3732bholler
176d0b3732bholler	__libc_get_cpuid(0, &cpuid_info, 0);
177d0b3732bholler
178d0b3732bholler	/*
179d0b3732bholler	 * Check for AuthenticAMD
180d0b3732bholler	 */
181d0b3732bholler	if ((cpuid_info.ebx == 0x68747541) && /* Auth */
182d0b3732bholler	    (cpuid_info.edx == 0x69746e65) && /* enti */
183d0b3732bholler	    (cpuid_info.ecx == 0x444d4163)) { /* cAMD */
184fad5204bostrovs		get_amd_cache_info();
185d0b3732bholler		return;
186d0b3732bholler	}
187d0b3732bholler
188d0b3732bholler	/*
189d0b3732bholler	 * Check for GenuineIntel
190d0b3732bholler	 */
191d0b3732bholler	if ((cpuid_info.ebx != 0x756e6547) || /* Genu */
192d0b3732bholler	    (cpuid_info.edx != 0x49656e69) || /* ineI */
193d0b3732bholler	    (cpuid_info.ecx != 0x6c65746e)) { /* ntel */
194d0b3732bholler		/*
195d0b3732bholler		 * Not Intel - use defaults.
196d0b3732bholler		 */
197d0b3732bholler		return;
198d0b3732bholler	}
199d0b3732bholler
200d0b3732bholler	/*
201d0b3732bholler	 * Genuine Intel
202d0b3732bholler	 */
203d0b3732bholler
204d0b3732bholler	/*
205d0b3732bholler	 * Look for CPUID function 4 support - Deterministic Cache Parameters.
206d0b3732bholler	 * Otherwise use default cache sizes.
207d0b3732bholler	 */
208d0b3732bholler	if (cpuid_info.eax >= 4) {
209d0b3732bholler		get_intel_cache_info();
210d0b3732bholler
211d0b3732bholler		/*
212d0b3732bholler		 * Check what SSE versions are supported.
213d0b3732bholler		 */
214d0b3732bholler		__libc_get_cpuid(1, &cpuid_info, 0);
215d0b3732bholler		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_2) {
216d0b3732bholler			use_sse |= USE_SSE4_2;
217d0b3732bholler		}
218d0b3732bholler		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_1) {
219d0b3732bholler			use_sse |= USE_SSE4_1;
220d0b3732bholler		}
221d0b3732bholler		if (cpuid_info.ecx & CPUID_INTC_ECX_SSSE3) {
222d0b3732bholler			use_sse |= USE_SSSE3;
223d0b3732bholler		}
224d0b3732bholler		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE3) {
225d0b3732bholler			use_sse |= USE_SSE3;
226d0b3732bholler		}
227d0b3732bholler		if (cpuid_info.edx & CPUID_INTC_EDX_SSE2) {
228d0b3732bholler			use_sse |= USE_SSE2;
229d0b3732bholler		}
230533d3a4Edward Gillett		use_sse |= USE_BSF;
231d0b3732bholler		__intel_set_memops_method(use_sse);
232d0b3732bholler	} else {
233fad5204bostrovs		__set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE,
234d0b3732bholler		    INTEL_DFLT_L2_CACHE_SIZE,
235d0b3732bholler		    INTEL_DFLT_LARGEST_CACHE_SIZE);
236d0b3732bholler		__intel_set_memops_method(use_sse);
237d0b3732bholler	}
238d0b3732bholler}
239