#include <sys/types.h>
#include "proc64_id.h"
#define NULL_CACHE 0x0
#define DATA_CACHE 0x1
#define INSTRUCTION_CACHE 0x2
#define UNIFIED_CACHE 0x3
struct cpuid_values {
uint_t eax;
uint_t ebx;
uint_t ecx;
uint_t edx;
};
static void
get_intel_cache_info(void)
{
int cache_level;
int largest_cache_level = 0;
int cache_index = 0;
int cache_type;
int line_size, partitions, ways, sets;
uint_t cache_size;
uint_t l1_cache_size = 0;
uint_t l2_cache_size = 0;
uint_t largest_level_cache = 0;
struct cpuid_values cpuid_info;
while (1) {
__libc_get_cpuid(4, (uint_t *)&cpuid_info, cache_index);
cache_type = cpuid_info.eax & 0x1f;
if (cache_type == NULL_CACHE) {
break;
}
cache_index += 1;
if (cache_type == INSTRUCTION_CACHE) {
continue;
}
cache_level = (cpuid_info.eax >> 0x5) & 0x7;
line_size = (cpuid_info.ebx & 0xfff) + 1;
partitions = ((cpuid_info.ebx >> 12) & 0x3ff) + 1;
ways = ((cpuid_info.ebx >> 22) & 0x3ff) + 1;
sets = cpuid_info.ecx + 1;
cache_size = ways * partitions * line_size * sets;
if (cache_level == 1) {
l1_cache_size = cache_size;
}
if (cache_level == 2) {
l2_cache_size = cache_size;
}
if (cache_level > largest_cache_level) {
largest_cache_level = cache_level;
largest_level_cache = cache_size;
}
}
__set_cache_sizes(l1_cache_size, l2_cache_size, largest_level_cache);
}
static void
get_amd_cache_info(void)
{
uint_t l1_cache_size = AMD_DFLT_L1_CACHE_SIZE;
uint_t l2_cache_size = AMD_DFLT_L2_CACHE_SIZE;
uint_t l3_cache_size = 0;
uint_t largest_level_cache = 0;
struct cpuid_values cpuid_info;
uint_t maxeax;
int ncores;
cpuid_info.eax = 0;
__libc_get_cpuid(0x80000000, (uint_t *)&cpuid_info, -1);
maxeax = cpuid_info.eax;
if (maxeax >= 0x80000005) {
__libc_get_cpuid(0x80000005, (uint_t *)&cpuid_info, -1);
l1_cache_size = ((cpuid_info.ecx >> 24) & 0xff) * 1024;
}
if (maxeax >= 0x80000006) {
__libc_get_cpuid(0x80000006, (uint_t *)&cpuid_info, -1);
l2_cache_size = ((cpuid_info.ecx >> 16) & 0xffff) * 1024;
l3_cache_size = ((cpuid_info.edx >> 18) & 0x3fff) * 512 * 1024;
}
if (maxeax >= 0x80000008 && l3_cache_size != 0) {
largest_level_cache = l3_cache_size;
__libc_get_cpuid(0x80000008, (uint_t *)&cpuid_info, -1);
ncores = (cpuid_info.ecx & 0xff) + 1;
if (ncores > 1)
largest_level_cache /= ncores;
largest_level_cache += l2_cache_size;
} else {
largest_level_cache = l2_cache_size;
}
__set_cache_sizes(l1_cache_size, l2_cache_size,
largest_level_cache);
}
void
__proc64id(void)
{
int use_sse = NO_SSE;
struct cpuid_values cpuid_info;
__libc_get_cpuid(0, &cpuid_info, 0);
if ((cpuid_info.ebx == 0x68747541) &&
(cpuid_info.edx == 0x69746e65) &&
(cpuid_info.ecx == 0x444d4163)) {
get_amd_cache_info();
return;
}
if ((cpuid_info.ebx != 0x756e6547) ||
(cpuid_info.edx != 0x49656e69) ||
(cpuid_info.ecx != 0x6c65746e)) {
return;
}
if (cpuid_info.eax >= 4) {
get_intel_cache_info();
__libc_get_cpuid(1, &cpuid_info, 0);
if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_2) {
use_sse |= USE_SSE4_2;
}
if (cpuid_info.ecx & CPUID_INTC_ECX_SSE4_1) {
use_sse |= USE_SSE4_1;
}
if (cpuid_info.ecx & CPUID_INTC_ECX_SSSE3) {
use_sse |= USE_SSSE3;
}
if (cpuid_info.ecx & CPUID_INTC_ECX_SSE3) {
use_sse |= USE_SSE3;
}
if (cpuid_info.edx & CPUID_INTC_EDX_SSE2) {
use_sse |= USE_SSE2;
}
use_sse |= USE_BSF;
__intel_set_memops_method(use_sse);
} else {
__set_cache_sizes(INTEL_DFLT_L1_CACHE_SIZE,
INTEL_DFLT_L2_CACHE_SIZE,
INTEL_DFLT_LARGEST_CACHE_SIZE);
__intel_set_memops_method(use_sse);
}
}