Home | History | Annotate | Download | only in gen
      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) 2009, Intel Corporation.
     24  * All rights reserved.
     25  */
     26 
     27 /*
     28  * Portions Copyright 2009 Advanced Micro Devices, Inc.
     29  */
     30 
     31 #include <sys/types.h>
     32 #include "proc64_id.h"
     33 
     34 /*
     35  * Intel cpuid eax=4 Cache Types
     36  */
     37 #define	NULL_CACHE		0x0
     38 #define	DATA_CACHE		0x1
     39 #define	INSTRUCTION_CACHE	0x2
     40 #define	UNIFIED_CACHE		0x3
     41 
     42 struct cpuid_values {
     43 	uint_t eax;
     44 	uint_t ebx;
     45 	uint_t ecx;
     46 	uint_t edx;
     47 };
     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 	__set_cache_sizes(l1_cache_size, l2_cache_size, largest_level_cache);
    107 }
    108 
    109 /*
    110  * get_amd_cache_info()
    111  *      Same as get_intel_cache_info() but for AMD processors
    112  */
    113 static void
    114 get_amd_cache_info(void)
    115 {
    116 	uint_t l1_cache_size = AMD_DFLT_L1_CACHE_SIZE;
    117 	uint_t l2_cache_size = AMD_DFLT_L2_CACHE_SIZE;
    118 	uint_t l3_cache_size = 0;
    119 	uint_t largest_level_cache = 0;
    120 	struct cpuid_values cpuid_info;
    121 	uint_t maxeax;
    122 	int ncores;
    123 
    124 	cpuid_info.eax = 0;
    125 	__libc_get_cpuid(0x80000000, (uint_t *)&cpuid_info, -1);
    126 	maxeax = cpuid_info.eax;
    127 
    128 	if (maxeax >= 0x80000005) {	/* We have L1D info */
    129 		__libc_get_cpuid(0x80000005, (uint_t *)&cpuid_info, -1);
    130 		l1_cache_size = ((cpuid_info.ecx >> 24) & 0xff) * 1024;
    131 	}
    132 
    133 	if (maxeax >= 0x80000006) {	/* We have L2 and L3 info */
    134 		__libc_get_cpuid(0x80000006, (uint_t *)&cpuid_info, -1);
    135 		l2_cache_size = ((cpuid_info.ecx >> 16) & 0xffff) * 1024;
    136 		l3_cache_size = ((cpuid_info.edx >> 18) & 0x3fff) * 512 * 1024;
    137 	}
    138 
    139 	/*
    140 	 * L3 cache is shared between cores on the processor
    141 	 */
    142 	if (maxeax >= 0x80000008 && l3_cache_size != 0) {
    143 		largest_level_cache = l3_cache_size;
    144 
    145 		/*
    146 		 * Divide by number of cores on the processor
    147 		 */
    148 		__libc_get_cpuid(0x80000008, (uint_t *)&cpuid_info, -1);
    149 		ncores = (cpuid_info.ecx & 0xff) + 1;
    150 		if (ncores > 1)
    151 			largest_level_cache /= ncores;
    152 
    153 		/*
    154 		 * L3 is a victim cache for L2
    155 		 */
    156 		largest_level_cache += l2_cache_size;
    157 	} else
    158 		largest_level_cache = l2_cache_size;
    159 
    160 		__set_cache_sizes(l1_cache_size, l2_cache_size,
    161 		    largest_level_cache);
    162 }
    163 
    164 /*
    165  * proc64_id()
    166  *	Determine cache and SSE level to use for memops and strops specific to
    167  *	processor type.
    168  */
    169 void
    170 __proc64id(void)
    171 {
    172 	int use_sse = NO_SSE;
    173 	struct cpuid_values cpuid_info;
    174 
    175 	__libc_get_cpuid(0, &cpuid_info, 0);
    176 
    177 	/*
    178 	 * Check for AuthenticAMD
    179 	 */
    180 	if ((cpuid_info.ebx == 0x68747541) && /* Auth */
    181 	    (cpuid_info.edx == 0x69746e65) && /* enti */
    182 	    (cpuid_info.ecx == 0x444d4163)) { /* cAMD */
    183 		get_amd_cache_info();
    184 		return;
    185 	}
    186 
    187 	/*
    188 	 * Check for GenuineIntel
    189 	 */
    190 	if ((cpuid_info.ebx != 0x756e6547) || /* Genu */
    191 	    (cpuid_info.edx != 0x49656e69) || /* ineI */
    192 	    (cpuid_info.ecx != 0x6c65746e)) { /* ntel */
    193 		/*
    194 		 * Not Intel - use defaults.
    195 		 */
    196 		return;
    197 	}
    198 
    199 	/*
    200 	 * Genuine Intel
    201 	 */
    202 
    203 	/*
    204 	 * Look for CPUID function 4 support - Deterministic Cache Parameters.
    205 	 * Otherwise use default cache sizes.
    206 	 */
    207 	if (cpuid_info.eax >= 4) {
    208 		get_intel_cache_info();
    209 
    210 		/*
    211 		 * Check what SSE versions are supported.
    212 		 */
    213 		__libc_get_cpuid(1, &cpuid_info, 0);
    214 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_2) {
    215 			use_sse |= USE_SSE4_2;
    216 		}
    217 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_1) {
    218 			use_sse |= USE_SSE4_1;
    219 		}
    220 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSSE3) {
    221 			use_sse |= USE_SSSE3;
    222 		}
    223 		if (cpuid_info.ecx & CPUID_INTC_ECX_SSE3) {
    224 			use_sse |= USE_SSE3;
    225 		}
    226 		if (cpuid_info.edx & CPUID_INTC_EDX_SSE2) {
    227 			use_sse |= USE_SSE2;
    228 		}
    229 		use_sse |= USE_BSF;
    230 		__intel_set_memops_method(use_sse);
    231 	} else {
    232 		__set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE,
    233 		    INTEL_DFLT_L2_CACHE_SIZE,
    234 		    INTEL_DFLT_LARGEST_CACHE_SIZE);
    235 		__intel_set_memops_method(use_sse);
    236 	}
    237 }
    238