xref: /onnv-gate/usr/src/lib/libc/amd64/gen/proc64_id.c (revision 10583:1058268e7f53)
16320Sbholler /*
26320Sbholler  * CDDL HEADER START
36320Sbholler  *
46320Sbholler  * The contents of this file are subject to the terms of the
56320Sbholler  * Common Development and Distribution License (the "License").
66320Sbholler  * You may not use this file except in compliance with the License.
76320Sbholler  *
86320Sbholler  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96320Sbholler  * or http://www.opensolaris.org/os/licensing.
106320Sbholler  * See the License for the specific language governing permissions
116320Sbholler  * and limitations under the License.
126320Sbholler  *
136320Sbholler  * When distributing Covered Code, include this CDDL HEADER in each
146320Sbholler  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156320Sbholler  * If applicable, add the following below this CDDL HEADER, with the
166320Sbholler  * fields enclosed by brackets "[]" replaced with your own identifying
176320Sbholler  * information: Portions Copyright [yyyy] [name of copyright owner]
186320Sbholler  *
196320Sbholler  * CDDL HEADER END
206320Sbholler  */
216320Sbholler 
226320Sbholler /*
23*10583SEdward.Gillett@Sun.COM  * Copyright (c) 2009, Intel Corporation.
246320Sbholler  * All rights reserved.
256320Sbholler  */
266320Sbholler 
2710024Sbostrovs /*
2810024Sbostrovs  * Portions Copyright 2009 Advanced Micro Devices, Inc.
2910024Sbostrovs  */
306320Sbholler 
316320Sbholler #include <sys/types.h>
326320Sbholler #include "proc64_id.h"
336320Sbholler 
346320Sbholler /*
356320Sbholler  * Intel cpuid eax=4 Cache Types
366320Sbholler  */
376320Sbholler #define	NULL_CACHE		0x0
386320Sbholler #define	DATA_CACHE		0x1
396320Sbholler #define	INSTRUCTION_CACHE	0x2
406320Sbholler #define	UNIFIED_CACHE		0x3
416320Sbholler 
426320Sbholler struct cpuid_values {
436320Sbholler 	uint_t eax;
446320Sbholler 	uint_t ebx;
456320Sbholler 	uint_t ecx;
466320Sbholler 	uint_t edx;
476320Sbholler };
486320Sbholler 
496320Sbholler /*
506320Sbholler  * get_intel_cache_info()
516320Sbholler  *	Get cpu cache sizes for optimized 64-bit libc functions mem* and str*.
526320Sbholler  *	Find the sizes of the 1st, 2nd and largest level caches.
536320Sbholler  */
546320Sbholler static void
get_intel_cache_info(void)556320Sbholler get_intel_cache_info(void)
566320Sbholler {
576320Sbholler 	int cache_level;
586320Sbholler 	int largest_cache_level = 0;
596320Sbholler 	int cache_index = 0;
606320Sbholler 	int cache_type;
616320Sbholler 	int line_size, partitions, ways, sets;
626320Sbholler 	uint_t cache_size;
636320Sbholler 	uint_t l1_cache_size = 0;
646320Sbholler 	uint_t l2_cache_size = 0;
656320Sbholler 	uint_t largest_level_cache = 0;
666320Sbholler 	struct cpuid_values cpuid_info;
676320Sbholler 
686320Sbholler 	while (1) {
696320Sbholler 		__libc_get_cpuid(4, (uint_t *)&cpuid_info, cache_index);
706320Sbholler 
716320Sbholler 		cache_type = cpuid_info.eax & 0x1f;
726320Sbholler 		if (cache_type == NULL_CACHE) {
736320Sbholler 			/*
746320Sbholler 			 * No more caches.
756320Sbholler 			 */
766320Sbholler 			break;
776320Sbholler 		}
786320Sbholler 		cache_index += 1;
796320Sbholler 
806320Sbholler 		if (cache_type == INSTRUCTION_CACHE) {
816320Sbholler 			/*
826320Sbholler 			 * Don't care for memops
836320Sbholler 			 */
846320Sbholler 			continue;
856320Sbholler 		}
866320Sbholler 
876320Sbholler 		cache_level = (cpuid_info.eax >> 0x5) & 0x7;
886320Sbholler 		line_size = (cpuid_info.ebx & 0xfff) + 1;
896320Sbholler 		partitions = ((cpuid_info.ebx >> 12) & 0x3ff) + 1;
906320Sbholler 		ways = ((cpuid_info.ebx >> 22) & 0x3ff) + 1;
916320Sbholler 		sets = cpuid_info.ecx + 1;
926320Sbholler 		cache_size = ways * partitions * line_size * sets;
936320Sbholler 
946320Sbholler 		if (cache_level == 1) {
956320Sbholler 			l1_cache_size = cache_size;
966320Sbholler 		}
976320Sbholler 		if (cache_level == 2) {
986320Sbholler 			l2_cache_size = cache_size;
996320Sbholler 		}
1006320Sbholler 		if (cache_level > largest_cache_level) {
1016320Sbholler 			largest_cache_level = cache_level;
1026320Sbholler 			largest_level_cache = cache_size;
1036320Sbholler 		}
1046320Sbholler 	}
1056320Sbholler 
10610024Sbostrovs 	__set_cache_sizes(l1_cache_size, l2_cache_size, largest_level_cache);
10710024Sbostrovs }
10810024Sbostrovs 
10910024Sbostrovs /*
11010024Sbostrovs  * get_amd_cache_info()
11110024Sbostrovs  *      Same as get_intel_cache_info() but for AMD processors
11210024Sbostrovs  */
11310024Sbostrovs static void
get_amd_cache_info(void)11410024Sbostrovs get_amd_cache_info(void)
11510024Sbostrovs {
11610024Sbostrovs 	uint_t l1_cache_size = AMD_DFLT_L1_CACHE_SIZE;
11710024Sbostrovs 	uint_t l2_cache_size = AMD_DFLT_L2_CACHE_SIZE;
11810024Sbostrovs 	uint_t l3_cache_size = 0;
11910024Sbostrovs 	uint_t largest_level_cache = 0;
12010024Sbostrovs 	struct cpuid_values cpuid_info;
12110024Sbostrovs 	uint_t maxeax;
12210024Sbostrovs 	int ncores;
12310024Sbostrovs 
12410024Sbostrovs 	cpuid_info.eax = 0;
12510024Sbostrovs 	__libc_get_cpuid(0x80000000, (uint_t *)&cpuid_info, -1);
12610024Sbostrovs 	maxeax = cpuid_info.eax;
12710024Sbostrovs 
12810024Sbostrovs 	if (maxeax >= 0x80000005) {	/* We have L1D info */
12910024Sbostrovs 		__libc_get_cpuid(0x80000005, (uint_t *)&cpuid_info, -1);
13010024Sbostrovs 		l1_cache_size = ((cpuid_info.ecx >> 24) & 0xff) * 1024;
13110024Sbostrovs 	}
13210024Sbostrovs 
13310024Sbostrovs 	if (maxeax >= 0x80000006) {	/* We have L2 and L3 info */
13410024Sbostrovs 		__libc_get_cpuid(0x80000006, (uint_t *)&cpuid_info, -1);
13510024Sbostrovs 		l2_cache_size = ((cpuid_info.ecx >> 16) & 0xffff) * 1024;
13610024Sbostrovs 		l3_cache_size = ((cpuid_info.edx >> 18) & 0x3fff) * 512 * 1024;
13710024Sbostrovs 	}
13810024Sbostrovs 
13910024Sbostrovs 	/*
14010024Sbostrovs 	 * L3 cache is shared between cores on the processor
14110024Sbostrovs 	 */
14210024Sbostrovs 	if (maxeax >= 0x80000008 && l3_cache_size != 0) {
14310024Sbostrovs 		largest_level_cache = l3_cache_size;
14410024Sbostrovs 
14510024Sbostrovs 		/*
14610024Sbostrovs 		 * Divide by number of cores on the processor
14710024Sbostrovs 		 */
14810024Sbostrovs 		__libc_get_cpuid(0x80000008, (uint_t *)&cpuid_info, -1);
14910024Sbostrovs 		ncores = (cpuid_info.ecx & 0xff) + 1;
15010024Sbostrovs 		if (ncores > 1)
15110024Sbostrovs 			largest_level_cache /= ncores;
15210024Sbostrovs 
15310024Sbostrovs 		/*
15410024Sbostrovs 		 * L3 is a victim cache for L2
15510024Sbostrovs 		 */
15610024Sbostrovs 		largest_level_cache += l2_cache_size;
15710024Sbostrovs 	} else
15810024Sbostrovs 		largest_level_cache = l2_cache_size;
15910024Sbostrovs 
16010024Sbostrovs 		__set_cache_sizes(l1_cache_size, l2_cache_size,
16110024Sbostrovs 		    largest_level_cache);
1626320Sbholler }
1636320Sbholler 
1646320Sbholler /*
1656320Sbholler  * proc64_id()
1666320Sbholler  *	Determine cache and SSE level to use for memops and strops specific to
1676320Sbholler  *	processor type.
1686320Sbholler  */
1696320Sbholler void
__proc64id(void)1706320Sbholler __proc64id(void)
1716320Sbholler {
1726320Sbholler 	int use_sse = NO_SSE;
1736320Sbholler 	struct cpuid_values cpuid_info;
1746320Sbholler 
1756320Sbholler 	__libc_get_cpuid(0, &cpuid_info, 0);
1766320Sbholler 
1776320Sbholler 	/*
1786320Sbholler 	 * Check for AuthenticAMD
1796320Sbholler 	 */
1806320Sbholler 	if ((cpuid_info.ebx == 0x68747541) && /* Auth */
1816320Sbholler 	    (cpuid_info.edx == 0x69746e65) && /* enti */
1826320Sbholler 	    (cpuid_info.ecx == 0x444d4163)) { /* cAMD */
18310024Sbostrovs 		get_amd_cache_info();
1846320Sbholler 		return;
1856320Sbholler 	}
1866320Sbholler 
1876320Sbholler 	/*
1886320Sbholler 	 * Check for GenuineIntel
1896320Sbholler 	 */
1906320Sbholler 	if ((cpuid_info.ebx != 0x756e6547) || /* Genu */
1916320Sbholler 	    (cpuid_info.edx != 0x49656e69) || /* ineI */
1926320Sbholler 	    (cpuid_info.ecx != 0x6c65746e)) { /* ntel */
1936320Sbholler 		/*
1946320Sbholler 		 * Not Intel - use defaults.
1956320Sbholler 		 */
1966320Sbholler 		return;
1976320Sbholler 	}
1986320Sbholler 
1996320Sbholler 	/*
2006320Sbholler 	 * Genuine Intel
2016320Sbholler 	 */
2026320Sbholler 
2036320Sbholler 	/*
2046320Sbholler 	 * Look for CPUID function 4 support - Deterministic Cache Parameters.
2056320Sbholler 	 * Otherwise use default cache sizes.
2066320Sbholler 	 */
2076320Sbholler 	if (cpuid_info.eax >= 4) {
2086320Sbholler 		get_intel_cache_info();
2096320Sbholler 
2106320Sbholler 		/*
2116320Sbholler 		 * Check what SSE versions are supported.
2126320Sbholler 		 */
2136320Sbholler 		__libc_get_cpuid(1, &cpuid_info, 0);
2146320Sbholler 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_2) {
2156320Sbholler 			use_sse |= USE_SSE4_2;
2166320Sbholler 		}
2176320Sbholler 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_1) {
2186320Sbholler 			use_sse |= USE_SSE4_1;
2196320Sbholler 		}
2206320Sbholler 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSSE3) {
2216320Sbholler 			use_sse |= USE_SSSE3;
2226320Sbholler 		}
2236320Sbholler 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE3) {
2246320Sbholler 			use_sse |= USE_SSE3;
2256320Sbholler 		}
2266320Sbholler 		if (cpuid_info.edx & CPUID_INTC_EDX_SSE2) {
2276320Sbholler 			use_sse |= USE_SSE2;
2286320Sbholler 		}
229*10583SEdward.Gillett@Sun.COM 		use_sse |= USE_BSF;
2306320Sbholler 		__intel_set_memops_method(use_sse);
2316320Sbholler 	} else {
23210024Sbostrovs 		__set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE,
2336320Sbholler 		    INTEL_DFLT_L2_CACHE_SIZE,
2346320Sbholler 		    INTEL_DFLT_LARGEST_CACHE_SIZE);
2356320Sbholler 		__intel_set_memops_method(use_sse);
2366320Sbholler 	}
2376320Sbholler }
238