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