Message ID | 20250112155453.1104139-5-riel@surriel.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | AMD broadcast TLB invalidation | expand |
On Sun, Jan 12, 2025 at 4:55 PM Rik van Riel <riel@surriel.com> wrote: > + /* Max number of pages INVLPGB can invalidate in one shot */ > + if (boot_cpu_has(X86_FEATURE_INVLPGB)) { > + cpuid(0x80000008, &eax, &ebx, &ecx, &edx); > + invlpgb_count_max = (edx & 0xffff) + 1; I assume the +1 is just a weird undocumented (or weirdly documented) encoding? https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24594.pdf says that field InvlpgbCountMax contains the "Maximum page count for INVLPGB instruction" and doesn't mention having to add 1 from what I can tell.
On Mon, 2025-01-13 at 16:50 +0100, Jann Horn wrote: > On Sun, Jan 12, 2025 at 4:55 PM Rik van Riel <riel@surriel.com> > wrote: > > + /* Max number of pages INVLPGB can invalidate in one shot > > */ > > + if (boot_cpu_has(X86_FEATURE_INVLPGB)) { > > + cpuid(0x80000008, &eax, &ebx, &ecx, &edx); > > + invlpgb_count_max = (edx & 0xffff) + 1; > > I assume the +1 is just a weird undocumented (or weirdly documented) > encoding? > https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24594.pdf > says that field InvlpgbCountMax contains the "Maximum page count for > INVLPGB instruction" and doesn't mention having to add 1 from what I > can tell. > The way I read the documentation, the number passed in to invlpgb (and retrieved from cpuid) corresponds to the number of extra pages invalidated beyond the first page at the specified address. Things have not exploded on me invalidating multiple pages at once in larger ranges, so I suspect my reading is right, but it would be nice for one of the AMD people to confirm :)
On 1/13/25 15:08, Rik van Riel wrote: > On Mon, 2025-01-13 at 16:50 +0100, Jann Horn wrote: >> On Sun, Jan 12, 2025 at 4:55 PM Rik van Riel <riel@surriel.com> >> wrote: >>> + /* Max number of pages INVLPGB can invalidate in one shot >>> */ >>> + if (boot_cpu_has(X86_FEATURE_INVLPGB)) { >>> + cpuid(0x80000008, &eax, &ebx, &ecx, &edx); >>> + invlpgb_count_max = (edx & 0xffff) + 1; >> >> I assume the +1 is just a weird undocumented (or weirdly documented) >> encoding? >> https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24594.pdf >> says that field InvlpgbCountMax contains the "Maximum page count for >> INVLPGB instruction" and doesn't mention having to add 1 from what I >> can tell. >> > The way I read the documentation, the number > passed in to invlpgb (and retrieved from cpuid) > corresponds to the number of extra pages > invalidated beyond the first page at the specified > address. > > Things have not exploded on me invalidating > multiple pages at once in larger ranges, so I > suspect my reading is right, but it would be > nice for one of the AMD people to confirm :) That is correct. Thanks, Tom >
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 2a7279d80460..bacdc502903f 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -395,6 +395,10 @@ config X86_VMX_FEATURE_NAMES def_bool y depends on IA32_FEAT_CTL +config X86_BROADCAST_TLB_FLUSH + def_bool y + depends on CPU_SUP_AMD + menuconfig PROCESSOR_SELECT bool "Supported processor vendors" if EXPERT help @@ -431,6 +435,7 @@ config CPU_SUP_CYRIX_32 config CPU_SUP_AMD default y bool "Support AMD processors" if PROCESSOR_SELECT + select X86_BROADCAST_TLB_FLUSH help This enables detection, tunings and quirks for AMD processors diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 17b6590748c0..f9b832e971c5 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -338,6 +338,7 @@ #define X86_FEATURE_CLZERO (13*32+ 0) /* "clzero" CLZERO instruction */ #define X86_FEATURE_IRPERF (13*32+ 1) /* "irperf" Instructions Retired Count */ #define X86_FEATURE_XSAVEERPTR (13*32+ 2) /* "xsaveerptr" Always save/restore FP error pointers */ +#define X86_FEATURE_INVLPGB (13*32+ 3) /* INVLPGB and TLBSYNC instruction supported. */ #define X86_FEATURE_RDPRU (13*32+ 4) /* "rdpru" Read processor register at user level */ #define X86_FEATURE_WBNOINVD (13*32+ 9) /* "wbnoinvd" WBNOINVD instruction */ #define X86_FEATURE_AMD_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */ diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 02fc2aa06e9e..8fe3b2dda507 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -183,6 +183,13 @@ static inline void cr4_init_shadow(void) extern unsigned long mmu_cr4_features; extern u32 *trampoline_cr4_features; +/* How many pages can we invalidate with one INVLPGB. */ +#ifdef CONFIG_X86_BROADCAST_TLB_FLUSH +extern u16 invlpgb_count_max; +#else +#define invlpgb_count_max 1 +#endif + extern void initialize_tlbstate_and_flush(void); /* diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 79d2e17f6582..bcf73775b4f8 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -29,6 +29,8 @@ #include "cpu.h" +u16 invlpgb_count_max __ro_after_init; + static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) { u32 gprs[8] = { 0 }; @@ -1135,6 +1137,12 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) tlb_lli_2m[ENTRIES] = eax & mask; tlb_lli_4m[ENTRIES] = tlb_lli_2m[ENTRIES] >> 1; + + /* Max number of pages INVLPGB can invalidate in one shot */ + if (boot_cpu_has(X86_FEATURE_INVLPGB)) { + cpuid(0x80000008, &eax, &ebx, &ecx, &edx); + invlpgb_count_max = (edx & 0xffff) + 1; + } } static const struct cpu_dev amd_cpu_dev = {
The CPU advertises the maximum number of pages that can be shot down with one INVLPGB instruction in the CPUID data. Save that information for later use. Signed-off-by: Rik van Riel <riel@surriel.com> --- arch/x86/Kconfig.cpu | 5 +++++ arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/tlbflush.h | 7 +++++++ arch/x86/kernel/cpu/amd.c | 8 ++++++++ 4 files changed, 21 insertions(+)