tlbflush.h 8.3 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0-only */
2 3 4 5 6 7 8 9 10 11 12
/*
 * Based on arch/arm/include/asm/tlbflush.h
 *
 * Copyright (C) 1999-2003 Russell King
 * Copyright (C) 2012 ARM Ltd.
 */
#ifndef __ASM_TLBFLUSH_H
#define __ASM_TLBFLUSH_H

#ifndef __ASSEMBLY__

13
#include <linux/bitfield.h>
14
#include <linux/mm_types.h>
15 16
#include <linux/sched.h>
#include <asm/cputype.h>
17
#include <asm/mmu.h>
18

19 20 21 22 23 24 25 26 27 28 29 30
/*
 * Raw TLBI operations.
 *
 * Where necessary, use the __tlbi() macro to avoid asm()
 * boilerplate. Drivers and most kernel code should use the TLB
 * management routines in preference to the macro below.
 *
 * The macro can be used as __tlbi(op) or __tlbi(op, arg), depending
 * on whether a particular TLBI operation takes an argument or
 * not. The macros handles invoking the asm with or without the
 * register argument as appropriate.
 */
31 32 33 34
#define __TLBI_0(op, arg) asm ("tlbi " #op "\n"				       \
		   ALTERNATIVE("nop\n			nop",		       \
			       "dsb ish\n		tlbi " #op,	       \
			       ARM64_WORKAROUND_REPEAT_TLBI,		       \
35
			       CONFIG_ARM64_WORKAROUND_REPEAT_TLBI)	       \
36 37 38 39 40 41
			    : : )

#define __TLBI_1(op, arg) asm ("tlbi " #op ", %0\n"			       \
		   ALTERNATIVE("nop\n			nop",		       \
			       "dsb ish\n		tlbi " #op ", %0",     \
			       ARM64_WORKAROUND_REPEAT_TLBI,		       \
42
			       CONFIG_ARM64_WORKAROUND_REPEAT_TLBI)	       \
43 44 45
			    : : "r" (arg))

#define __TLBI_N(op, arg, n, ...) __TLBI_##n(op, arg)
46 47 48

#define __tlbi(op, ...)		__TLBI_N(op, ##__VA_ARGS__, 1, 0)

49 50 51 52 53
#define __tlbi_user(op, arg) do {						\
	if (arm64_kernel_unmapped_at_el0())					\
		__tlbi(op, (arg) | USER_ASID_FLAG);				\
} while (0)

54 55 56 57 58 59 60 61 62
/* This macro creates a properly formatted VA operand for the TLBI */
#define __TLBI_VADDR(addr, asid)				\
	({							\
		unsigned long __ta = (addr) >> 12;		\
		__ta &= GENMASK_ULL(43, 0);			\
		__ta |= (unsigned long)(asid) << 48;		\
		__ta;						\
	})

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
/*
 * Level-based TLBI operations.
 *
 * When ARMv8.4-TTL exists, TLBI operations take an additional hint for
 * the level at which the invalidation must take place. If the level is
 * wrong, no invalidation may take place. In the case where the level
 * cannot be easily determined, a 0 value for the level parameter will
 * perform a non-hinted invalidation.
 *
 * For Stage-2 invalidation, use the level values provided to that effect
 * in asm/stage2_pgtable.h.
 */
#define TLBI_TTL_MASK		GENMASK_ULL(47, 44)
#define TLBI_TTL_TG_4K		1
#define TLBI_TTL_TG_16K		2
#define TLBI_TTL_TG_64K		3

#define __tlbi_level(op, addr, level)					\
	do {								\
		u64 arg = addr;						\
									\
		if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL) &&	\
		    level) {						\
			u64 ttl = level & 3;				\
									\
			switch (PAGE_SIZE) {				\
			case SZ_4K:					\
				ttl |= TLBI_TTL_TG_4K << 2;		\
				break;					\
			case SZ_16K:					\
				ttl |= TLBI_TTL_TG_16K << 2;		\
				break;					\
			case SZ_64K:					\
				ttl |= TLBI_TTL_TG_64K << 2;		\
				break;					\
			}						\
									\
			arg &= ~TLBI_TTL_MASK;				\
			arg |= FIELD_PREP(TLBI_TTL_MASK, ttl);		\
		}							\
									\
		__tlbi(op, arg);					\
	} while(0)

