blob: 9ad329ad74586a4f09e20f9135cdbda94e4c839a [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)
Catalin Marinasfaa7bc52009-05-30 14:00:14 +010043
44/* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */
45#define TLB_V7_UIS_PAGE (1 << 19)
46#define TLB_V7_UIS_FULL (1 << 20)
47#define TLB_V7_UIS_ASID (1 << 21)
48
Catalin Marinasb8349b52010-05-07 18:03:05 +010049/* Inner Shareable BTB operation (ARMv7 MP extensions) */
50#define TLB_V7_IS_BTB (1 << 22)
51
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +020052#define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define TLB_DCLEAN (1 << 30)
54#define TLB_WB (1 << 31)
55
56/*
57 * MMU TLB Model
58 * =============
59 *
60 * We have the following to choose from:
61 * v3 - ARMv3
62 * v4 - ARMv4 without write buffer
63 * v4wb - ARMv4 with write buffer without I TLB flush entry instruction
64 * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +020065 * fr - Feroceon (v4wbi with non-outer-cacheable page table walks)
Paulius Zaleckas28853ac2009-03-25 13:10:01 +020066 * fa - Faraday (v4 with write buffer with UTLB and branch target buffer (BTB))
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 * v6wbi - ARMv6 with write buffer with I TLB flush entry instruction
Paul Walmsley61db7fb2008-08-12 00:04:15 +010068 * v7wbi - identical to v6wbi
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 */
70#undef _TLB
71#undef MULTI_TLB
72
73#define v3_tlb_flags (TLB_V3_FULL | TLB_V3_PAGE)
74
75#ifdef CONFIG_CPU_TLB_V3
76# define v3_possible_flags v3_tlb_flags
77# define v3_always_flags v3_tlb_flags
78# ifdef _TLB
79# define MULTI_TLB 1
80# else
81# define _TLB v3
82# endif
83#else
84# define v3_possible_flags 0
85# define v3_always_flags (-1UL)
86#endif
87
88#define v4_tlb_flags (TLB_V4_U_FULL | TLB_V4_U_PAGE)
89
90#ifdef CONFIG_CPU_TLB_V4WT
91# define v4_possible_flags v4_tlb_flags
92# define v4_always_flags v4_tlb_flags
93# ifdef _TLB
94# define MULTI_TLB 1
95# else
96# define _TLB v4
97# endif
98#else
99# define v4_possible_flags 0
100# define v4_always_flags (-1UL)
101#endif
102
Paulius Zaleckas28853ac2009-03-25 13:10:01 +0200103#define fa_tlb_flags (TLB_WB | TLB_BTB | TLB_DCLEAN | \
104 TLB_V4_U_FULL | TLB_V4_U_PAGE)
105
106#ifdef CONFIG_CPU_TLB_FA
107# define fa_possible_flags fa_tlb_flags
108# define fa_always_flags fa_tlb_flags
109# ifdef _TLB
110# define MULTI_TLB 1
111# else
112# define _TLB fa
113# endif
114#else
115# define fa_possible_flags 0
116# define fa_always_flags (-1UL)
117#endif
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#define v4wbi_tlb_flags (TLB_WB | TLB_DCLEAN | \
120 TLB_V4_I_FULL | TLB_V4_D_FULL | \
121 TLB_V4_I_PAGE | TLB_V4_D_PAGE)
122
123#ifdef CONFIG_CPU_TLB_V4WBI
124# define v4wbi_possible_flags v4wbi_tlb_flags
125# define v4wbi_always_flags v4wbi_tlb_flags
126# ifdef _TLB
127# define MULTI_TLB 1
128# else
129# define _TLB v4wbi
130# endif
131#else
132# define v4wbi_possible_flags 0
133# define v4wbi_always_flags (-1UL)
134#endif
135
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200136#define fr_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_L2CLEAN_FR | \
137 TLB_V4_I_FULL | TLB_V4_D_FULL | \
138 TLB_V4_I_PAGE | TLB_V4_D_PAGE)
139
140#ifdef CONFIG_CPU_TLB_FEROCEON
141# define fr_possible_flags fr_tlb_flags
142# define fr_always_flags fr_tlb_flags
143# ifdef _TLB
144# define MULTI_TLB 1
145# else
146# define _TLB v4wbi
147# endif
148#else
149# define fr_possible_flags 0
150# define fr_always_flags (-1UL)
151#endif
152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153#define v4wb_tlb_flags (TLB_WB | TLB_DCLEAN | \
154 TLB_V4_I_FULL | TLB_V4_D_FULL | \
155 TLB_V4_D_PAGE)
156
157#ifdef CONFIG_CPU_TLB_V4WB
158# define v4wb_possible_flags v4wb_tlb_flags
159# define v4wb_always_flags v4wb_tlb_flags
160# ifdef _TLB
161# define MULTI_TLB 1
162# else
163# define _TLB v4wb
164# endif
165#else
166# define v4wb_possible_flags 0
167# define v4wb_always_flags (-1UL)
168#endif
169
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200170#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 TLB_V6_I_FULL | TLB_V6_D_FULL | \
172 TLB_V6_I_PAGE | TLB_V6_D_PAGE | \
173 TLB_V6_I_ASID | TLB_V6_D_ASID)
174
175#ifdef CONFIG_CPU_TLB_V6
176# define v6wbi_possible_flags v6wbi_tlb_flags
177# define v6wbi_always_flags v6wbi_tlb_flags
178# ifdef _TLB
179# define MULTI_TLB 1
180# else
181# define _TLB v6wbi
182# endif
183#else
184# define v6wbi_possible_flags 0
185# define v6wbi_always_flags (-1UL)
186#endif
187
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100188#ifdef CONFIG_SMP
Catalin Marinasb8349b52010-05-07 18:03:05 +0100189#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100190 TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
191#else
192#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
193 TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID)
194#endif
195
Catalin Marinas2ccdd1e2007-05-18 11:25:31 +0100196#ifdef CONFIG_CPU_TLB_V7
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100197# define v7wbi_possible_flags v7wbi_tlb_flags
198# define v7wbi_always_flags v7wbi_tlb_flags
Catalin Marinas2ccdd1e2007-05-18 11:25:31 +0100199# ifdef _TLB
200# define MULTI_TLB 1
201# else
202# define _TLB v7wbi
203# endif
204#else
205# define v7wbi_possible_flags 0
206# define v7wbi_always_flags (-1UL)
207#endif
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209#ifndef _TLB
210#error Unknown TLB model
211#endif
212
213#ifndef __ASSEMBLY__
214
Alexey Dobriyane8edc6e2007-05-21 01:22:52 +0400215#include <linux/sched.h>
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217struct cpu_tlb_fns {
218 void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
219 void (*flush_kern_range)(unsigned long, unsigned long);
220 unsigned long tlb_flags;
221};
222
223/*
224 * Select the calling method
225 */
226#ifdef MULTI_TLB
227
228#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range
229#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range
230
231#else
232
233#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range)
234#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range)
235
236extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
237extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
238
239#endif
240
241extern struct cpu_tlb_fns cpu_tlb;
242
243#define __cpu_tlb_flags cpu_tlb.tlb_flags
244
245/*
246 * TLB Management
247 * ==============
248 *
249 * The arch/arm/mm/tlb-*.S files implement these methods.
250 *
251 * The TLB specific code is expected to perform whatever tests it
252 * needs to determine if it should invalidate the TLB for each
253 * call. Start addresses are inclusive and end addresses are
254 * exclusive; it is safe to round these addresses down.
255 *
256 * flush_tlb_all()
257 *
258 * Invalidate the entire TLB.
259 *
260 * flush_tlb_mm(mm)
261 *
262 * Invalidate all TLB entries in a particular address
263 * space.
264 * - mm - mm_struct describing address space
265 *
266 * flush_tlb_range(mm,start,end)
267 *
268 * Invalidate a range of TLB entries in the specified
269 * address space.
270 * - mm - mm_struct describing address space
271 * - start - start address (may not be aligned)
272 * - end - end address (exclusive, may not be aligned)
273 *
274 * flush_tlb_page(vaddr,vma)
275 *
276 * Invalidate the specified page in the specified address range.
277 * - vaddr - virtual address (may not be aligned)
278 * - vma - vma_struct describing address range
279 *
280 * flush_kern_tlb_page(kaddr)
281 *
282 * Invalidate the TLB entry for the specified page. The address
283 * will be in the kernels virtual memory space. Current uses
284 * only require the D-TLB to be invalidated.
285 * - kaddr - Kernel virtual memory address
286 */
287
288/*
289 * We optimise the code below by:
290 * - building a set of TLB flags that might be set in __cpu_tlb_flags
291 * - building a set of TLB flags that will always be set in __cpu_tlb_flags
292 * - if we're going to need __cpu_tlb_flags, access it once and only once
293 *
294 * This allows us to build optimal assembly for the single-CPU type case,
295 * and as close to optimal given the compiler constrants for multi-CPU
296 * case. We could do better for the multi-CPU case if the compiler
297 * implemented the "%?" method, but this has been discontinued due to too
298 * many people getting it wrong.
299 */
300#define possible_tlb_flags (v3_possible_flags | \
301 v4_possible_flags | \
302 v4wbi_possible_flags | \
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200303 fr_possible_flags | \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 v4wb_possible_flags | \
Paulius Zaleckas28853ac2009-03-25 13:10:01 +0200305 fa_possible_flags | \
Paul Walmsley61db7fb2008-08-12 00:04:15 +0100306 v6wbi_possible_flags | \
307 v7wbi_possible_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309#define always_tlb_flags (v3_always_flags & \
310 v4_always_flags & \
311 v4wbi_always_flags & \
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200312 fr_always_flags & \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 v4wb_always_flags & \
Paulius Zaleckas28853ac2009-03-25 13:10:01 +0200314 fa_always_flags & \
Paul Walmsley61db7fb2008-08-12 00:04:15 +0100315 v6wbi_always_flags & \
316 v7wbi_always_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
319
Russell King603fff52005-06-28 13:40:39 +0100320static inline void local_flush_tlb_all(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
322 const int zero = 0;
323 const unsigned int __tlb_flag = __cpu_tlb_flags;
324
325 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100326 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 if (tlb_flag(TLB_V3_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100329 asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 if (tlb_flag(TLB_V4_U_FULL | TLB_V6_U_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100331 asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 if (tlb_flag(TLB_V4_D_FULL | TLB_V6_D_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100333 asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100335 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100336 if (tlb_flag(TLB_V7_UIS_FULL))
337 asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
Catalin Marinase6a5d662007-02-05 14:47:51 +0100338
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200339 if (tlb_flag(TLB_BTB)) {
Catalin Marinase6a5d662007-02-05 14:47:51 +0100340 /* flush the branch target cache */
341 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
342 dsb();
343 isb();
344 }
Catalin Marinasb8349b52010-05-07 18:03:05 +0100345 if (tlb_flag(TLB_V7_IS_BTB)) {
346 /* flush the branch target cache */
347 asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc");
348 dsb();
349 isb();
350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351}
352
Russell King603fff52005-06-28 13:40:39 +0100353static inline void local_flush_tlb_mm(struct mm_struct *mm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 const int zero = 0;
356 const int asid = ASID(mm);
357 const unsigned int __tlb_flag = __cpu_tlb_flags;
358
359 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100360 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Santosh Shilimkardaaeb6c2009-10-15 15:06:47 +0100362 if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 if (tlb_flag(TLB_V3_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100364 asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (tlb_flag(TLB_V4_U_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100366 asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 if (tlb_flag(TLB_V4_D_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100368 asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 if (tlb_flag(TLB_V4_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100370 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
Santosh Shilimkardaaeb6c2009-10-15 15:06:47 +0100372 put_cpu();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 if (tlb_flag(TLB_V6_U_ASID))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100375 asm("mcr p15, 0, %0, c8, c7, 2" : : "r" (asid) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 if (tlb_flag(TLB_V6_D_ASID))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100377 asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 if (tlb_flag(TLB_V6_I_ASID))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100379 asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100380 if (tlb_flag(TLB_V7_UIS_ASID))
Will Deaconcdf357f2010-08-05 11:20:51 +0100381#ifdef CONFIG_ARM_ERRATA_720789
382 asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
383#else
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100384 asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc");
Will Deaconcdf357f2010-08-05 11:20:51 +0100385#endif
Catalin Marinase6a5d662007-02-05 14:47:51 +0100386
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200387 if (tlb_flag(TLB_BTB)) {
Catalin Marinase6a5d662007-02-05 14:47:51 +0100388 /* flush the branch target cache */
389 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
390 dsb();
391 }
Catalin Marinasb8349b52010-05-07 18:03:05 +0100392 if (tlb_flag(TLB_V7_IS_BTB)) {
393 /* flush the branch target cache */
394 asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc");
395 dsb();
396 isb();
397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398}
399
400static inline void
Russell King603fff52005-06-28 13:40:39 +0100401local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
403 const int zero = 0;
404 const unsigned int __tlb_flag = __cpu_tlb_flags;
405
406 uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
407
408 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100409 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Rusty Russell56f8ba82009-09-24 09:34:49 -0600411 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (tlb_flag(TLB_V3_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100413 asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 if (tlb_flag(TLB_V4_U_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100415 asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 if (tlb_flag(TLB_V4_D_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100417 asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if (tlb_flag(TLB_V4_I_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100419 asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100421 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 }
423
424 if (tlb_flag(TLB_V6_U_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100425 asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 if (tlb_flag(TLB_V6_D_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100427 asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 if (tlb_flag(TLB_V6_I_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100429 asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100430 if (tlb_flag(TLB_V7_UIS_PAGE))
Will Deaconcdf357f2010-08-05 11:20:51 +0100431#ifdef CONFIG_ARM_ERRATA_720789
432 asm("mcr p15, 0, %0, c8, c3, 3" : : "r" (uaddr & PAGE_MASK) : "cc");
433#else
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100434 asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc");
Will Deaconcdf357f2010-08-05 11:20:51 +0100435#endif
Catalin Marinase6a5d662007-02-05 14:47:51 +0100436
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200437 if (tlb_flag(TLB_BTB)) {
Catalin Marinase6a5d662007-02-05 14:47:51 +0100438 /* flush the branch target cache */
439 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
440 dsb();
441 }
Catalin Marinasb8349b52010-05-07 18:03:05 +0100442 if (tlb_flag(TLB_V7_IS_BTB)) {
443 /* flush the branch target cache */
444 asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc");
445 dsb();
446 isb();
447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448}
449
Russell King603fff52005-06-28 13:40:39 +0100450static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
452 const int zero = 0;
453 const unsigned int __tlb_flag = __cpu_tlb_flags;
454
455 kaddr &= PAGE_MASK;
456
457 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100458 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 if (tlb_flag(TLB_V3_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100461 asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (tlb_flag(TLB_V4_U_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100463 asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 if (tlb_flag(TLB_V4_D_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100465 asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 if (tlb_flag(TLB_V4_I_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100467 asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100469 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
471 if (tlb_flag(TLB_V6_U_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100472 asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 if (tlb_flag(TLB_V6_D_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100474 asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 if (tlb_flag(TLB_V6_I_PAGE))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100476 asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100477 if (tlb_flag(TLB_V7_UIS_PAGE))
478 asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc");
Catalin Marinas6a0e2432006-03-07 14:42:27 +0000479
Paulius Zaleckasbba7d0b2009-03-25 10:58:47 +0200480 if (tlb_flag(TLB_BTB)) {
Catalin Marinase6a5d662007-02-05 14:47:51 +0100481 /* flush the branch target cache */
482 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
483 dsb();
484 isb();
485 }
Catalin Marinasb8349b52010-05-07 18:03:05 +0100486 if (tlb_flag(TLB_V7_IS_BTB)) {
487 /* flush the branch target cache */
488 asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc");
489 dsb();
490 isb();
491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
494/*
495 * flush_pmd_entry
496 *
497 * Flush a PMD entry (word aligned, or double-word aligned) to
498 * RAM if the TLB for the CPU we are running on requires this.
499 * This is typically used when we are creating PMD entries.
500 *
501 * clean_pmd_entry
502 *
503 * Clean (but don't drain the write buffer) if the CPU requires
504 * these operations. This is typically used when we are removing
505 * PMD entries.
506 */
507static inline void flush_pmd_entry(pmd_t *pmd)
508{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 const unsigned int __tlb_flag = __cpu_tlb_flags;
510
511 if (tlb_flag(TLB_DCLEAN))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100512 asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
513 : : "r" (pmd) : "cc");
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200514
515 if (tlb_flag(TLB_L2CLEAN_FR))
516 asm("mcr p15, 1, %0, c15, c9, 1 @ L2 flush_pmd"
517 : : "r" (pmd) : "cc");
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100520 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
523static inline void clean_pmd_entry(pmd_t *pmd)
524{
525 const unsigned int __tlb_flag = __cpu_tlb_flags;
526
527 if (tlb_flag(TLB_DCLEAN))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100528 asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
529 : : "r" (pmd) : "cc");
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200530
531 if (tlb_flag(TLB_L2CLEAN_FR))
532 asm("mcr p15, 1, %0, c15, c9, 1 @ L2 flush_pmd"
533 : : "r" (pmd) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534}
535
536#undef tlb_flag
537#undef always_tlb_flags
538#undef possible_tlb_flags
539
540/*
541 * Convert calls to our calling convention.
542 */
Russell King603fff52005-06-28 13:40:39 +0100543#define local_flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
544#define local_flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
545
546#ifndef CONFIG_SMP
547#define flush_tlb_all local_flush_tlb_all
548#define flush_tlb_mm local_flush_tlb_mm
549#define flush_tlb_page local_flush_tlb_page
550#define flush_tlb_kernel_page local_flush_tlb_kernel_page
551#define flush_tlb_range local_flush_tlb_range
552#define flush_tlb_kernel_range local_flush_tlb_kernel_range
553#else
554extern void flush_tlb_all(void);
555extern void flush_tlb_mm(struct mm_struct *mm);
556extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
557extern void flush_tlb_kernel_page(unsigned long kaddr);
558extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
559extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
560#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562/*
Catalin Marinasc0177802010-09-13 15:57:36 +0100563 * If PG_dcache_clean is not set for the page, we need to ensure that any
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 * cache entries for the kernels virtual memory range are written
565 * back to the page.
566 */
Russell King4b3073e2009-12-18 16:40:18 +0000567extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
568 pte_t *ptep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570#endif
571
Hyok S. Choi01579032006-02-24 21:41:25 +0000572#endif /* CONFIG_MMU */
573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574#endif