18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Based on arch/arm/include/asm/tlbflush.h
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1999-2003 Russell King
68c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#ifndef __ASM_TLBFLUSH_H
98c2ecf20Sopenharmony_ci#define __ASM_TLBFLUSH_H
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
148c2ecf20Sopenharmony_ci#include <linux/mm_types.h>
158c2ecf20Sopenharmony_ci#include <linux/sched.h>
168c2ecf20Sopenharmony_ci#include <asm/cputype.h>
178c2ecf20Sopenharmony_ci#include <asm/mmu.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Raw TLBI operations.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * Where necessary, use the __tlbi() macro to avoid asm()
238c2ecf20Sopenharmony_ci * boilerplate. Drivers and most kernel code should use the TLB
248c2ecf20Sopenharmony_ci * management routines in preference to the macro below.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * The macro can be used as __tlbi(op) or __tlbi(op, arg), depending
278c2ecf20Sopenharmony_ci * on whether a particular TLBI operation takes an argument or
288c2ecf20Sopenharmony_ci * not. The macros handles invoking the asm with or without the
298c2ecf20Sopenharmony_ci * register argument as appropriate.
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci#define __TLBI_0(op, arg) asm (ARM64_ASM_PREAMBLE			       \
328c2ecf20Sopenharmony_ci			       "tlbi " #op "\n"				       \
338c2ecf20Sopenharmony_ci		   ALTERNATIVE("nop\n			nop",		       \
348c2ecf20Sopenharmony_ci			       "dsb ish\n		tlbi " #op,	       \
358c2ecf20Sopenharmony_ci			       ARM64_WORKAROUND_REPEAT_TLBI,		       \
368c2ecf20Sopenharmony_ci			       CONFIG_ARM64_WORKAROUND_REPEAT_TLBI)	       \
378c2ecf20Sopenharmony_ci			    : : )
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define __TLBI_1(op, arg) asm (ARM64_ASM_PREAMBLE			       \
408c2ecf20Sopenharmony_ci			       "tlbi " #op ", %0\n"			       \
418c2ecf20Sopenharmony_ci		   ALTERNATIVE("nop\n			nop",		       \
428c2ecf20Sopenharmony_ci			       "dsb ish\n		tlbi " #op ", %0",     \
438c2ecf20Sopenharmony_ci			       ARM64_WORKAROUND_REPEAT_TLBI,		       \
448c2ecf20Sopenharmony_ci			       CONFIG_ARM64_WORKAROUND_REPEAT_TLBI)	       \
458c2ecf20Sopenharmony_ci			    : : "r" (arg))
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define __TLBI_N(op, arg, n, ...) __TLBI_##n(op, arg)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define __tlbi(op, ...)		__TLBI_N(op, ##__VA_ARGS__, 1, 0)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define __tlbi_user(op, arg) do {						\
528c2ecf20Sopenharmony_ci	if (arm64_kernel_unmapped_at_el0())					\
538c2ecf20Sopenharmony_ci		__tlbi(op, (arg) | USER_ASID_FLAG);				\
548c2ecf20Sopenharmony_ci} while (0)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/* This macro creates a properly formatted VA operand for the TLBI */
578c2ecf20Sopenharmony_ci#define __TLBI_VADDR(addr, asid)				\
588c2ecf20Sopenharmony_ci	({							\
598c2ecf20Sopenharmony_ci		unsigned long __ta = (addr) >> 12;		\
608c2ecf20Sopenharmony_ci		__ta &= GENMASK_ULL(43, 0);			\
618c2ecf20Sopenharmony_ci		__ta |= (unsigned long)(asid) << 48;		\
628c2ecf20Sopenharmony_ci		__ta;						\
638c2ecf20Sopenharmony_ci	})
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/*
668c2ecf20Sopenharmony_ci * Get translation granule of the system, which is decided by
678c2ecf20Sopenharmony_ci * PAGE_SIZE.  Used by TTL.
688c2ecf20Sopenharmony_ci *  - 4KB	: 1
698c2ecf20Sopenharmony_ci *  - 16KB	: 2
708c2ecf20Sopenharmony_ci *  - 64KB	: 3
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_ci#define TLBI_TTL_TG_4K		1
738c2ecf20Sopenharmony_ci#define TLBI_TTL_TG_16K		2
748c2ecf20Sopenharmony_ci#define TLBI_TTL_TG_64K		3
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic inline unsigned long get_trans_granule(void)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	switch (PAGE_SIZE) {
798c2ecf20Sopenharmony_ci	case SZ_4K:
808c2ecf20Sopenharmony_ci		return TLBI_TTL_TG_4K;
818c2ecf20Sopenharmony_ci	case SZ_16K:
828c2ecf20Sopenharmony_ci		return TLBI_TTL_TG_16K;
838c2ecf20Sopenharmony_ci	case SZ_64K:
848c2ecf20Sopenharmony_ci		return TLBI_TTL_TG_64K;
858c2ecf20Sopenharmony_ci	default:
868c2ecf20Sopenharmony_ci		return 0;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/*
918c2ecf20Sopenharmony_ci * Level-based TLBI operations.
928c2ecf20Sopenharmony_ci *
938c2ecf20Sopenharmony_ci * When ARMv8.4-TTL exists, TLBI operations take an additional hint for
948c2ecf20Sopenharmony_ci * the level at which the invalidation must take place. If the level is
958c2ecf20Sopenharmony_ci * wrong, no invalidation may take place. In the case where the level
968c2ecf20Sopenharmony_ci * cannot be easily determined, a 0 value for the level parameter will
978c2ecf20Sopenharmony_ci * perform a non-hinted invalidation.
988c2ecf20Sopenharmony_ci *
998c2ecf20Sopenharmony_ci * For Stage-2 invalidation, use the level values provided to that effect
1008c2ecf20Sopenharmony_ci * in asm/stage2_pgtable.h.
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_ci#define TLBI_TTL_MASK		GENMASK_ULL(47, 44)
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define __tlbi_level(op, addr, level) do {				\
1058c2ecf20Sopenharmony_ci	u64 arg = addr;							\
1068c2ecf20Sopenharmony_ci									\
1078c2ecf20Sopenharmony_ci	if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL) &&		\
1088c2ecf20Sopenharmony_ci	    level) {							\
1098c2ecf20Sopenharmony_ci		u64 ttl = level & 3;					\
1108c2ecf20Sopenharmony_ci		ttl |= get_trans_granule() << 2;			\
1118c2ecf20Sopenharmony_ci		arg &= ~TLBI_TTL_MASK;					\
1128c2ecf20Sopenharmony_ci		arg |= FIELD_PREP(TLBI_TTL_MASK, ttl);			\
1138c2ecf20Sopenharmony_ci	}								\
1148c2ecf20Sopenharmony_ci									\
1158c2ecf20Sopenharmony_ci	__tlbi(op, arg);						\
1168c2ecf20Sopenharmony_ci} while(0)
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define __tlbi_user_level(op, arg, level) do {				\
1198c2ecf20Sopenharmony_ci	if (arm64_kernel_unmapped_at_el0())				\
1208c2ecf20Sopenharmony_ci		__tlbi_level(op, (arg | USER_ASID_FLAG), level);	\
1218c2ecf20Sopenharmony_ci} while (0)
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/*
1248c2ecf20Sopenharmony_ci * This macro creates a properly formatted VA operand for the TLB RANGE.
1258c2ecf20Sopenharmony_ci * The value bit assignments are:
1268c2ecf20Sopenharmony_ci *
1278c2ecf20Sopenharmony_ci * +----------+------+-------+-------+-------+----------------------+
1288c2ecf20Sopenharmony_ci * |   ASID   |  TG  | SCALE |  NUM  |  TTL  |        BADDR         |
1298c2ecf20Sopenharmony_ci * +-----------------+-------+-------+-------+----------------------+
1308c2ecf20Sopenharmony_ci * |63      48|47  46|45   44|43   39|38   37|36                   0|
1318c2ecf20Sopenharmony_ci *
1328c2ecf20Sopenharmony_ci * The address range is determined by below formula:
1338c2ecf20Sopenharmony_ci * [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE)
1348c2ecf20Sopenharmony_ci *
1358c2ecf20Sopenharmony_ci */
1368c2ecf20Sopenharmony_ci#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl)		\
1378c2ecf20Sopenharmony_ci	({							\
1388c2ecf20Sopenharmony_ci		unsigned long __ta = (addr) >> PAGE_SHIFT;	\
1398c2ecf20Sopenharmony_ci		__ta &= GENMASK_ULL(36, 0);			\
1408c2ecf20Sopenharmony_ci		__ta |= (unsigned long)(ttl) << 37;		\
1418c2ecf20Sopenharmony_ci		__ta |= (unsigned long)(num) << 39;		\
1428c2ecf20Sopenharmony_ci		__ta |= (unsigned long)(scale) << 44;		\
1438c2ecf20Sopenharmony_ci		__ta |= get_trans_granule() << 46;		\
1448c2ecf20Sopenharmony_ci		__ta |= (unsigned long)(asid) << 48;		\
1458c2ecf20Sopenharmony_ci		__ta;						\
1468c2ecf20Sopenharmony_ci	})
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/* These macros are used by the TLBI RANGE feature. */
1498c2ecf20Sopenharmony_ci#define __TLBI_RANGE_PAGES(num, scale)	\
1508c2ecf20Sopenharmony_ci	((unsigned long)((num) + 1) << (5 * (scale) + 1))
1518c2ecf20Sopenharmony_ci#define MAX_TLBI_RANGE_PAGES		__TLBI_RANGE_PAGES(31, 3)
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci * Generate 'num' values from -1 to 30 with -1 rejected by the
1558c2ecf20Sopenharmony_ci * __flush_tlb_range() loop below.
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_ci#define TLBI_RANGE_MASK			GENMASK_ULL(4, 0)
1588c2ecf20Sopenharmony_ci#define __TLBI_RANGE_NUM(pages, scale)	\
1598c2ecf20Sopenharmony_ci	((((pages) >> (5 * (scale) + 1)) & TLBI_RANGE_MASK) - 1)
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/*
1628c2ecf20Sopenharmony_ci *	TLB Invalidation
1638c2ecf20Sopenharmony_ci *	================
1648c2ecf20Sopenharmony_ci *
1658c2ecf20Sopenharmony_ci * 	This header file implements the low-level TLB invalidation routines
1668c2ecf20Sopenharmony_ci *	(sometimes referred to as "flushing" in the kernel) for arm64.
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci *	Every invalidation operation uses the following template:
1698c2ecf20Sopenharmony_ci *
1708c2ecf20Sopenharmony_ci *	DSB ISHST	// Ensure prior page-table updates have completed
1718c2ecf20Sopenharmony_ci *	TLBI ...	// Invalidate the TLB
1728c2ecf20Sopenharmony_ci *	DSB ISH		// Ensure the TLB invalidation has completed
1738c2ecf20Sopenharmony_ci *      if (invalidated kernel mappings)
1748c2ecf20Sopenharmony_ci *		ISB	// Discard any instructions fetched from the old mapping
1758c2ecf20Sopenharmony_ci *
1768c2ecf20Sopenharmony_ci *
1778c2ecf20Sopenharmony_ci *	The following functions form part of the "core" TLB invalidation API,
1788c2ecf20Sopenharmony_ci *	as documented in Documentation/core-api/cachetlb.rst:
1798c2ecf20Sopenharmony_ci *
1808c2ecf20Sopenharmony_ci *	flush_tlb_all()
1818c2ecf20Sopenharmony_ci *		Invalidate the entire TLB (kernel + user) on all CPUs
1828c2ecf20Sopenharmony_ci *
1838c2ecf20Sopenharmony_ci *	flush_tlb_mm(mm)
1848c2ecf20Sopenharmony_ci *		Invalidate an entire user address space on all CPUs.
1858c2ecf20Sopenharmony_ci *		The 'mm' argument identifies the ASID to invalidate.
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci *	flush_tlb_range(vma, start, end)
1888c2ecf20Sopenharmony_ci *		Invalidate the virtual-address range '[start, end)' on all
1898c2ecf20Sopenharmony_ci *		CPUs for the user address space corresponding to 'vma->mm'.
1908c2ecf20Sopenharmony_ci *		Note that this operation also invalidates any walk-cache
1918c2ecf20Sopenharmony_ci *		entries associated with translations for the specified address
1928c2ecf20Sopenharmony_ci *		range.
1938c2ecf20Sopenharmony_ci *
1948c2ecf20Sopenharmony_ci *	flush_tlb_kernel_range(start, end)
1958c2ecf20Sopenharmony_ci *		Same as flush_tlb_range(..., start, end), but applies to
1968c2ecf20Sopenharmony_ci * 		kernel mappings rather than a particular user address space.
1978c2ecf20Sopenharmony_ci *		Whilst not explicitly documented, this function is used when
1988c2ecf20Sopenharmony_ci *		unmapping pages from vmalloc/io space.
1998c2ecf20Sopenharmony_ci *
2008c2ecf20Sopenharmony_ci *	flush_tlb_page(vma, addr)
2018c2ecf20Sopenharmony_ci *		Invalidate a single user mapping for address 'addr' in the
2028c2ecf20Sopenharmony_ci *		address space corresponding to 'vma->mm'.  Note that this
2038c2ecf20Sopenharmony_ci *		operation only invalidates a single, last-level page-table
2048c2ecf20Sopenharmony_ci *		entry and therefore does not affect any walk-caches.
2058c2ecf20Sopenharmony_ci *
2068c2ecf20Sopenharmony_ci *
2078c2ecf20Sopenharmony_ci *	Next, we have some undocumented invalidation routines that you probably
2088c2ecf20Sopenharmony_ci *	don't want to call unless you know what you're doing:
2098c2ecf20Sopenharmony_ci *
2108c2ecf20Sopenharmony_ci *	local_flush_tlb_all()
2118c2ecf20Sopenharmony_ci *		Same as flush_tlb_all(), but only applies to the calling CPU.
2128c2ecf20Sopenharmony_ci *
2138c2ecf20Sopenharmony_ci *	__flush_tlb_kernel_pgtable(addr)
2148c2ecf20Sopenharmony_ci *		Invalidate a single kernel mapping for address 'addr' on all
2158c2ecf20Sopenharmony_ci *		CPUs, ensuring that any walk-cache entries associated with the
2168c2ecf20Sopenharmony_ci *		translation are also invalidated.
2178c2ecf20Sopenharmony_ci *
2188c2ecf20Sopenharmony_ci *	__flush_tlb_range(vma, start, end, stride, last_level)
2198c2ecf20Sopenharmony_ci *		Invalidate the virtual-address range '[start, end)' on all
2208c2ecf20Sopenharmony_ci *		CPUs for the user address space corresponding to 'vma->mm'.
2218c2ecf20Sopenharmony_ci *		The invalidation operations are issued at a granularity
2228c2ecf20Sopenharmony_ci *		determined by 'stride' and only affect any walk-cache entries
2238c2ecf20Sopenharmony_ci *		if 'last_level' is equal to false.
2248c2ecf20Sopenharmony_ci *
2258c2ecf20Sopenharmony_ci *
2268c2ecf20Sopenharmony_ci *	Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented
2278c2ecf20Sopenharmony_ci *	on top of these routines, since that is our interface to the mmu_gather
2288c2ecf20Sopenharmony_ci *	API as used by munmap() and friends.
2298c2ecf20Sopenharmony_ci */
2308c2ecf20Sopenharmony_cistatic inline void local_flush_tlb_all(void)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	dsb(nshst);
2338c2ecf20Sopenharmony_ci	__tlbi(vmalle1);
2348c2ecf20Sopenharmony_ci	dsb(nsh);
2358c2ecf20Sopenharmony_ci	isb();
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic inline void flush_tlb_all(void)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	dsb(ishst);
2418c2ecf20Sopenharmony_ci	__tlbi(vmalle1is);
2428c2ecf20Sopenharmony_ci	dsb(ish);
2438c2ecf20Sopenharmony_ci	isb();
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic inline void flush_tlb_mm(struct mm_struct *mm)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	unsigned long asid;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	dsb(ishst);
2518c2ecf20Sopenharmony_ci	asid = __TLBI_VADDR(0, ASID(mm));
2528c2ecf20Sopenharmony_ci	__tlbi(aside1is, asid);
2538c2ecf20Sopenharmony_ci	__tlbi_user(aside1is, asid);
2548c2ecf20Sopenharmony_ci	dsb(ish);
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic inline void flush_tlb_page_nosync(struct vm_area_struct *vma,
2588c2ecf20Sopenharmony_ci					 unsigned long uaddr)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	unsigned long addr;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	dsb(ishst);
2638c2ecf20Sopenharmony_ci	addr = __TLBI_VADDR(uaddr, ASID(vma->vm_mm));
2648c2ecf20Sopenharmony_ci	__tlbi(vale1is, addr);
2658c2ecf20Sopenharmony_ci	__tlbi_user(vale1is, addr);
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic inline void flush_tlb_page(struct vm_area_struct *vma,
2698c2ecf20Sopenharmony_ci				  unsigned long uaddr)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	flush_tlb_page_nosync(vma, uaddr);
2728c2ecf20Sopenharmony_ci	dsb(ish);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci/*
2768c2ecf20Sopenharmony_ci * This is meant to avoid soft lock-ups on large TLB flushing ranges and not
2778c2ecf20Sopenharmony_ci * necessarily a performance improvement.
2788c2ecf20Sopenharmony_ci */
2798c2ecf20Sopenharmony_ci#define MAX_TLBI_OPS	PTRS_PER_PTE
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic inline void __flush_tlb_range(struct vm_area_struct *vma,
2828c2ecf20Sopenharmony_ci				     unsigned long start, unsigned long end,
2838c2ecf20Sopenharmony_ci				     unsigned long stride, bool last_level,
2848c2ecf20Sopenharmony_ci				     int tlb_level)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	int num = 0;
2878c2ecf20Sopenharmony_ci	int scale = 0;
2888c2ecf20Sopenharmony_ci	unsigned long asid, addr, pages;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	start = round_down(start, stride);
2918c2ecf20Sopenharmony_ci	end = round_up(end, stride);
2928c2ecf20Sopenharmony_ci	pages = (end - start) >> PAGE_SHIFT;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/*
2958c2ecf20Sopenharmony_ci	 * When not uses TLB range ops, we can handle up to
2968c2ecf20Sopenharmony_ci	 * (MAX_TLBI_OPS - 1) pages;
2978c2ecf20Sopenharmony_ci	 * When uses TLB range ops, we can handle up to
2988c2ecf20Sopenharmony_ci	 * (MAX_TLBI_RANGE_PAGES - 1) pages.
2998c2ecf20Sopenharmony_ci	 */
3008c2ecf20Sopenharmony_ci	if ((!system_supports_tlb_range() &&
3018c2ecf20Sopenharmony_ci	     (end - start) >= (MAX_TLBI_OPS * stride)) ||
3028c2ecf20Sopenharmony_ci	    pages >= MAX_TLBI_RANGE_PAGES) {
3038c2ecf20Sopenharmony_ci		flush_tlb_mm(vma->vm_mm);
3048c2ecf20Sopenharmony_ci		return;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	dsb(ishst);
3088c2ecf20Sopenharmony_ci	asid = ASID(vma->vm_mm);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/*
3118c2ecf20Sopenharmony_ci	 * When the CPU does not support TLB range operations, flush the TLB
3128c2ecf20Sopenharmony_ci	 * entries one by one at the granularity of 'stride'. If the the TLB
3138c2ecf20Sopenharmony_ci	 * range ops are supported, then:
3148c2ecf20Sopenharmony_ci	 *
3158c2ecf20Sopenharmony_ci	 * 1. If 'pages' is odd, flush the first page through non-range
3168c2ecf20Sopenharmony_ci	 *    operations;
3178c2ecf20Sopenharmony_ci	 *
3188c2ecf20Sopenharmony_ci	 * 2. For remaining pages: the minimum range granularity is decided
3198c2ecf20Sopenharmony_ci	 *    by 'scale', so multiple range TLBI operations may be required.
3208c2ecf20Sopenharmony_ci	 *    Start from scale = 0, flush the corresponding number of pages
3218c2ecf20Sopenharmony_ci	 *    ((num+1)*2^(5*scale+1) starting from 'addr'), then increase it
3228c2ecf20Sopenharmony_ci	 *    until no pages left.
3238c2ecf20Sopenharmony_ci	 *
3248c2ecf20Sopenharmony_ci	 * Note that certain ranges can be represented by either num = 31 and
3258c2ecf20Sopenharmony_ci	 * scale or num = 0 and scale + 1. The loop below favours the latter
3268c2ecf20Sopenharmony_ci	 * since num is limited to 30 by the __TLBI_RANGE_NUM() macro.
3278c2ecf20Sopenharmony_ci	 */
3288c2ecf20Sopenharmony_ci	while (pages > 0) {
3298c2ecf20Sopenharmony_ci		if (!system_supports_tlb_range() ||
3308c2ecf20Sopenharmony_ci		    pages % 2 == 1) {
3318c2ecf20Sopenharmony_ci			addr = __TLBI_VADDR(start, asid);
3328c2ecf20Sopenharmony_ci			if (last_level) {
3338c2ecf20Sopenharmony_ci				__tlbi_level(vale1is, addr, tlb_level);
3348c2ecf20Sopenharmony_ci				__tlbi_user_level(vale1is, addr, tlb_level);
3358c2ecf20Sopenharmony_ci			} else {
3368c2ecf20Sopenharmony_ci				__tlbi_level(vae1is, addr, tlb_level);
3378c2ecf20Sopenharmony_ci				__tlbi_user_level(vae1is, addr, tlb_level);
3388c2ecf20Sopenharmony_ci			}
3398c2ecf20Sopenharmony_ci			start += stride;
3408c2ecf20Sopenharmony_ci			pages -= stride >> PAGE_SHIFT;
3418c2ecf20Sopenharmony_ci			continue;
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		num = __TLBI_RANGE_NUM(pages, scale);
3458c2ecf20Sopenharmony_ci		if (num >= 0) {
3468c2ecf20Sopenharmony_ci			addr = __TLBI_VADDR_RANGE(start, asid, scale,
3478c2ecf20Sopenharmony_ci						  num, tlb_level);
3488c2ecf20Sopenharmony_ci			if (last_level) {
3498c2ecf20Sopenharmony_ci				__tlbi(rvale1is, addr);
3508c2ecf20Sopenharmony_ci				__tlbi_user(rvale1is, addr);
3518c2ecf20Sopenharmony_ci			} else {
3528c2ecf20Sopenharmony_ci				__tlbi(rvae1is, addr);
3538c2ecf20Sopenharmony_ci				__tlbi_user(rvae1is, addr);
3548c2ecf20Sopenharmony_ci			}
3558c2ecf20Sopenharmony_ci			start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT;
3568c2ecf20Sopenharmony_ci			pages -= __TLBI_RANGE_PAGES(num, scale);
3578c2ecf20Sopenharmony_ci		}
3588c2ecf20Sopenharmony_ci		scale++;
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci	dsb(ish);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic inline void flush_tlb_range(struct vm_area_struct *vma,
3648c2ecf20Sopenharmony_ci				   unsigned long start, unsigned long end)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	/*
3678c2ecf20Sopenharmony_ci	 * We cannot use leaf-only invalidation here, since we may be invalidating
3688c2ecf20Sopenharmony_ci	 * table entries as part of collapsing hugepages or moving page tables.
3698c2ecf20Sopenharmony_ci	 * Set the tlb_level to 0 because we can not get enough information here.
3708c2ecf20Sopenharmony_ci	 */
3718c2ecf20Sopenharmony_ci	__flush_tlb_range(vma, start, end, PAGE_SIZE, false, 0);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	unsigned long addr;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if ((end - start) > (MAX_TLBI_OPS * PAGE_SIZE)) {
3798c2ecf20Sopenharmony_ci		flush_tlb_all();
3808c2ecf20Sopenharmony_ci		return;
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	start = __TLBI_VADDR(start, 0);
3848c2ecf20Sopenharmony_ci	end = __TLBI_VADDR(end, 0);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	dsb(ishst);
3878c2ecf20Sopenharmony_ci	for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
3888c2ecf20Sopenharmony_ci		__tlbi(vaale1is, addr);
3898c2ecf20Sopenharmony_ci	dsb(ish);
3908c2ecf20Sopenharmony_ci	isb();
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci/*
3948c2ecf20Sopenharmony_ci * Used to invalidate the TLB (walk caches) corresponding to intermediate page
3958c2ecf20Sopenharmony_ci * table levels (pgd/pud/pmd).
3968c2ecf20Sopenharmony_ci */
3978c2ecf20Sopenharmony_cistatic inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	unsigned long addr = __TLBI_VADDR(kaddr, 0);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	dsb(ishst);
4028c2ecf20Sopenharmony_ci	__tlbi(vaae1is, addr);
4038c2ecf20Sopenharmony_ci	dsb(ish);
4048c2ecf20Sopenharmony_ci	isb();
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci#endif
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci#endif
409