blob: a62218013c78bd80447013c5f9f8872c010cd638 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Russell King4baa9922008-08-02 10:55:55 +01002 * arch/arm/include/asm/tlbflush.h
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 1999-2003 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#ifndef _ASMARM_TLBFLUSH_H
11#define _ASMARM_TLBFLUSH_H
12
Hyok S. Choi01579032006-02-24 21:41:25 +000013
14#ifndef CONFIG_MMU
15
16#define tlb_flush(tlb) ((void) tlb)
17
Russell Kingfb1c7762006-02-24 21:44:56 +000018#else /* CONFIG_MMU */
Hyok S. Choi01579032006-02-24 21:41:25 +000019
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <asm/glue.h>
21
22#define TLB_V3_PAGE (1 << 0)
23#define TLB_V4_U_PAGE (1 << 1)
24#define TLB_V4_D_PAGE (1 << 2)
25#define TLB_V4_I_PAGE (1 << 3)
26#define TLB_V6_U_PAGE (1 << 4)
27#define TLB_V6_D_PAGE (1 << 5)
28#define TLB_V6_I_PAGE (1 << 6)
29
30#define TLB_V3_FULL (1 << 8)
31#define TLB_V4_U_FULL (1 << 9)
32#define TLB_V4_D_FULL (1 << 10)
33#define TLB_V4_I_FULL (1 << 11)
34#define TLB_V6_U_FULL (1 << 12)
35#define TLB_V6_D_FULL (1 << 13)
36#define TLB_V6_I_FULL (1 << 14)
37
38#define TLB_V6_U_ASID (1 << 16)
39#define TLB_V6_D_ASID (1 << 17)
40#define TLB_V6_I_ASID (1 << 18)
41
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +020042#define TLB_BTB (1 << 28)
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +020043#define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#define TLB_DCLEAN (1 << 30)
45#define TLB_WB (1 << 31)
46
47/*
48 * MMU TLB Model
49 * =============
50 *
51 * We have the following to choose from:
52 * v3 - ARMv3
53 * v4 - ARMv4 without write buffer
54 * v4wb - ARMv4 with write buffer without I TLB flush entry instruction
55 * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +020056 * fr - Feroceon (v4wbi with non-outer-cacheable page table walks)
Paulius Zaleckas28853ac2009-03-25 13:10:01 +020057 * fa - Faraday (v4 with write buffer with UTLB and branch target buffer (BTB))
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 * v6wbi - ARMv6 with write buffer with I TLB flush entry instruction
Paul Walmsley61db7fb2008-08-12 00:04:15 +010059 * v7wbi - identical to v6wbi
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 */
61#undef _TLB
62#undef MULTI_TLB
63
64#define v3_tlb_flags (TLB_V3_FULL | TLB_V3_PAGE)
65
66#ifdef CONFIG_CPU_TLB_V3
67# define v3_possible_flags v3_tlb_flags
68# define v3_always_flags v3_tlb_flags
69# ifdef _TLB
70# define MULTI_TLB 1
71# else
72# define _TLB v3
73# endif
74#else
75# define v3_possible_flags 0
76# define v3_always_flags (-1UL)
77#endif
78
79#define v4_tlb_flags (TLB_V4_U_FULL | TLB_V4_U_PAGE)
80
81#ifdef CONFIG_CPU_TLB_V4WT
82# define v4_possible_flags v4_tlb_flags
83# define v4_always_flags v4_tlb_flags
84# ifdef _TLB
85# define MULTI_TLB 1
86# else
87# define _TLB v4
88# endif
89#else
90# define v4_possible_flags 0
91# define v4_always_flags (-1UL)
92#endif
93
Paulius Zaleckas28853ac2009-03-25 13:10:01 +020094#define fa_tlb_flags (TLB_WB | TLB_BTB | TLB_DCLEAN | \
95 TLB_V4_U_FULL | TLB_V4_U_PAGE)
96
97#ifdef CONFIG_CPU_TLB_FA
98# define fa_possible_flags fa_tlb_flags
99# define fa_always_flags fa_tlb_flags
100# ifdef _TLB
101# define MULTI_TLB 1
102# else
103# define _TLB fa
104# endif
105#else
106# define fa_possible_flags 0
107# define fa_always_flags (-1UL)
108#endif
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110#define v4wbi_tlb_flags (TLB_WB | TLB_DCLEAN | \
111 TLB_V4_I_FULL | TLB_V4_D_FULL | \
112 TLB_V4_I_PAGE | TLB_V4_D_PAGE)
113
114#ifdef CONFIG_CPU_TLB_V4WBI
115# define v4wbi_possible_flags v4wbi_tlb_flags
116# define v4wbi_always_flags v4wbi_tlb_flags
117# ifdef _TLB
118# define MULTI_TLB 1
119# else
120# define _TLB v4wbi
121# endif
122#else
123# define v4wbi_possible_flags 0
124# define v4wbi_always_flags (-1UL)
125#endif
126
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200127#define fr_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_L2CLEAN_FR | \
128 TLB_V4_I_FULL | TLB_V4_D_FULL | \
129 TLB_V4_I_PAGE | TLB_V4_D_PAGE)
130
131#ifdef CONFIG_CPU_TLB_FEROCEON
132# define fr_possible_flags fr_tlb_flags
133# define fr_always_flags fr_tlb_flags
134# ifdef _TLB
135# define MULTI_TLB 1
136# else
137# define _TLB v4wbi
138# endif
139#else
140# define fr_possible_flags 0
141# define fr_always_flags (-1UL)
142#endif
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144#define v4wb_tlb_flags (TLB_WB | TLB_DCLEAN | \
145 TLB_V4_I_FULL | TLB_V4_D_FULL | \
146 TLB_V4_D_PAGE)
147
148#ifdef CONFIG_CPU_TLB_V4WB
149# define v4wb_possible_flags v4wb_tlb_flags
150# define v4wb_always_flags v4wb_tlb_flags
151# ifdef _TLB
152# define MULTI_TLB 1
153# else
154# define _TLB v4wb
155# endif
156#else
157# define v4wb_possible_flags 0
158# define v4wb_always_flags (-1UL)
159#endif
160
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200161#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 TLB_V6_I_FULL | TLB_V6_D_FULL | \
163 TLB_V6_I_PAGE | TLB_V6_D_PAGE | \
164 TLB_V6_I_ASID | TLB_V6_D_ASID)
165
166#ifdef CONFIG_CPU_TLB_V6
167# define v6wbi_possible_flags v6wbi_tlb_flags
168# define v6wbi_always_flags v6wbi_tlb_flags
169# ifdef _TLB
170# define MULTI_TLB 1
171# else
172# define _TLB v6wbi
173# endif
174#else
175# define v6wbi_possible_flags 0
176# define v6wbi_always_flags (-1UL)
177#endif
178
Catalin Marinas2ccdd1e2007-05-18 11:25:31 +0100179#ifdef CONFIG_CPU_TLB_V7
180# define v7wbi_possible_flags v6wbi_tlb_flags
181# define v7wbi_always_flags v6wbi_tlb_flags
182# ifdef _TLB
183# define MULTI_TLB 1
184# else
185# define _TLB v7wbi
186# endif
187#else
188# define v7wbi_possible_flags 0
189# define v7wbi_always_flags (-1UL)
190#endif
191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192#ifndef _TLB
193#error Unknown TLB model
194#endif
195
196#ifndef __ASSEMBLY__
197
Alexey Dobriyane8edc6e2007-05-21 01:22:52 +0400198#include <linux/sched.h>
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200struct cpu_tlb_fns {
201 void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
202 void (*flush_kern_range)(unsigned long, unsigned long);
203 unsigned long tlb_flags;
204};
205
206/*
207 * Select the calling method
208 */
209#ifdef MULTI_TLB
210
211#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range
212#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range
213
214#else
215
216#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range)
217#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range)
218
219extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
220extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
221
222#endif
223
224extern struct cpu_tlb_fns cpu_tlb;
225
226#define __cpu_tlb_flags cpu_tlb.tlb_flags
227
228/*
229 * TLB Management
230 * ==============
231 *
232 * The arch/arm/mm/tlb-*.S files implement these methods.
233 *
234 * The TLB specific code is expected to perform whatever tests it
235 * needs to determine if it should invalidate the TLB for each
236 * call. Start addresses are inclusive and end addresses are
237 * exclusive; it is safe to round these addresses down.
238 *
239 * flush_tlb_all()
240 *
241 * Invalidate the entire TLB.
242 *
243 * flush_tlb_mm(mm)
244 *
245 * Invalidate all TLB entries in a particular address
246 * space.
247 * - mm - mm_struct describing address space
248 *
249 * flush_tlb_range(mm,start,end)
250 *
251 * Invalidate a range of TLB entries in the specified
252 * address space.
253 * - mm - mm_struct describing address space
254 * - start - start address (may not be aligned)
255 * - end - end address (exclusive, may not be aligned)
256 *
257 * flush_tlb_page(vaddr,vma)
258 *
259 * Invalidate the specified page in the specified address range.
260 * - vaddr - virtual address (may not be aligned)
261 * - vma - vma_struct describing address range
262 *
263 * flush_kern_tlb_page(kaddr)
264 *
265 * Invalidate the TLB entry for the specified page. The address
266 * will be in the kernels virtual memory space. Current uses
267 * only require the D-TLB to be invalidated.
268 * - kaddr - Kernel virtual memory address
269 */
270
271/*
272 * We optimise the code below by:
273 * - building a set of TLB flags that might be set in __cpu_tlb_flags
274 * - building a set of TLB flags that will always be set in __cpu_tlb_flags
275 * - if we're going to need __cpu_tlb_flags, access it once and only once
276 *
277 * This allows us to build optimal assembly for the single-CPU type case,
278 * and as close to optimal given the compiler constrants for multi-CPU
279 * case. We could do better for the multi-CPU case if the compiler
280 * implemented the "%?" method, but this has been discontinued due to too
281 * many people getting it wrong.
282 */
283#define possible_tlb_flags (v3_possible_flags | \
284 v4_possible_flags | \
285 v4wbi_possible_flags | \
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200286 fr_possible_flags | \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 v4wb_possible_flags | \
Paulius Zaleckas28853ac2009-03-25 13:10:01 +0200288 fa_possible_flags | \
Paul Walmsley61db7fb2008-08-12 00:04:15 +0100289 v6wbi_possible_flags | \
290 v7wbi_possible_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292#define always_tlb_flags (v3_always_flags & \
293 v4_always_flags & \
294 v4wbi_always_flags & \
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200295 fr_always_flags & \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 v4wb_always_flags & \
Paulius Zaleckas28853ac2009-03-25 13:10:01 +0200297 fa_always_flags & \
Paul Walmsley61db7fb2008-08-12 00:04:15 +0100298 v6wbi_always_flags & \
299 v7wbi_always_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
302
Russell King603fff52005-06-28 13:40:39 +0100303static inline void local_flush_tlb_all(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
305 const int zero = 0;
306 const unsigned int __tlb_flag = __cpu_tlb_flags;
307
308 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100309 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 if (tlb_flag(TLB_V3_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100312 asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 if (tlb_flag(TLB_V4_U_FULL | TLB_V6_U_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100314 asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (tlb_flag(TLB_V4_D_FULL | TLB_V6_D_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100316 asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100318 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Catalin Marinase6a5d662007-02-05 14:47:51 +0100319
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200320 if (tlb_flag(TLB_BTB)) {
Catalin Marinase6a5d662007-02-05 14:47:51 +0100321 /* flush the branch target cache */
322 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
323 dsb();
324 isb();
325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Russell King603fff52005-06-28 13:40:39 +0100328static inline void local_flush_tlb_mm(struct mm_struct *mm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 const int zero = 0;
331 const int asid = ASID(mm);
332 const unsigned int __tlb_flag = __cpu_tlb_flags;
333
334 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100335 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337 if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) {
338 if (tlb_flag(TLB_V3_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100339 asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 if (tlb_flag(TLB_V4_U_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100341 asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 if (tlb_flag(TLB_V4_D_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100343 asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 if (tlb_flag(TLB_V4_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100345 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 }
347
348 if (tlb_flag(TLB_V6_U_ASID))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100349 asm("mcr p15, 0, %0, c8, c7, 2" : : "r" (asid) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 if (tlb_flag(TLB_V6_D_ASID))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100351 asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (tlb_flag(TLB_V6_I_ASID))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100353 asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
Catalin Marinase6a5d662007-02-05 14:47:51 +0100354
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200355 if (tlb_flag(TLB_BTB)) {
Catalin Marinase6a5d662007-02-05 14:47:51 +0100356 /* flush the branch target cache */
357 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
358 dsb();
359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
362static inline void
Russell King603fff52005-06-28 13:40:39 +0100363local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 const int zero = 0;
366 const unsigned int __tlb_flag = __cpu_tlb_flags;
367
368 uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
369
370 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100371 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
374 if (tlb_flag(TLB_V3_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100375 asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 if (tlb_flag(TLB_V4_U_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100377 asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 if (tlb_flag(TLB_V4_D_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100379 asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 if (tlb_flag(TLB_V4_I_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100381 asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100383 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 }
385
386 if (tlb_flag(TLB_V6_U_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100387 asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (tlb_flag(TLB_V6_D_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100389 asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 if (tlb_flag(TLB_V6_I_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100391 asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
Catalin Marinase6a5d662007-02-05 14:47:51 +0100392
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200393 if (tlb_flag(TLB_BTB)) {
Catalin Marinase6a5d662007-02-05 14:47:51 +0100394 /* flush the branch target cache */
395 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
396 dsb();
397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398}
399
Russell King603fff52005-06-28 13:40:39 +0100400static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401{
402 const int zero = 0;
403 const unsigned int __tlb_flag = __cpu_tlb_flags;
404
405 kaddr &= PAGE_MASK;
406
407 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100408 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
410 if (tlb_flag(TLB_V3_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100411 asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (tlb_flag(TLB_V4_U_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100413 asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 if (tlb_flag(TLB_V4_D_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100415 asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 if (tlb_flag(TLB_V4_I_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100417 asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100419 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 if (tlb_flag(TLB_V6_U_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100422 asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 if (tlb_flag(TLB_V6_D_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100424 asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 if (tlb_flag(TLB_V6_I_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100426 asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
Catalin Marinas6a0e2432006-03-07 14:42:27 +0000427
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200428 if (tlb_flag(TLB_BTB)) {
Catalin Marinase6a5d662007-02-05 14:47:51 +0100429 /* flush the branch target cache */
430 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
431 dsb();
432 isb();
433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
436/*
437 * flush_pmd_entry
438 *
439 * Flush a PMD entry (word aligned, or double-word aligned) to
440 * RAM if the TLB for the CPU we are running on requires this.
441 * This is typically used when we are creating PMD entries.
442 *
443 * clean_pmd_entry
444 *
445 * Clean (but don't drain the write buffer) if the CPU requires
446 * these operations. This is typically used when we are removing
447 * PMD entries.
448 */
449static inline void flush_pmd_entry(pmd_t *pmd)
450{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 const unsigned int __tlb_flag = __cpu_tlb_flags;
452
453 if (tlb_flag(TLB_DCLEAN))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100454 asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
455 : : "r" (pmd) : "cc");
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200456
457 if (tlb_flag(TLB_L2CLEAN_FR))
458 asm("mcr p15, 1, %0, c15, c9, 1 @ L2 flush_pmd"
459 : : "r" (pmd) : "cc");
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100462 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
465static inline void clean_pmd_entry(pmd_t *pmd)
466{
467 const unsigned int __tlb_flag = __cpu_tlb_flags;
468
469 if (tlb_flag(TLB_DCLEAN))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100470 asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
471 : : "r" (pmd) : "cc");
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200472
473 if (tlb_flag(TLB_L2CLEAN_FR))
474 asm("mcr p15, 1, %0, c15, c9, 1 @ L2 flush_pmd"
475 : : "r" (pmd) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476}
477
478#undef tlb_flag
479#undef always_tlb_flags
480#undef possible_tlb_flags
481
482/*
483 * Convert calls to our calling convention.
484 */
Russell King603fff52005-06-28 13:40:39 +0100485#define local_flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
486#define local_flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
487
488#ifndef CONFIG_SMP
489#define flush_tlb_all local_flush_tlb_all
490#define flush_tlb_mm local_flush_tlb_mm
491#define flush_tlb_page local_flush_tlb_page
492#define flush_tlb_kernel_page local_flush_tlb_kernel_page
493#define flush_tlb_range local_flush_tlb_range
494#define flush_tlb_kernel_range local_flush_tlb_kernel_range
495#else
496extern void flush_tlb_all(void);
497extern void flush_tlb_mm(struct mm_struct *mm);
498extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
499extern void flush_tlb_kernel_page(unsigned long kaddr);
500extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
501extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
502#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504/*
505 * if PG_dcache_dirty is set for the page, we need to ensure that any
506 * cache entries for the kernels virtual memory range are written
507 * back to the page.
508 */
509extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte);
510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511#endif
512
Hyok S. Choi01579032006-02-24 21:41:25 +0000513#endif /* CONFIG_MMU */
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515#endif