All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Cameron <jonathan.cameron@huawei.com>
To: Ryan Roberts <ryan.roberts@arm.com>
Cc: Will Deacon <will@kernel.org>, Ard Biesheuvel <ardb@kernel.org>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Mark Rutland <mark.rutland@arm.com>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Oliver Upton <oliver.upton@linux.dev>,
	Marc Zyngier <maz@kernel.org>, "Dev Jain" <dev.jain@arm.com>,
	Linu Cherian <Linu.Cherian@arm.com>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 11/13] arm64: mm: More flags for __flush_tlb_range()
Date: Tue, 27 Jan 2026 12:45:33 +0000	[thread overview]
Message-ID: <20260127124533.0000302e@huawei.com> (raw)
In-Reply-To: <20260119172202.1681510-12-ryan.roberts@arm.com>

On Mon, 19 Jan 2026 17:21:58 +0000
Ryan Roberts <ryan.roberts@arm.com> wrote:

> Refactor function variants with "_nosync", "_local" and "_nonotify" into
> a single __always_inline implementation that takes flags and rely on
> constant folding to select the parts that are actually needed at any
> given callsite, based on the provided flags.
> 
> Flags all live in the tlbf_t (TLB flags) type; TLBF_NONE (0) continues
> to provide the strongest semantics (i.e. evict from walk cache,
> broadcast, synchronise and notify). Each flag reduces the strength in
> some way; TLBF_NONOTIFY, TLBF_NOSYNC and TLBF_NOBROADCAST are added to
> complement the existing TLBF_NOWALKCACHE.

Unless I'm missing something the case of TLBF_NOBROADCAST but not
TLBF_NOWALKCACHE isn't currently used.
  
I wonder if bringing that in with a user will make it easier to see what
is going on.

Otherwise, 3 vs 2 underscores? Can we come up with something easier
to read than that?

