[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <685632f2-44a4-a7fd-063b-1d426896f297@amd.com>
Date: Mon, 13 Jan 2025 08:21:47 -0600
From: Tom Lendacky <thomas.lendacky@....com>
To: Rik van Riel <riel@...riel.com>, x86@...nel.org
Cc: linux-kernel@...r.kernel.org, bp@...en8.de, peterz@...radead.org,
dave.hansen@...ux.intel.com, zhengqi.arch@...edance.com,
nadav.amit@...il.com, kernel-team@...a.com, linux-mm@...ck.org,
akpm@...ux-foundation.org, jannh@...gle.com
Subject: Re: [PATCH v4 05/12] x86/mm: add INVLPGB support code
On 1/12/25 09:53, Rik van Riel wrote:
> Add invlpgb.h with the helper functions and definitions needed to use
> broadcast TLB invalidation on AMD EPYC 3 and newer CPUs.
>
> Signed-off-by: Rik van Riel <riel@...riel.com>
> ---
> arch/x86/include/asm/invlpgb.h | 95 +++++++++++++++++++++++++++++++++
> arch/x86/include/asm/tlbflush.h | 1 +
> 2 files changed, 96 insertions(+)
> create mode 100644 arch/x86/include/asm/invlpgb.h
>
> diff --git a/arch/x86/include/asm/invlpgb.h b/arch/x86/include/asm/invlpgb.h
> new file mode 100644
> index 000000000000..d62e3733a1ab
> --- /dev/null
> +++ b/arch/x86/include/asm/invlpgb.h
> @@ -0,0 +1,95 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_X86_INVLPGB
> +#define _ASM_X86_INVLPGB
> +
> +#include <vdso/bits.h>
> +
> +/*
> + * INVLPGB does broadcast TLB invalidation across all the CPUs in the system.
> + *
> + * The INVLPGB instruction is weakly ordered, and a batch of invalidations can
> + * be done in a parallel fashion.
> + *
> + * TLBSYNC is used to ensure that pending INVLPGB invalidations initiated from
> + * this CPU have completed.
> + */
> +static inline void __invlpgb(unsigned long asid, unsigned long pcid, unsigned long addr,
> + int extra_count, bool pmd_stride, unsigned long flags)
> +{
> + u32 edx = (pcid << 16) | asid;
> + u32 ecx = (pmd_stride << 31);
> + u64 rax = addr | flags;
> +
> + /* Protect against negative numbers. */
> + extra_count = max(extra_count, 0);
> + ecx |= extra_count;
A bad ECX value (ECX[15:0] > invlpgb_count_max) will result in a #GP, is
that ok?
Thanks,
Tom
> +
> + asm volatile("invlpgb" : : "a" (rax), "c" (ecx), "d" (edx));
> +}
> +
> +/* Wait for INVLPGB originated by this CPU to complete. */
> +static inline void tlbsync(void)
> +{
> + asm volatile("tlbsync");
> +}
> +
> +/*
> + * INVLPGB can be targeted by virtual address, PCID, ASID, or any combination
> + * of the three. For example:
> + * - INVLPGB_VA | INVLPGB_INCLUDE_GLOBAL: invalidate all TLB entries at the address
> + * - INVLPGB_PCID: invalidate all TLB entries matching the PCID
> + *
> + * The first can be used to invalidate (kernel) mappings at a particular
> + * address across all processes.
> + *
> + * The latter invalidates all TLB entries matching a PCID.
> + */
> +#define INVLPGB_VA BIT(0)
> +#define INVLPGB_PCID BIT(1)
> +#define INVLPGB_ASID BIT(2)
> +#define INVLPGB_INCLUDE_GLOBAL BIT(3)
> +#define INVLPGB_FINAL_ONLY BIT(4)
> +#define INVLPGB_INCLUDE_NESTED BIT(5)
> +
> +/* Flush all mappings for a given pcid and addr, not including globals. */
> +static inline void invlpgb_flush_user(unsigned long pcid,
> + unsigned long addr)
> +{
> + __invlpgb(0, pcid, addr, 0, 0, INVLPGB_PCID | INVLPGB_VA);
> + tlbsync();
> +}
> +
> +static inline void invlpgb_flush_user_nr_nosync(unsigned long pcid,
> + unsigned long addr,
> + int nr, bool pmd_stride)
> +{
> + __invlpgb(0, pcid, addr, nr - 1, pmd_stride, INVLPGB_PCID | INVLPGB_VA);
> +}
> +
> +/* Flush all mappings for a given PCID, not including globals. */
> +static inline void invlpgb_flush_single_pcid_nosync(unsigned long pcid)
> +{
> + __invlpgb(0, pcid, 0, 0, 0, INVLPGB_PCID);
> +}
> +
> +/* Flush all mappings, including globals, for all PCIDs. */
> +static inline void invlpgb_flush_all(void)
> +{
> + __invlpgb(0, 0, 0, 0, 0, INVLPGB_INCLUDE_GLOBAL);
> + tlbsync();
> +}
> +
> +/* Flush addr, including globals, for all PCIDs. */
> +static inline void invlpgb_flush_addr_nosync(unsigned long addr, int nr)
> +{
> + __invlpgb(0, 0, addr, nr - 1, 0, INVLPGB_INCLUDE_GLOBAL);
> +}
> +
> +/* Flush all mappings for all PCIDs except globals. */
> +static inline void invlpgb_flush_all_nonglobals(void)
> +{
> + __invlpgb(0, 0, 0, 0, 0, 0);
> + tlbsync();
> +}
> +
> +#endif /* _ASM_X86_INVLPGB */
> diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
> index 8fe3b2dda507..dba5caa4a9f4 100644
> --- a/arch/x86/include/asm/tlbflush.h
> +++ b/arch/x86/include/asm/tlbflush.h
> @@ -10,6 +10,7 @@
> #include <asm/cpufeature.h>
> #include <asm/special_insns.h>
> #include <asm/smp.h>
> +#include <asm/invlpgb.h>
> #include <asm/invpcid.h>
> #include <asm/pti.h>
> #include <asm/processor-flags.h>
Powered by blists - more mailing lists