[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250905121515.192792-31-darwi@linutronix.de>
Date: Fri, 5 Sep 2025 14:15:10 +0200
From: "Ahmed S. Darwish" <darwi@...utronix.de>
To: Borislav Petkov <bp@...en8.de>,
Ingo Molnar <mingo@...hat.com>,
Dave Hansen <dave.hansen@...ux.intel.com>
Cc: Thomas Gleixner <tglx@...utronix.de>,
Andrew Cooper <andrew.cooper3@...rix.com>,
Sean Christopherson <seanjc@...gle.com>,
David Woodhouse <dwmw2@...radead.org>,
"H. Peter Anvin" <hpa@...or.com>,
Peter Zijlstra <peterz@...radead.org>,
Sohil Mehta <sohil.mehta@...el.com>,
John Ogness <john.ogness@...utronix.de>,
x86@...nel.org,
x86-cpuid@...ts.linux.dev,
LKML <linux-kernel@...r.kernel.org>,
"Ahmed S. Darwish" <darwi@...utronix.de>
Subject: [PATCH v5 30/35] x86/cacheinfo: Use parsed CPUID(0x80000005) and CPUID(0x80000006)
At the AMD CPUID(0x4)-emulation logic, use parsed CPUID(0x80000005) and
CPUID(0x80000006) access instead of direct CPUID queries.
Beside the CPUID parser centralization benefits, this allows using the
auto-generated <asm/cpuid/leaf_types.h> data types, and their full C99
bitfields, instead of doing ugly bitwise operations or defining custom
data types at call sites.
Remove the 'union {l1,l2,l3}_cache' data types as they are no longer
needed.
Replace the expression:
ci->num_leaves = (cpuid_edx(0x80000006) & 0xf000) ? 4 : 3;
with:
ci->num_leaves = cpuid_leaf(c, 0x80000006)->l3_assoc ? 4 : 3;
since per AMD manuals, an L3 associativity level of zero implies the
absence of an L3 cache on the CPU. The CPUID(0x80000006) l3_assoc
bitfield above is 4 bits wide at EDX offset 12.
While at it, separate the 'Fallback AMD CPUID(0x4) emulation' comment
from the '@..._L2_L3_INVALID_ASSOC' one, since the former acts as a
source code section header.
Signed-off-by: Ahmed S. Darwish <darwi@...utronix.de>
---
arch/x86/kernel/cpu/cacheinfo.c | 105 ++++++++++++--------------------
1 file changed, 40 insertions(+), 65 deletions(-)
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index 8474d9047bad..7033baa94276 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -56,47 +56,17 @@ static const enum cache_type cache_type_map[] = {
};
/*
- * Fallback AMD CPUID(0x4) emulation
+ * Fallback AMD CPUID(0x4) emulation:
* AMD CPUs with TOPOEXT can just use CPUID(0x8000001d)
- *
+ */
+
+/*
* @AMD_L2_L3_INVALID_ASSOC: cache info for the respective L2/L3 cache should
* be determined from CPUID(0x8000001d) instead of CPUID(0x80000006).
*/
-
#define AMD_CPUID4_FULLY_ASSOCIATIVE 0xffff
#define AMD_L2_L3_INVALID_ASSOC 0x9
-union l1_cache {
- struct {
- unsigned line_size :8;
- unsigned lines_per_tag :8;
- unsigned assoc :8;
- unsigned size_in_kb :8;
- };
- unsigned int val;
-};
-
-union l2_cache {
- struct {
- unsigned line_size :8;
- unsigned lines_per_tag :4;
- unsigned assoc :4;
- unsigned size_in_kb :16;
- };
- unsigned int 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 int val;
-};
-
/* L2/L3 associativity mapping */
static const unsigned short assocs[] = {
[1] = 1,
@@ -117,50 +87,52 @@ static const unsigned short assocs[] = {
static const unsigned char levels[] = { 1, 1, 2, 3 };
static const unsigned char types[] = { 1, 2, 3, 3 };
-static void legacy_amd_cpuid4(int index, struct leaf_0x4_n *regs)
+static void legacy_amd_cpuid4(struct cpuinfo_x86 *c, int index, struct leaf_0x4_n *regs)
{
- unsigned int dummy, line_size, lines_per_tag, assoc, size_in_kb;
- union l1_cache l1i, l1d, *l1;
- union l2_cache l2;
- union l3_cache l3;
+ const struct leaf_0x80000005_0 *el5 = cpuid_leaf(c, 0x80000005);
+ const struct leaf_0x80000006_0 *el6 = cpuid_leaf(c, 0x80000006);
+ const struct cpuid_regs *el5_raw = cpuid_leaf_raw(c, 0x80000005);
+ unsigned int line_size, lines_per_tag, assoc, size_in_kb;
*regs = (struct leaf_0x4_n){ };
- cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
- cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
-
- l1 = &l1d;
switch (index) {
- case 1:
- l1 = &l1i;
- fallthrough;
case 0:
- if (!l1->val)
+ if (!el5 || !el5_raw->ecx)
return;
- assoc = (l1->assoc == 0xff) ? AMD_CPUID4_FULLY_ASSOCIATIVE : l1->assoc;
- line_size = l1->line_size;
- lines_per_tag = l1->lines_per_tag;
- size_in_kb = l1->size_in_kb;
+ assoc = el5->l1_dcache_assoc;
+ line_size = el5->l1_dcache_line_size;
+ lines_per_tag = el5->l1_dcache_nlines;
+ size_in_kb = el5->l1_dcache_size_kb;
+ break;
+ case 1:
+ if (!el5 || !el5_raw->edx)
+ return;
+
+ assoc = el5->l1_icache_assoc;
+ line_size = el5->l1_icache_line_size;
+ lines_per_tag = el5->l1_icache_nlines;
+ size_in_kb = el5->l1_icache_size_kb;
break;
case 2:
- if (!l2.assoc || l2.assoc == AMD_L2_L3_INVALID_ASSOC)
+ if (!el6 || !el6->l2_assoc || el6->l2_assoc == AMD_L2_L3_INVALID_ASSOC)
return;
/* Use x86_cache_size as it might have K7 errata fixes */
- assoc = assocs[l2.assoc];
- line_size = l2.line_size;
- lines_per_tag = l2.lines_per_tag;
+ assoc = assocs[el6->l2_assoc];
+ line_size = el6->l2_line_size;
+ lines_per_tag = el6->l2_nlines;
size_in_kb = __this_cpu_read(cpu_info.x86_cache_size);
break;
case 3:
- if (!l3.assoc || l3.assoc == AMD_L2_L3_INVALID_ASSOC)
+ if (!el6 || !el6->l3_assoc || el6->l3_assoc == AMD_L2_L3_INVALID_ASSOC)
return;
- assoc = assocs[l3.assoc];
- line_size = l3.line_size;
- lines_per_tag = l3.lines_per_tag;
- size_in_kb = l3.size_encoded * 512;
+ assoc = assocs[el6->l3_assoc];
+ line_size = el6->l3_line_size;
+ lines_per_tag = el6->l3_nlines;
+ size_in_kb = el6->l3_size_range * 512;
if (boot_cpu_has(X86_FEATURE_AMD_DCM)) {
size_in_kb = size_in_kb >> 1;
assoc = assoc >> 1;
@@ -170,6 +142,10 @@ static void legacy_amd_cpuid4(int index, struct leaf_0x4_n *regs)
return;
}
+ /* For L1d and L1i caches, 0xff is the full associativity marker */
+ if ((index == 0 || index == 1) && assoc == 0xff)
+ assoc = AMD_CPUID4_FULLY_ASSOCIATIVE;
+
regs->cache_self_init = 1;
regs->cache_type = types[index];
regs->cache_level = levels[index];
@@ -213,7 +189,7 @@ static int amd_fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4
/* CPUID(0x8000001d) and CPUID(0x4) have the same bitfields */
l_0x4_regs = *(struct leaf_0x4_n *)regs;
} else
- legacy_amd_cpuid4(index, &l_0x4_regs);
+ legacy_amd_cpuid4(c, index, &l_0x4_regs);
return cpuid4_info_fill_done(id4, &l_0x4_regs);
}
@@ -300,10 +276,9 @@ void init_amd_cacheinfo(struct cpuinfo_x86 *c)
{
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
- if (boot_cpu_has(X86_FEATURE_TOPOEXT))
- ci->num_leaves = cpuid_subleaf_count(c, 0x8000001d);
- else if (c->extended_cpuid_level >= 0x80000006)
- ci->num_leaves = (cpuid_edx(0x80000006) & 0xf000) ? 4 : 3;
+ ci->num_leaves = boot_cpu_has(X86_FEATURE_TOPOEXT) ?
+ cpuid_subleaf_count(c, 0x8000001d) :
+ cpuid_leaf(c, 0x80000006)->l3_assoc ? 4 : 3;
}
void init_hygon_cacheinfo(struct cpuinfo_x86 *c)
--
2.50.1
Powered by blists - more mailing lists