> 
> The result is a clearer, simpler, more powerful API.
> 
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>  arch/arm64/include/asm/tlbflush.h | 107 +++++++++++++++++++-----------
>  arch/arm64/mm/contpte.c           |   9 ++-
>  2 files changed, 74 insertions(+), 42 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
> index 1ad1c864e1f8..f03831cd8719 100644
> --- a/arch/arm64/include/asm/tlbflush.h
> +++ b/arch/arm64/include/asm/tlbflush.h
> @@ -107,6 +107,12 @@ static inline unsigned long get_trans_granule(void)
>  
>  typedef void (*tlbi_op)(u64 arg);
>  
> +static __always_inline void vae1(u64 arg)
> +{
> +	__tlbi(vae1, arg);
> +	__tlbi_user(vae1, arg);
> +}
> +
>  static __always_inline void vae1is(u64 arg)
>  {
>  	__tlbi(vae1is, arg);
> @@ -275,7 +281,10 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
>   *		no invalidation may take place. In the case where the level
>   *		cannot be easily determined, the value TLBI_TTL_UNKNOWN will
>   *		perform a non-hinted invalidation. flags may be TLBF_NONE (0) or
> - *		TLBF_NOWALKCACHE (elide eviction of walk cache entries).
> + *		any combination of TLBF_NOWALKCACHE (elide eviction of walk
> + *		cache entries), TLBF_NONOTIFY (don't call mmu notifiers),
> + *		TLBF_NOSYNC (don't issue trailing dsb) and TLBF_NOBROADCAST
> + *		(only perform the invalidation for the local cpu).
>   *
>   *	local_flush_tlb_page(vma, addr)
>   *		Local variant of flush_tlb_page().  Stale TLB entries may
> @@ -285,12 +294,6 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
>   *		Same as local_flush_tlb_page() except MMU notifier will not be
>   *		called.
>   *
> - *	local_flush_tlb_contpte(vma, addr)
> - *		Invalidate the virtual-address range
> - *		'[addr, addr+CONT_PTE_SIZE)' mapped with contpte on local CPU
> - *		for the user address space corresponding to 'vma->mm'.  Stale
> - *		TLB entries may remain in remote CPUs.
> - *
>   *	Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented
>   *	on top of these routines, since that is our interface to the mmu_gather
>   *	API as used by munmap() and friends.
> @@ -435,6 +438,12 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
>   *    operations can only span an even number of pages. We save this for last to
>   *    ensure 64KB start alignment is maintained for the LPA2 case.
>   */
> +static __always_inline void rvae1(u64 arg)
> +{
> +	__tlbi(rvae1, arg);
> +	__tlbi_user(rvae1, arg);
> +}
> +
>  static __always_inline void rvae1is(u64 arg)
>  {
>  	__tlbi(rvae1is, arg);
> @@ -541,15 +550,23 @@ typedef unsigned __bitwise tlbf_t;
>  /* Invalidate tlb entries only, leaving the page table walk cache intact. */
>  #define TLBF_NOWALKCACHE	((__force tlbf_t)BIT(0))
>  
> -static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
> -				     unsigned long start, unsigned long end,
> -				     unsigned long stride, int tlb_level,
> -				     tlbf_t flags)
> +/* Skip the trailing dsb after issuing tlbi. */
> +#define TLBF_NOSYNC		((__force tlbf_t)BIT(1))
> +
> +/* Suppress tlb notifier callbacks for this flush operation. */
> +#define TLBF_NONOTIFY		((__force tlbf_t)BIT(2))
> +
> +/* Perform the tlbi locally without broadcasting to other CPUs. */
> +#define TLBF_NOBROADCAST	((__force tlbf_t)BIT(3))
> +
> +static __always_inline void ___flush_tlb_range(struct vm_area_struct *vma,

Can we come up with anything better for naming than more underscores?

My eyes skipped over there being 3 here rather than 2 and I got rather confused
as a result.  Maybe at least make it excessive and go from 2 to 4+?

> +					unsigned long start, unsigned long end,
> +					unsigned long stride, int tlb_level,
> +					tlbf_t flags)
>  {
> +	struct mm_struct *mm = vma->vm_mm;
>  	unsigned long asid, pages;
>  
> -	start = round_down(start, stride);
> -	end = round_up(end, stride);
>  	pages = (end - start) >> PAGE_SHIFT;
>  
>  	if (__flush_tlb_range_limit_excess(pages, stride)) {
> @@ -557,17 +574,41 @@ static inline void __flush_tlb_range_nosync(struct mm_struct *mm,
>  		return;
>  	}
>  
> -	dsb(ishst);
> +	if (!(flags & TLBF_NOBROADCAST))
> +		dsb(ishst);
> +	else
> +		dsb(nshst);
> +
>  	asid = ASID(mm);
>  
> -	if (flags & TLBF_NOWALKCACHE)
> -		__flush_s1_tlb_range_op(vale1is, start, pages, stride,
> -				     asid, tlb_level);
> -	else
> +	switch (flags & (TLBF_NOWALKCACHE | TLBF_NOBROADCAST)) {
> +	case TLBF_NONE:
>  		__flush_s1_tlb_range_op(vae1is, start, pages, stride,
> -				     asid, tlb_level);
> +					asid, tlb_level);
> +		break;
> +	case TLBF_NOWALKCACHE:
> +		__flush_s1_tlb_range_op(vale1is, start, pages, stride,
> +					asid, tlb_level);
> +		break;
> +	case TLBF_NOBROADCAST:
> +		__flush_s1_tlb_range_op(vae1, start, pages, stride,
> +					asid, tlb_level);
> +		break;
> +	case TLBF_NOWALKCACHE | TLBF_NOBROADCAST:
> +		__flush_s1_tlb_range_op(vale1, start, pages, stride,
> +					asid, tlb_level);
> +		break;
> +	}
> +
> +	if (!(flags & TLBF_NONOTIFY))
> +		mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, end);
>  
> -	mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, end);
> +	if (!(flags & TLBF_NOSYNC)) {
> +		if (!(flags & TLBF_NOBROADCAST))
> +			dsb(ish);
> +		else
> +			dsb(nsh);
> +	}
>  }
>  
>  static inline void __flush_tlb_range(struct vm_area_struct *vma,
> @@ -575,24 +616,9 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
>  				     unsigned long stride, int tlb_level,
>  				     tlbf_t flags)
>  {
> -	__flush_tlb_range_nosync(vma->vm_mm, start, end, stride,
> -				 tlb_level, flags);
> -	dsb(ish);
> -}
> -
> -static inline void local_flush_tlb_contpte(struct vm_area_struct *vma,
> -					   unsigned long addr)
> -{
> -	unsigned long asid;
> -
> -	addr = round_down(addr, CONT_PTE_SIZE);
> -
> -	dsb(nshst);
> -	asid = ASID(vma->vm_mm);
> -	__flush_s1_tlb_range_op(vale1, addr, CONT_PTES, PAGE_SIZE, asid, 3);
> -	mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, addr,
> -						    addr + CONT_PTE_SIZE);
> -	dsb(nsh);
> +	start = round_down(start, stride);
> +	end = round_up(end, stride);
> +	___flush_tlb_range(vma, start, end, stride, tlb_level, flags);
>  }
>  
>  static inline void flush_tlb_range(struct vm_area_struct *vma,
> @@ -645,7 +671,10 @@ static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
>  static inline void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch,
>  		struct mm_struct *mm, unsigned long start, unsigned long end)
>  {
> -	__flush_tlb_range_nosync(mm, start, end, PAGE_SIZE, 3, TLBF_NOWALKCACHE);
> +	struct vm_area_struct vma = { .vm_mm = mm, .vm_flags = 0 };
> +
> +	__flush_tlb_range(&vma, start, end, PAGE_SIZE, 3,
> +			  TLBF_NOWALKCACHE | TLBF_NOSYNC);
>  }
>  
>  static inline bool __pte_flags_need_flush(ptdesc_t oldval, ptdesc_t newval)
> diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
> index 1a12bb728ee1..ec17a0e70415 100644
> --- a/arch/arm64/mm/contpte.c
> +++ b/arch/arm64/mm/contpte.c
> @@ -527,8 +527,8 @@ int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
>  		 * eliding the trailing DSB applies here.
>  		 */
>  		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
> -		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
> -					 PAGE_SIZE, 3, TLBF_NOWALKCACHE);
> +		__flush_tlb_range(vma, addr, addr + CONT_PTE_SIZE,
> +				  PAGE_SIZE, 3, TLBF_NOWALKCACHE | TLBF_NOSYNC);
>  	}
>  
>  	return young;
> @@ -623,7 +623,10 @@ int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
>  			__ptep_set_access_flags(vma, addr, ptep, entry, 0);
>  
>  		if (dirty)
> -			local_flush_tlb_contpte(vma, start_addr);
> +			__flush_tlb_range(vma, start_addr,
> +					  start_addr + CONT_PTE_SIZE,
> +					  PAGE_SIZE, 3,
> +					  TLBF_NOWALKCACHE | TLBF_NOBROADCAST);
>  	} else {
>  		__contpte_try_unfold(vma->vm_mm, addr, ptep, orig_pte);
>  		__ptep_set_access_flags(vma, addr, ptep, entry, dirty);



  reply	other threads:[~2026-01-27 12:46 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-19 17:21 [PATCH v2 00/13] arm64: Refactor TLB invalidation API and implementation Ryan Roberts
2026-01-19 17:21 ` [PATCH v2 01/13] arm64: mm: Re-implement the __tlbi_level macro as a C function Ryan Roberts
2026-01-27 11:12   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 02/13] arm64: mm: Introduce a C wrapper for by-range TLB invalidation Ryan Roberts
2026-01-27 11:19   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 03/13] arm64: mm: Implicitly invalidate user ASID based on TLBI operation Ryan Roberts
2026-01-27 11:31   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 04/13] arm64: mm: Push __TLBI_VADDR() into __tlbi_level() Ryan Roberts
2026-01-27 11:37   ` Jonathan Cameron
2026-01-27 13:26     ` Ryan Roberts
2026-01-19 17:21 ` [PATCH v2 05/13] arm64: mm: Inline __TLBI_VADDR_RANGE() into __tlbi_range() Ryan Roberts
2026-01-27 11:46   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 06/13] arm64: mm: Re-implement the __flush_tlb_range_op macro in C Ryan Roberts
2026-01-27 12:06   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 07/13] arm64: mm: Simplify __TLBI_RANGE_NUM() macro Ryan Roberts
2026-01-27 12:09   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 08/13] arm64: mm: Simplify __flush_tlb_range_limit_excess() Ryan Roberts
2026-01-27 12:15   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 09/13] arm64: mm: Refactor flush_tlb_page() to use __tlbi_level_asid() Ryan Roberts
2026-01-27 12:25   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 10/13] arm64: mm: Refactor __flush_tlb_range() to take flags Ryan Roberts
2026-01-27 12:28   ` Jonathan Cameron
2026-01-19 17:21 ` [PATCH v2 11/13] arm64: mm: More flags for __flush_tlb_range() Ryan Roberts
2026-01-27 12:45   ` Jonathan Cameron [this message]
2026-01-27 13:50     ` Ryan Roberts
2026-01-27 14:11       ` Jonathan Cameron
2026-01-27 14:14         ` Jonathan Cameron
2026-01-27 14:47           ` Ryan Roberts
2026-01-19 17:21 ` [PATCH v2 12/13] arm64: mm: Wrap flush_tlb_page() around ___flush_tlb_range() Ryan Roberts
2026-01-27 12:59   ` Jonathan Cameron
2026-01-27 14:03     ` Ryan Roberts
2026-01-27 14:08       ` Jonathan Cameron
2026-01-19 17:22 ` [PATCH v2 13/13] arm64: mm: Provide level hint for flush_tlb_page() Ryan Roberts

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260127124533.0000302e@huawei.com \
    --to=jonathan.cameron@huawei.com \
    --cc=Linu.Cherian@arm.com \
    --cc=ardb@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=dev.jain@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=maz@kernel.org \
    --cc=oliver.upton@linux.dev \
    --cc=ryan.roberts@arm.com \
    --cc=torvalds@linux-foundation.org \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.