All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86/CPU/AMD: Fix Zen5 TLB sizes reporting
@ 2026-08-21  2:20 Borislav Petkov
  2026-08-21  4:51 ` Borislav Petkov
  0 siblings, 1 reply; 2+ messages in thread
From: Borislav Petkov @ 2026-08-21  2:20 UTC (permalink / raw)
  To: X86; +Cc: LKML, Borislav Petkov (AMD)

From: "Borislav Petkov (AMD)" <bp@alien8.de>

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@alien8.de>
---
 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 73d5c740202d..46937d15a95a 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -473,6 +473,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 54e14ed276b5..e5279bc648d3 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 c7352827f491..4fe158fb8e6e 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;
 
 	n = c->extended_cpuid_level;
 
@@ -875,9 +875,11 @@ void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
 
 	cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
 	l2size = ecx >> 16;
+	shift = !!cpu_has(c, X86_FEATURE_L2_TLB_SIZE_X32) * 5;
 
 #ifdef CONFIG_X86_64
 	c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
+	c->x86_tlbsize <<= shift;
 #else
 	/* do processor-specific cache resizing */
 	if (this_cpu->legacy_cache_size)
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] x86/CPU/AMD: Fix Zen5 TLB sizes reporting
  2026-08-21  2:20 [PATCH] x86/CPU/AMD: Fix Zen5 TLB sizes reporting Borislav Petkov
@ 2026-08-21  4:51 ` Borislav Petkov
  0 siblings, 0 replies; 2+ messages in thread
From: Borislav Petkov @ 2026-08-21  4:51 UTC (permalink / raw)
  To: Borislav Petkov; +Cc: X86, LKML

On Thu, Aug 20, 2026 at 07:20:31PM -0700, Borislav Petkov wrote:
>  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;

Sashiko says:

| Could this shift operation overflow the target variables?
| The variables tlb_lld_4k and tlb_lli_4k are defined globally as u16.
| The architectural maximum raw value for the CPUID mask is 4095. When
| shifted by 5 for the new X32 encoding, this yields up to 131040, which
| exceeds the 65535 maximum capacity of a u16 variable.
| While current Zen 5 CPUs might report smaller values that fit safely,
| future CPUs returning larger raw values could be truncated.

I say, sure, let's get there first. More than 65K TLB entries - that would be
cheap TLB design when it comes to power... /eyeroll.

I'll gladly touch that bunch of u16s then.

> @@ -875,9 +875,11 @@ void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
>  
>  	cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
>  	l2size = ecx >> 16;
> +	shift = !!cpu_has(c, X86_FEATURE_L2_TLB_SIZE_X32) * 5;
>  
>  #ifdef CONFIG_X86_64
>  	c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
> +	c->x86_tlbsize <<= shift;
>  #else

Sashiko says:

| Will this trigger a compiler warning on 32-bit builds?
| The shift variable is assigned unconditionally here, but its only usage
| is bounded by the CONFIG_X86_64 block just below it. On targets
| where CONFIG_X86_64 is not set, shift is written to but never read.

Sure, fixed.

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-21  4:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21  2:20 [PATCH] x86/CPU/AMD: Fix Zen5 TLB sizes reporting Borislav Petkov
2026-08-21  4:51 ` Borislav Petkov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.