[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250506050437.10264-21-darwi@linutronix.de>
Date: Tue, 6 May 2025 07:04:31 +0200
From: "Ahmed S. Darwish" <darwi@...utronix.de>
To: Ingo Molnar <mingo@...hat.com>,
Borislav Petkov <bp@...en8.de>,
Dave Hansen <dave.hansen@...ux.intel.com>
Cc: Thomas Gleixner <tglx@...utronix.de>,
Andrew Cooper <andrew.cooper3@...rix.com>,
"H. Peter Anvin" <hpa@...or.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 v1 20/26] x86/cacheinfo: Use scanned CPUID(0x8000001d)
Refactor the AMD CPUID(0x8000001d) cacheinfo logic to use the scanned
CPUID API instead of issuing direct CPUID queries.
Beside CPUID data centralization benefits, this allows using the
auto-generated <cpuid/leaves.h> 'struct cpuid_0x8000001d_0' data type
with its full C99 bitfields instead of doing ugly bitwise operations.
Since scanned CPUID access requires a 'struct cpuinfo_x86' reference,
trickle it down to relevant functions.
Use the scanned CPUID API:
cpudata_cpuid_nr_entries(c, 0x8000001d)
to find the number of cache leaves, thus replacing
amd_find_num_cache_leaves() and its direct CPUID queries. Drop that
function entirely as it is no longer needed.
For now, keep using the 'union _cpuid4_leaf_eax/ebx/ecx' structures as
they are required by the AMD CPUID(0x4) emulation code paths. A follow
up commit will replace them with <cpuid/leaves.h> equivalents.
Note, for below code:
cpuid_count(0x8000001d, llc_index, &eax, &ebx, &ecx, &edx);
if (eax)
num_sharing_cache = ((eax >> 14) & 0xfff) + 1;
if (num_sharing_cache) {
int index_msb = get_count_order(num_sharing_cache);
...
}
it is replaced with:
const struct leaf_0x8000001d_0 *leaf =
cpudata_cpuid_index(c, 0x8000001d, llc_index);
if (leaf) {
int index_msb = get_count_order(l->num_threads_sharing + 1);
...
}
The "if (leaf)" check is sufficient since the scanned CPUID API returns
NULL if the leaf is out of range (> max CPU extended leaf) or if the
'llc_index' is out of range. An out of range LLC index is equivalent to
"EAX.cache_type == 0" in the original code, making the logic match.
Signed-off-by: Ahmed S. Darwish <darwi@...utronix.de>
---
arch/x86/kernel/cpu/cacheinfo.c | 47 +++++++++++----------------------
1 file changed, 16 insertions(+), 31 deletions(-)
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index 9de75c8b76ff..4f218960cc41 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -237,16 +237,19 @@ static int cpuid4_info_fill_done(struct _cpuid4_info *id4, union _cpuid4_leaf_ea
return 0;
}
-static int amd_fill_cpuid4_info(int index, struct _cpuid4_info *id4)
+static int amd_fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_info *id4)
{
union _cpuid4_leaf_eax eax;
union _cpuid4_leaf_ebx ebx;
union _cpuid4_leaf_ecx ecx;
- u32 ignored;
- if (boot_cpu_has(X86_FEATURE_TOPOEXT) || boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
- cpuid_count(0x8000001d, index, &eax.full, &ebx.full, &ecx.full, &ignored);
- else
+ if (boot_cpu_has(X86_FEATURE_TOPOEXT) || boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
+ const struct cpuid_regs *regs = cpudata_cpuid_index_regs(c, 0x8000001d, index);
+
+ eax.full = regs->eax;
+ ebx.full = regs->ebx;
+ ecx.full = regs->ecx;
+ } else
legacy_amd_cpuid4(index, &eax, &ebx, &ecx);
return cpuid4_info_fill_done(id4, eax, ebx, ecx);
@@ -267,25 +270,10 @@ static int fill_cpuid4_info(struct cpuinfo_x86 *c, int index, struct _cpuid4_inf
u8 cpu_vendor = boot_cpu_data.x86_vendor;
return (cpu_vendor == X86_VENDOR_AMD || cpu_vendor == X86_VENDOR_HYGON) ?
- amd_fill_cpuid4_info(index, id4) :
+ amd_fill_cpuid4_info(c, index, id4) :
intel_fill_cpuid4_info(c, index, id4);
}
-static int amd_find_num_cache_leaves(struct cpuinfo_x86 *c)
-{
- unsigned int eax, ebx, ecx, edx;
- union _cpuid4_leaf_eax cache_eax;
- int i = -1;
-
- /* Do a CPUID(0x8000001d) loop to calculate num_cache_leaves */
- do {
- ++i;
- cpuid_count(0x8000001d, i, &eax, &ebx, &ecx, &edx);
- cache_eax.full = eax;
- } while (cache_eax.split.type != CTYPE_NULL);
- return i;
-}
-
/*
* AMD/Hygon CPUs may have multiple LLCs if L3 caches exist.
*/
@@ -309,15 +297,12 @@ void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, u16 die_id)
* Newer families: LLC ID is calculated from the number
* of threads sharing the L3 cache.
*/
- u32 eax, ebx, ecx, edx, num_sharing_cache = 0;
- u32 llc_index = amd_find_num_cache_leaves(c) - 1;
-
- cpuid_count(0x8000001d, llc_index, &eax, &ebx, &ecx, &edx);
- if (eax)
- num_sharing_cache = ((eax >> 14) & 0xfff) + 1;
+ u32 llc_index = cpudata_cpuid_nr_entries(c, 0x8000001d) - 1;
+ const struct leaf_0x8000001d_0 *leaf =
+ cpudata_cpuid_index(c, 0x8000001d, llc_index);
- if (num_sharing_cache) {
- int index_msb = get_count_order(num_sharing_cache);
+ if (leaf) {
+ int index_msb = get_count_order(leaf->num_threads_sharing + 1);
c->topo.llc_id = c->topo.apicid >> index_msb;
}
@@ -341,7 +326,7 @@ 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 = amd_find_num_cache_leaves(c);
+ ci->num_leaves = cpudata_cpuid_nr_entries(c, 0x8000001d);
else if (c->extended_cpuid_level >= 0x80000006)
ci->num_leaves = (cpuid_edx(0x80000006) & 0xf000) ? 4 : 3;
}
@@ -350,7 +335,7 @@ void init_hygon_cacheinfo(struct cpuinfo_x86 *c)
{
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
- ci->num_leaves = amd_find_num_cache_leaves(c);
+ ci->num_leaves = cpudata_cpuid_nr_entries(c, 0x8000001d);
}
static void intel_cacheinfo_done(struct cpuinfo_x86 *c, unsigned int l3,
--
2.49.0
Powered by blists - more mailing lists