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