i386: Add L3 cache support to AMD CPUID4 emulation
With that an L3 cache is correctly reported in the cache information in /sys With fixes from Andreas Herrmann and Dean Gaudet and Joachim Deguara Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
2aae950b21
commit
67cddd9479
|
@ -272,8 +272,12 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (cpuid_eax(0x80000000) >= 0x80000006)
|
if (cpuid_eax(0x80000000) >= 0x80000006) {
|
||||||
num_cache_leaves = 3;
|
if ((c->x86 == 0x10) && (cpuid_edx(0x80000006) & 0xf000))
|
||||||
|
num_cache_leaves = 4;
|
||||||
|
else
|
||||||
|
num_cache_leaves = 3;
|
||||||
|
}
|
||||||
|
|
||||||
if (amd_apic_timer_broken())
|
if (amd_apic_timer_broken())
|
||||||
set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
|
set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Changes:
|
* Changes:
|
||||||
* Venkatesh Pallipadi : Adding cache identification through cpuid(4)
|
* Venkatesh Pallipadi : Adding cache identification through cpuid(4)
|
||||||
* Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
|
* Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
|
||||||
* Andi Kleen : CPUID4 emulation on AMD.
|
* Andi Kleen / Andreas Herrmann : CPUID4 emulation on AMD.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -135,7 +135,7 @@ unsigned short num_cache_leaves;
|
||||||
|
|
||||||
/* AMD doesn't have CPUID4. Emulate it here to report the same
|
/* AMD doesn't have CPUID4. Emulate it here to report the same
|
||||||
information to the user. This makes some assumptions about the machine:
|
information to the user. This makes some assumptions about the machine:
|
||||||
No L3, L2 not shared, no SMT etc. that is currently true on AMD CPUs.
|
L2 not shared, no SMT etc. that is currently true on AMD CPUs.
|
||||||
|
|
||||||
In theory the TLBs could be reported as fake type (they are in "dummy").
|
In theory the TLBs could be reported as fake type (they are in "dummy").
|
||||||
Maybe later */
|
Maybe later */
|
||||||
|
@ -159,13 +159,26 @@ union l2_cache {
|
||||||
unsigned val;
|
unsigned val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union l3_cache {
|
||||||
|
struct {
|
||||||
|
unsigned line_size : 8;
|
||||||
|
unsigned lines_per_tag : 4;
|
||||||
|
unsigned assoc : 4;
|
||||||
|
unsigned res : 2;
|
||||||
|
unsigned size_encoded : 14;
|
||||||
|
};
|
||||||
|
unsigned val;
|
||||||
|
};
|
||||||
|
|
||||||
static const unsigned short assocs[] = {
|
static const unsigned short assocs[] = {
|
||||||
[1] = 1, [2] = 2, [4] = 4, [6] = 8,
|
[1] = 1, [2] = 2, [4] = 4, [6] = 8,
|
||||||
[8] = 16,
|
[8] = 16, [0xa] = 32, [0xb] = 48,
|
||||||
|
[0xc] = 64,
|
||||||
[0xf] = 0xffff // ??
|
[0xf] = 0xffff // ??
|
||||||
};
|
};
|
||||||
static const unsigned char levels[] = { 1, 1, 2 };
|
|
||||||
static const unsigned char types[] = { 1, 2, 3 };
|
static const unsigned char levels[] = { 1, 1, 2, 3 };
|
||||||
|
static const unsigned char types[] = { 1, 2, 3, 3 };
|
||||||
|
|
||||||
static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
|
static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
|
||||||
union _cpuid4_leaf_ebx *ebx,
|
union _cpuid4_leaf_ebx *ebx,
|
||||||
|
@ -175,37 +188,58 @@ static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
|
||||||
unsigned line_size, lines_per_tag, assoc, size_in_kb;
|
unsigned line_size, lines_per_tag, assoc, size_in_kb;
|
||||||
union l1_cache l1i, l1d;
|
union l1_cache l1i, l1d;
|
||||||
union l2_cache l2;
|
union l2_cache l2;
|
||||||
|
union l3_cache l3;
|
||||||
|
union l1_cache *l1 = &l1d;
|
||||||
|
|
||||||
eax->full = 0;
|
eax->full = 0;
|
||||||
ebx->full = 0;
|
ebx->full = 0;
|
||||||
ecx->full = 0;
|
ecx->full = 0;
|
||||||
|
|
||||||
cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
|
cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
|
||||||
cpuid(0x80000006, &dummy, &dummy, &l2.val, &dummy);
|
cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
|
||||||
|
|
||||||
if (leaf > 2 || !l1d.val || !l1i.val || !l2.val)
|
switch (leaf) {
|
||||||
return;
|
case 1:
|
||||||
|
l1 = &l1i;
|
||||||
eax->split.is_self_initializing = 1;
|
case 0:
|
||||||
eax->split.type = types[leaf];
|
if (!l1->val)
|
||||||
eax->split.level = levels[leaf];
|
return;
|
||||||
eax->split.num_threads_sharing = 0;
|
|
||||||
eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
|
|
||||||
|
|
||||||
if (leaf <= 1) {
|
|
||||||
union l1_cache *l1 = leaf == 0 ? &l1d : &l1i;
|
|
||||||
assoc = l1->assoc;
|
assoc = l1->assoc;
|
||||||
line_size = l1->line_size;
|
line_size = l1->line_size;
|
||||||
lines_per_tag = l1->lines_per_tag;
|
lines_per_tag = l1->lines_per_tag;
|
||||||
size_in_kb = l1->size_in_kb;
|
size_in_kb = l1->size_in_kb;
|
||||||
} else {
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!l2.val)
|
||||||
|
return;
|
||||||
assoc = l2.assoc;
|
assoc = l2.assoc;
|
||||||
line_size = l2.line_size;
|
line_size = l2.line_size;
|
||||||
lines_per_tag = l2.lines_per_tag;
|
lines_per_tag = l2.lines_per_tag;
|
||||||
/* cpu_data has errata corrections for K7 applied */
|
/* cpu_data has errata corrections for K7 applied */
|
||||||
size_in_kb = current_cpu_data.x86_cache_size;
|
size_in_kb = current_cpu_data.x86_cache_size;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!l3.val)
|
||||||
|
return;
|
||||||
|
assoc = l3.assoc;
|
||||||
|
line_size = l3.line_size;
|
||||||
|
lines_per_tag = l3.lines_per_tag;
|
||||||
|
size_in_kb = l3.size_encoded * 512;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eax->split.is_self_initializing = 1;
|
||||||
|
eax->split.type = types[leaf];
|
||||||
|
eax->split.level = levels[leaf];
|
||||||
|
if (leaf == 3)
|
||||||
|
eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
|
||||||
|
else
|
||||||
|
eax->split.num_threads_sharing = 0;
|
||||||
|
eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
|
||||||
|
|
||||||
|
|
||||||
if (assoc == 0xf)
|
if (assoc == 0xf)
|
||||||
eax->split.is_fully_associative = 1;
|
eax->split.is_fully_associative = 1;
|
||||||
ebx->split.coherency_line_size = line_size - 1;
|
ebx->split.coherency_line_size = line_size - 1;
|
||||||
|
|
|
@ -602,8 +602,11 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
||||||
if (c->extended_cpuid_level >= 0x80000008)
|
if (c->extended_cpuid_level >= 0x80000008)
|
||||||
amd_detect_cmp(c);
|
amd_detect_cmp(c);
|
||||||
|
|
||||||
/* Fix cpuid4 emulation for more */
|
if (c->extended_cpuid_level >= 0x80000006 &&
|
||||||
num_cache_leaves = 3;
|
(cpuid_edx(0x80000006) & 0xf000))
|
||||||
|
num_cache_leaves = 4;
|
||||||
|
else
|
||||||
|
num_cache_leaves = 3;
|
||||||
|
|
||||||
/* RDTSC can be speculated around */
|
/* RDTSC can be speculated around */
|
||||||
clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
|
clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
|
||||||
|
|
Loading…
Reference in New Issue