[tip: x86/cpu] x86/CPU/AMD: Fix Zen5 TLB sizes reporting

From: tip-bot2 for Borislav Petkov (AMD)

Date: Mon Sep 14 2026 - 23:21:21 EST


The following commit has been merged into the x86/cpu branch of tip:

Commit-ID: 228200f695c0f92c5fd06ff0bdcf94bb0d2ca7f5
Gitweb: https://git.kernel.org/tip/228200f695c0f92c5fd06ff0bdcf94bb0d2ca7f5
Author: Borislav Petkov (AMD) <bp@xxxxxxxxx>
AuthorDate: Thu, 20 Aug 2026 17:02:10 -07:00
Committer: Borislav Petkov (AMD) <bp@xxxxxxxxx>
CommitterDate: Mon, 14 Sep 2026 19:10:24 -07:00

x86/CPU/AMD: Fix Zen5 TLB sizes reporting

Starting with Zen5, TLB sizes in CPUID_Fn80000006_E[AB]X are reported
as multiples of 32. There's a CPUID bit which determines that:

CPUID_Fn80000021_EAX [Extended Feature 2 EAX] (Core::X86::Cpuid::FeatureExt2Eax)
...

14: L2TlbSizeX32. Read-only. Reset: 1. Indicates that L2TLB sizes are encoded as multiples of 32.

Update the places which report that information.

With it, the numbers look correct now:

-Last level iTLB entries: 4KB 64, 2MB 64, 4MB 32
-Last level dTLB entries: 4KB 128, 2MB 128, 4MB 64, 1GB 0
+Last level iTLB entries: 4KB 2048, 2MB 2048, 4MB 1024
+Last level dTLB entries: 4KB 4096, 2MB 4096, 4MB 2048, 1GB 0

/proc/cpuinfo

-TLB size : 192 4K pages
+TLB size : 6144 4K pages

Signed-off-by: Borislav Petkov (AMD) <bp@xxxxxxxxx>
Link: https://lore.kernel.org/r/20260821022031.946311-1-bp@xxxxxxxxxx
---
arch/x86/include/asm/cpufeatures.h | 2 ++
arch/x86/kernel/cpu/amd.c | 21 +++++++++++++--------
arch/x86/kernel/cpu/common.c | 4 +++-
3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index f70ee74..a7689e6 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -483,6 +483,8 @@
#define X86_FEATURE_AUTOIBRS (20*32+ 8) /* Automatic IBRS */
#define X86_FEATURE_NO_SMM_CTL_MSR (20*32+ 9) /* SMM_CTL MSR is not present */

+#define X86_FEATURE_L2_TLB_SIZE_X32 (20*32+14) /* L2 TLB sizes are encoded as multiples of 32 */
+
#define X86_FEATURE_GP_ON_USER_CPUID (20*32+17) /* User CPUID faulting */

#define X86_FEATURE_PREFETCHI (20*32+20) /* Prefetch Data/Instruction to Cache Level */
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 54e14ed..e5279bc 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -1192,7 +1192,7 @@ static unsigned int amd_size_cache(struct cpuinfo_x86 *c, unsigned int size)

static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
{
- u32 ebx, eax, ecx, edx;
+ u32 ebx, eax, ecx, edx, shift, tmp;
u16 mask = 0xfff;

if (c->x86 < 0xf)
@@ -1201,10 +1201,12 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
if (c->extended_cpuid_level < 0x80000006)
return;

+ shift = !!cpu_has(c, X86_FEATURE_L2_TLB_SIZE_X32) * 5;
+
cpuid(0x80000006, &eax, &ebx, &ecx, &edx);

- tlb_lld_4k = (ebx >> 16) & mask;
- tlb_lli_4k = ebx & mask;
+ tlb_lld_4k = ((ebx >> 16) & mask) << shift;
+ tlb_lli_4k = (ebx & mask) << shift;

/*
* K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB
@@ -1216,16 +1218,18 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
}

/* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
- if (!((eax >> 16) & mask))
+ tmp = ((eax >> 16) & mask) << shift;
+ if (!tmp)
tlb_lld_2m = (cpuid_eax(0x80000005) >> 16) & 0xff;
else
- tlb_lld_2m = (eax >> 16) & mask;
+ tlb_lld_2m = tmp;

/* a 4M entry uses two 2M entries */
tlb_lld_4m = tlb_lld_2m >> 1;

/* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
- if (!(eax & mask)) {
+ tmp = (eax & mask) << shift;
+ if (!tmp) {
/* Erratum 658 */
if (c->x86 == 0x15 && c->x86_model <= 0x1f) {
tlb_lli_2m = 1024;
@@ -1233,8 +1237,9 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
tlb_lli_2m = eax & 0xff;
}
- } else
- tlb_lli_2m = eax & mask;
+ } else {
+ tlb_lli_2m = tmp;
+ }

tlb_lli_4m = tlb_lli_2m >> 1;

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index c735282..3716a6a 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -857,7 +857,7 @@ static void get_model_name(struct cpuinfo_x86 *c)

void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
{
- unsigned int n, dummy, ebx, ecx, edx, l2size;
+ unsigned int n, dummy, ebx, ecx, edx, l2size, shift __maybe_unused;

n = c->extended_cpuid_level;

@@ -877,7 +877,9 @@ void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
l2size = ecx >> 16;

#ifdef CONFIG_X86_64
+ shift = !!cpu_has(c, X86_FEATURE_L2_TLB_SIZE_X32) * 5;
c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
+ c->x86_tlbsize <<= shift;
#else
/* do processor-specific cache resizing */
if (this_cpu->legacy_cache_size)