107
/*
108 109
 *	TLB Invalidation
 *	================
110
 *
111 112
 * 	This header file implements the low-level TLB invalidation routines
 *	(sometimes referred to as "flushing" in the kernel) for arm64.
113
 *
114
 *	Every invalidation operation uses the following template:
115
 *
116 117 118 119 120
 *	DSB ISHST	// Ensure prior page-table updates have completed
 *	TLBI ...	// Invalidate the TLB
 *	DSB ISH		// Ensure the TLB invalidation has completed
 *      if (invalidated kernel mappings)
 *		ISB	// Discard any instructions fetched from the old mapping
121 122
 *
 *
123 124
 *	The following functions form part of the "core" TLB invalidation API,
 *	as documented in Documentation/core-api/cachetlb.rst:
125
 *
126 127
 *	flush_tlb_all()
 *		Invalidate the entire TLB (kernel + user) on all CPUs
128
 *
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
 *	flush_tlb_mm(mm)
 *		Invalidate an entire user address space on all CPUs.
 *		The 'mm' argument identifies the ASID to invalidate.
 *
 *	flush_tlb_range(vma, start, end)
 *		Invalidate the virtual-address range '[start, end)' on all
 *		CPUs for the user address space corresponding to 'vma->mm'.
 *		Note that this operation also invalidates any walk-cache
 *		entries associated with translations for the specified address
 *		range.
 *
 *	flush_tlb_kernel_range(start, end)
 *		Same as flush_tlb_range(..., start, end), but applies to
 * 		kernel mappings rather than a particular user address space.
 *		Whilst not explicitly documented, this function is used when
 *		unmapping pages from vmalloc/io space.
 *
 *	flush_tlb_page(vma, addr)
 *		Invalidate a single user mapping for address 'addr' in the
 *		address space corresponding to 'vma->mm'.  Note that this
 *		operation only invalidates a single, last-level page-table
 *		entry and therefore does not affect any walk-caches.
 *
 *
 *	Next, we have some undocumented invalidation routines that you probably
 *	don't want to call unless you know what you're doing:
 *
 *	local_flush_tlb_all()
 *		Same as flush_tlb_all(), but only applies to the calling CPU.
 *
 *	__flush_tlb_kernel_pgtable(addr)
 *		Invalidate a single kernel mapping for address 'addr' on all
 *		CPUs, ensuring that any walk-cache entries associated with the
 *		translation are also invalidated.
 *
 *	__flush_tlb_range(vma, start, end, stride, last_level)
 *		Invalidate the virtual-address range '[start, end)' on all
 *		CPUs for the user address space corresponding to 'vma->mm'.
 *		The invalidation operations are issued at a granularity
 *		determined by 'stride' and only affect any walk-cache entries
 *		if 'last_level' is equal to false.
 *
 *
 *	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.
175
 */
176 177 178
static inline void local_flush_tlb_all(void)
{
	dsb(nshst);
179
	__tlbi(vmalle1);
180 181 182 183
	dsb(nsh);
	isb();
}

184 185
static inline void flush_tlb_all(void)
{
186
	dsb(ishst);
187
	__tlbi(vmalle1is);
188
	dsb(ish);
189 190 191 192 193
	isb();
}

static inline void flush_tlb_mm(struct mm_struct *mm)
{
194
	unsigned long asid = __TLBI_VADDR(0, ASID(mm));
195

196
	dsb(ishst);
197
	__tlbi(aside1is, asid);
198
	__tlbi_user(aside1is, asid);
199
	dsb(ish);
200 201
}

202 203
static inline void flush_tlb_page_nosync(struct vm_area_struct *vma,
					 unsigned long uaddr)
204
{
205
	unsigned long addr = __TLBI_VADDR(uaddr, ASID(vma->vm_mm));
206

207
	dsb(ishst);
208
	__tlbi(vale1is, addr);
209
	__tlbi_user(vale1is, addr);
210 211 212 213 214 215
}

static inline void flush_tlb_page(struct vm_area_struct *vma,
				  unsigned long uaddr)
{
	flush_tlb_page_nosync(vma, uaddr);
216
	dsb(ish);
217 218
}

219 220 221 222
/*
 * This is meant to avoid soft lock-ups on large TLB flushing ranges and not
 * necessarily a performance improvement.
 */
223
#define MAX_TLBI_OPS	PTRS_PER_PTE
224

225 226
static inline void __flush_tlb_range(struct vm_area_struct *vma,
				     unsigned long start, unsigned long end,
227
				     unsigned long stride, bool last_level)
228
{
229
	unsigned long asid = ASID(vma->vm_mm);
230
	unsigned long addr;
231

232 233 234
	start = round_down(start, stride);
	end = round_up(end, stride);

235
	if ((end - start) >= (MAX_TLBI_OPS * stride)) {
236 237 238 239
		flush_tlb_mm(vma->vm_mm);
		return;
	}

240 241 242
	/* Convert the stride into units of 4k */
	stride >>= 12;

243 244
	start = __TLBI_VADDR(start, asid);
	end = __TLBI_VADDR(end, asid);
245 246

	dsb(ishst);
247
	for (addr = start; addr < end; addr += stride) {
248
		if (last_level) {
249
			__tlbi(vale1is, addr);
250 251
			__tlbi_user(vale1is, addr);
		} else {
252
			__tlbi(vae1is, addr);
253 254
			__tlbi_user(vae1is, addr);
		}
255
	}
256 257 258
	dsb(ish);
}

259 260 261
static inline void flush_tlb_range(struct vm_area_struct *vma,
				   unsigned long start, unsigned long end)
{
262 263 264 265
	/*
	 * We cannot use leaf-only invalidation here, since we may be invalidating
	 * table entries as part of collapsing hugepages or moving page tables.
	 */
266
	__flush_tlb_range(vma, start, end, PAGE_SIZE, false);
267 268
}

269
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
270 271
{
	unsigned long addr;
272

273
	if ((end - start) > (MAX_TLBI_OPS * PAGE_SIZE)) {
274 275 276 277
		flush_tlb_all();
		return;
	}

278 279
	start = __TLBI_VADDR(start, 0);
	end = __TLBI_VADDR(end, 0);
280 281 282

	dsb(ishst);
	for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
283
		__tlbi(vaale1is, addr);
284
	dsb(ish);
285
	isb();
286
}
287

288 289 290 291
/*
 * Used to invalidate the TLB (walk caches) corresponding to intermediate page
 * table levels (pgd/pud/pmd).
 */
292 293 294 295
static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
{
	unsigned long addr = __TLBI_VADDR(kaddr, 0);

296
	dsb(ishst);
297 298
	__tlbi(vaae1is, addr);
	dsb(ish);
299
	isb();
300
}
301 302 303
#endif

#endif