xref: /linux/arch/xtensa/include/asm/tlbflush.h (revision f615136c06a791364f5afa8b8ba965315a6440f1)
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2001 - 2013 Tensilica Inc.
7  */
8 
9 #ifndef _XTENSA_TLBFLUSH_H
10 #define _XTENSA_TLBFLUSH_H
11 
12 #include <linux/stringify.h>
13 #include <asm/processor.h>
14 
15 #define DTLB_WAY_PGD	7
16 
17 #define ITLB_ARF_WAYS	4
18 #define DTLB_ARF_WAYS	4
19 
20 #define ITLB_HIT_BIT	3
21 #define DTLB_HIT_BIT	4
22 
23 #ifndef __ASSEMBLY__
24 
25 /* TLB flushing:
26  *
27  *  - flush_tlb_all() flushes all processes TLB entries
28  *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
29  *  - flush_tlb_page(mm, vmaddr) flushes a single page
30  *  - flush_tlb_range(mm, start, end) flushes a range of pages
31  */
32 
33 void local_flush_tlb_all(void);
34 void local_flush_tlb_mm(struct mm_struct *mm);
35 void local_flush_tlb_page(struct vm_area_struct *vma,
36 		unsigned long page);
37 void local_flush_tlb_range(struct vm_area_struct *vma,
38 		unsigned long start, unsigned long end);
39 
40 #ifdef CONFIG_SMP
41 
42 void flush_tlb_all(void);
43 void flush_tlb_mm(struct mm_struct *);
44 void flush_tlb_page(struct vm_area_struct *, unsigned long);
45 void flush_tlb_range(struct vm_area_struct *, unsigned long,
46 		unsigned long);
47 
48 static inline void flush_tlb_kernel_range(unsigned long start,
49 		unsigned long end)
50 {
51 	flush_tlb_all();
52 }
53 
54 #else /* !CONFIG_SMP */
55 
56 #define flush_tlb_all()			   local_flush_tlb_all()
57 #define flush_tlb_mm(mm)		   local_flush_tlb_mm(mm)
58 #define flush_tlb_page(vma, page)	   local_flush_tlb_page(vma, page)
59 #define flush_tlb_range(vma, vmaddr, end)  local_flush_tlb_range(vma, vmaddr, \
60 								 end)
61 #define flush_tlb_kernel_range(start, end) local_flush_tlb_all()
62 
63 #endif /* CONFIG_SMP */
64 
65 /* TLB operations. */
66 
67 static inline unsigned long itlb_probe(unsigned long addr)
68 {
69 	unsigned long tmp;
70 	__asm__ __volatile__("pitlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
71 	return tmp;
72 }
73 
74 static inline unsigned long dtlb_probe(unsigned long addr)
75 {
76 	unsigned long tmp;
77 	__asm__ __volatile__("pdtlb  %0, %1\n\t" : "=a" (tmp) : "a" (addr));
78 	return tmp;
79 }
80 
81 static inline void invalidate_itlb_entry (unsigned long probe)
82 {
83 	__asm__ __volatile__("iitlb  %0; isync\n\t" : : "a" (probe));
84 }
85 
86 static inline void invalidate_dtlb_entry (unsigned long probe)
87 {
88 	__asm__ __volatile__("idtlb  %0; dsync\n\t" : : "a" (probe));
89 }
90 
91 /* Use the .._no_isync functions with caution.  Generally, these are
92  * handy for bulk invalidates followed by a single 'isync'.  The
93  * caller must follow up with an 'isync', which can be relatively
94  * expensive on some Xtensa implementations.
95  */
96 static inline void invalidate_itlb_entry_no_isync (unsigned entry)
97 {
98 	/* Caller must follow up with 'isync'. */
99 	__asm__ __volatile__ ("iitlb  %0\n" : : "a" (entry) );
100 }
101 
102 static inline void invalidate_dtlb_entry_no_isync (unsigned entry)
103 {
104 	/* Caller must follow up with 'isync'. */
105 	__asm__ __volatile__ ("idtlb  %0\n" : : "a" (entry) );
106 }
107 
108 static inline void set_itlbcfg_register (unsigned long val)
109 {
110 	__asm__ __volatile__("wsr  %0, itlbcfg\n\t" "isync\n\t"
111 			     : : "a" (val));
112 }
113 
114 static inline void set_dtlbcfg_register (unsigned long val)
115 {
116 	__asm__ __volatile__("wsr  %0, dtlbcfg; dsync\n\t"
117 	    		     : : "a" (val));
118 }
119 
120 static inline void set_ptevaddr_register (unsigned long val)
121 {
122 	__asm__ __volatile__(" wsr  %0, ptevaddr; isync\n"
123 			     : : "a" (val));
124 }
125 
126 static inline unsigned long read_ptevaddr_register (void)
127 {
128 	unsigned long tmp;
129 	__asm__ __volatile__("rsr  %0, ptevaddr\n\t" : "=a" (tmp));
130 	return tmp;
131 }
132 
133 static inline void write_dtlb_entry (pte_t entry, int way)
134 {
135 	__asm__ __volatile__("wdtlb  %1, %0; dsync\n\t"
136 			     : : "r" (way), "r" (entry) );
137 }
138 
139 static inline void write_itlb_entry (pte_t entry, int way)
140 {
141 	__asm__ __volatile__("witlb  %1, %0; isync\n\t"
142 	                     : : "r" (way), "r" (entry) );
143 }
144 
145 static inline void invalidate_page_directory (void)
146 {
147 	invalidate_dtlb_entry (DTLB_WAY_PGD);
148 	invalidate_dtlb_entry (DTLB_WAY_PGD+1);
149 	invalidate_dtlb_entry (DTLB_WAY_PGD+2);
150 }
151 
152 static inline void invalidate_itlb_mapping (unsigned address)
153 {
154 	unsigned long tlb_entry;
155 	if (((tlb_entry = itlb_probe(address)) & (1 << ITLB_HIT_BIT)) != 0)
156 		invalidate_itlb_entry(tlb_entry);
157 }
158 
159 static inline void invalidate_dtlb_mapping (unsigned address)
160 {
161 	unsigned long tlb_entry;
162 	if (((tlb_entry = dtlb_probe(address)) & (1 << DTLB_HIT_BIT)) != 0)
163 		invalidate_dtlb_entry(tlb_entry);
164 }
165 
166 #define check_pgt_cache()	do { } while (0)
167 
168 
169 /*
170  * DO NOT USE THESE FUNCTIONS.  These instructions aren't part of the Xtensa
171  * ISA and exist only for test purposes..
172  * You may find it helpful for MMU debugging, however.
173  *
174  * 'at' is the unmodified input register
175  * 'as' is the output register, as follows (specific to the Linux config):
176  *
177  *      as[31..12] contain the virtual address
178  *      as[11..08] are meaningless
179  *      as[07..00] contain the asid
180  */
181 
182 static inline unsigned long read_dtlb_virtual (int way)
183 {
184 	unsigned long tmp;
185 	__asm__ __volatile__("rdtlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
186 	return tmp;
187 }
188 
189 static inline unsigned long read_dtlb_translation (int way)
190 {
191 	unsigned long tmp;
192 	__asm__ __volatile__("rdtlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
193 	return tmp;
194 }
195 
196 static inline unsigned long read_itlb_virtual (int way)
197 {
198 	unsigned long tmp;
199 	__asm__ __volatile__("ritlb0  %0, %1\n\t" : "=a" (tmp), "+a" (way));
200 	return tmp;
201 }
202 
203 static inline unsigned long read_itlb_translation (int way)
204 {
205 	unsigned long tmp;
206 	__asm__ __volatile__("ritlb1  %0, %1\n\t" : "=a" (tmp), "+a" (way));
207 	return tmp;
208 }
209 
210 #endif	/* __ASSEMBLY__ */
211 #endif	/* _XTENSA_TLBFLUSH_H */
212