xref: /openbmc/linux/arch/arm64/include/asm/tlbflush.h (revision 4f3db074)
1 /*
2  * Based on arch/arm/include/asm/tlbflush.h
3  *
4  * Copyright (C) 1999-2003 Russell King
5  * Copyright (C) 2012 ARM Ltd.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #ifndef __ASM_TLBFLUSH_H
20 #define __ASM_TLBFLUSH_H
21 
22 #ifndef __ASSEMBLY__
23 
24 #include <linux/sched.h>
25 #include <asm/cputype.h>
26 
27 /*
28  *	TLB Management
29  *	==============
30  *
31  *	The arch/arm64/mm/tlb.S files implement these methods.
32  *
33  *	The TLB specific code is expected to perform whatever tests it needs
34  *	to determine if it should invalidate the TLB for each call.  Start
35  *	addresses are inclusive and end addresses are exclusive; it is safe to
36  *	round these addresses down.
37  *
38  *	flush_tlb_all()
39  *
40  *		Invalidate the entire TLB.
41  *
42  *	flush_tlb_mm(mm)
43  *
44  *		Invalidate all TLB entries in a particular address space.
45  *		- mm	- mm_struct describing address space
46  *
47  *	flush_tlb_range(mm,start,end)
48  *
49  *		Invalidate a range of TLB entries in the specified address
50  *		space.
51  *		- mm	- mm_struct describing address space
52  *		- start - start address (may not be aligned)
53  *		- end	- end address (exclusive, may not be aligned)
54  *
55  *	flush_tlb_page(vaddr,vma)
56  *
57  *		Invalidate the specified page in the specified address range.
58  *		- vaddr - virtual address (may not be aligned)
59  *		- vma	- vma_struct describing address range
60  *
61  *	flush_kern_tlb_page(kaddr)
62  *
63  *		Invalidate the TLB entry for the specified page.  The address
64  *		will be in the kernels virtual memory space.  Current uses
65  *		only require the D-TLB to be invalidated.
66  *		- kaddr - Kernel virtual memory address
67  */
68 static inline void flush_tlb_all(void)
69 {
70 	dsb(ishst);
71 	asm("tlbi	vmalle1is");
72 	dsb(ish);
73 	isb();
74 }
75 
76 static inline void flush_tlb_mm(struct mm_struct *mm)
77 {
78 	unsigned long asid = (unsigned long)ASID(mm) << 48;
79 
80 	dsb(ishst);
81 	asm("tlbi	aside1is, %0" : : "r" (asid));
82 	dsb(ish);
83 }
84 
85 static inline void flush_tlb_page(struct vm_area_struct *vma,
86 				  unsigned long uaddr)
87 {
88 	unsigned long addr = uaddr >> 12 |
89 		((unsigned long)ASID(vma->vm_mm) << 48);
90 
91 	dsb(ishst);
92 	asm("tlbi	vae1is, %0" : : "r" (addr));
93 	dsb(ish);
94 }
95 
96 static inline void __flush_tlb_range(struct vm_area_struct *vma,
97 				     unsigned long start, unsigned long end)
98 {
99 	unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48;
100 	unsigned long addr;
101 	start = asid | (start >> 12);
102 	end = asid | (end >> 12);
103 
104 	dsb(ishst);
105 	for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
106 		asm("tlbi vae1is, %0" : : "r"(addr));
107 	dsb(ish);
108 }
109 
110 static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long end)
111 {
112 	unsigned long addr;
113 	start >>= 12;
114 	end >>= 12;
115 
116 	dsb(ishst);
117 	for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
118 		asm("tlbi vaae1is, %0" : : "r"(addr));
119 	dsb(ish);
120 	isb();
121 }
122 
123 /*
124  * This is meant to avoid soft lock-ups on large TLB flushing ranges and not
125  * necessarily a performance improvement.
126  */
127 #define MAX_TLB_RANGE	(1024UL << PAGE_SHIFT)
128 
129 static inline void flush_tlb_range(struct vm_area_struct *vma,
130 				   unsigned long start, unsigned long end)
131 {
132 	if ((end - start) <= MAX_TLB_RANGE)
133 		__flush_tlb_range(vma, start, end);
134 	else
135 		flush_tlb_mm(vma->vm_mm);
136 }
137 
138 static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
139 {
140 	if ((end - start) <= MAX_TLB_RANGE)
141 		__flush_tlb_kernel_range(start, end);
142 	else
143 		flush_tlb_all();
144 }
145 
146 /*
147  * Used to invalidate the TLB (walk caches) corresponding to intermediate page
148  * table levels (pgd/pud/pmd).
149  */
150 static inline void __flush_tlb_pgtable(struct mm_struct *mm,
151 				       unsigned long uaddr)
152 {
153 	unsigned long addr = uaddr >> 12 | ((unsigned long)ASID(mm) << 48);
154 
155 	dsb(ishst);
156 	asm("tlbi	vae1is, %0" : : "r" (addr));
157 	dsb(ish);
158 }
159 /*
160  * On AArch64, the cache coherency is handled via the set_pte_at() function.
161  */
162 static inline void update_mmu_cache(struct vm_area_struct *vma,
163 				    unsigned long addr, pte_t *ptep)
164 {
165 	/*
166 	 * set_pte() does not have a DSB for user mappings, so make sure that
167 	 * the page table write is visible.
168 	 */
169 	dsb(ishst);
170 }
171 
172 #define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
173 
174 #endif
175 
176 #endif
177