x86: Add cache information support for Zhaoxin processors

To obtain Zhaoxin CPU cache information, add a new function
handle_zhaoxin().

Add a new function get_common_cache_info() that extracts the code
in init_cacheinfo() to get the value of the variable shared, threads.

Add Zhaoxin branch in init_cacheinfo() for initializing variables,
such as __x86_shared_cache_size.
This commit is contained in:
mayshao-oc 2020-04-26 13:48:27 +08:00 committed by H.J. Lu
parent 32ac0b9884
commit a98dc92dd1
1 changed files with 282 additions and 196 deletions

View File

@ -436,6 +436,57 @@ handle_amd (int name)
} }
static long int __attribute__ ((noinline))
handle_zhaoxin (int name)
{
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
int folded_rel_name = (M(name) / 3) * 3;
unsigned int round = 0;
while (1)
{
__cpuid_count (4, round, eax, ebx, ecx, edx);
enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
if (type == null)
break;
unsigned int level = (eax >> 5) & 0x7;
if ((level == 1 && type == data
&& folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE))
|| (level == 1 && type == inst
&& folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE))
|| (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE))
|| (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)))
{
unsigned int offset = M(name) - folded_rel_name;
if (offset == 0)
/* Cache size. */
return (((ebx >> 22) + 1)
* (((ebx >> 12) & 0x3ff) + 1)
* ((ebx & 0xfff) + 1)
* (ecx + 1));
if (offset == 1)
return (ebx >> 22) + 1;
assert (offset == 2);
return (ebx & 0xfff) + 1;
}
++round;
}
/* Nothing found. */
return 0;
}
/* Get the value of the system variable NAME. */ /* Get the value of the system variable NAME. */
long int long int
attribute_hidden attribute_hidden
@ -449,6 +500,9 @@ __cache_sysconf (int name)
if (cpu_features->basic.kind == arch_kind_amd) if (cpu_features->basic.kind == arch_kind_amd)
return handle_amd (name); return handle_amd (name);
if (cpu_features->basic.kind == arch_kind_zhaoxin)
return handle_zhaoxin (name);
// XXX Fill in more vendors. // XXX Fill in more vendors.
/* CPU not known, we have no information. */ /* CPU not known, we have no information. */
@ -483,32 +537,13 @@ int __x86_prefetchw attribute_hidden;
static void static void
__attribute__((constructor)) get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr,
init_cacheinfo (void) long int core)
{ {
/* Find out what brand of processor. */
unsigned int eax; unsigned int eax;
unsigned int ebx; unsigned int ebx;
unsigned int ecx; unsigned int ecx;
unsigned int edx; unsigned int edx;
int max_cpuid_ex;
long int data = -1;
long int shared = -1;
unsigned int level;
unsigned int threads = 0;
const struct cpu_features *cpu_features = __get_cpu_features ();
int max_cpuid = cpu_features->basic.max_cpuid;
if (cpu_features->basic.kind == arch_kind_intel)
{
data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features);
long int core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features);
bool inclusive_cache = true;
/* Try L3 first. */
level = 3;
shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features);
/* Number of logical processors sharing L2 cache. */ /* Number of logical processors sharing L2 cache. */
int threads_l2; int threads_l2;
@ -516,6 +551,21 @@ init_cacheinfo (void)
/* Number of logical processors sharing L3 cache. */ /* Number of logical processors sharing L3 cache. */
int threads_l3; int threads_l3;
const struct cpu_features *cpu_features = __get_cpu_features ();
int max_cpuid = cpu_features->basic.max_cpuid;
unsigned int family = cpu_features->basic.family;
unsigned int model = cpu_features->basic.model;
long int shared = *shared_ptr;
unsigned int threads = *threads_ptr;
bool inclusive_cache = true;
bool support_count_mask = true;
/* Try L3 first. */
unsigned int level = 3;
if (cpu_features->basic.kind == arch_kind_zhaoxin && family == 6)
support_count_mask = false;
if (shared <= 0) if (shared <= 0)
{ {
/* Try L2 otherwise. */ /* Try L2 otherwise. */
@ -538,9 +588,6 @@ init_cacheinfo (void)
highest cache level. */ highest cache level. */
if (max_cpuid >= 4) if (max_cpuid >= 4)
{ {
unsigned int family = cpu_features->basic.family;
unsigned int model = cpu_features->basic.model;
int i = 0; int i = 0;
/* Query until cache level 2 and 3 are enumerated. */ /* Query until cache level 2 and 3 are enumerated. */
@ -553,7 +600,8 @@ init_cacheinfo (void)
which sometimes fail to iterate all cache parameters. which sometimes fail to iterate all cache parameters.
Do not loop indefinitely here, stop in this case and Do not loop indefinitely here, stop in this case and
assume there is no such information. */ assume there is no such information. */
if ((eax & 0x1f) == 0) if (cpu_features->basic.kind == arch_kind_intel
&& (eax & 0x1f) == 0 )
goto intel_bug_no_cache_info; goto intel_bug_no_cache_info;
switch ((eax >> 5) & 0x7) switch ((eax >> 5) & 0x7)
@ -589,7 +637,7 @@ init_cacheinfo (void)
numbers of addressable IDs for logical processors sharing numbers of addressable IDs for logical processors sharing
the cache, instead of the maximum number of threads the cache, instead of the maximum number of threads
sharing the cache. */ sharing the cache. */
if (max_cpuid >= 11) if (max_cpuid >= 11 && support_count_mask)
{ {
/* Find the number of logical processors shipped in /* Find the number of logical processors shipped in
one core and apply count mask. */ one core and apply count mask. */
@ -656,7 +704,9 @@ init_cacheinfo (void)
if (threads_l2) if (threads_l2)
{ {
threads = threads_l2; threads = threads_l2;
if (threads > 2 && family == 6) if (cpu_features->basic.kind == arch_kind_intel
&& threads > 2
&& family == 6)
switch (model) switch (model)
{ {
case 0x37: case 0x37:
@ -680,7 +730,6 @@ init_cacheinfo (void)
intel_bug_no_cache_info: intel_bug_no_cache_info:
/* Assume that all logical threads share the highest cache /* Assume that all logical threads share the highest cache
level. */ level. */
threads threads
= ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx = ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx
>> 16) & 0xff); >> 16) & 0xff);
@ -699,6 +748,43 @@ intel_bug_no_cache_info:
core /= threads_l2; core /= threads_l2;
shared += core; shared += core;
} }
*shared_ptr = shared;
*threads_ptr = threads;
}
static void
__attribute__((constructor))
init_cacheinfo (void)
{
/* Find out what brand of processor. */
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
int max_cpuid_ex;
long int data = -1;
long int shared = -1;
long int core;
unsigned int threads = 0;
const struct cpu_features *cpu_features = __get_cpu_features ();
if (cpu_features->basic.kind == arch_kind_intel)
{
data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features);
core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features);
shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features);
get_common_cache_info (&shared, &threads, core);
}
else if (cpu_features->basic.kind == arch_kind_zhaoxin)
{
data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE);
core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE);
shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE);
get_common_cache_info (&shared, &threads, core);
} }
else if (cpu_features->basic.kind == arch_kind_amd) else if (cpu_features->basic.kind == arch_kind_amd)
{ {