blob: 6e924d3a77ebc168cb8359e7cf79f21b8890146d [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
Russell King58e9c472011-02-20 12:27:49 +000013#ifdef CONFIG_MMU
Hyok S. Choi01579032006-02-24 21:41:25 +000014
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <asm/glue.h>
16
17#define TLB_V3_PAGE (1 << 0)
18#define TLB_V4_U_PAGE (1 << 1)
19#define TLB_V4_D_PAGE (1 << 2)
20#define TLB_V4_I_PAGE (1 << 3)
21#define TLB_V6_U_PAGE (1 << 4)
22#define TLB_V6_D_PAGE (1 << 5)
23#define TLB_V6_I_PAGE (1 << 6)
24
25#define TLB_V3_FULL (1 << 8)
26#define TLB_V4_U_FULL (1 << 9)
27#define TLB_V4_D_FULL (1 << 10)
28#define TLB_V4_I_FULL (1 << 11)
29#define TLB_V6_U_FULL (1 << 12)
30#define TLB_V6_D_FULL (1 << 13)
31#define TLB_V6_I_FULL (1 << 14)
32
33#define TLB_V6_U_ASID (1 << 16)
34#define TLB_V6_D_ASID (1 << 17)
35#define TLB_V6_I_ASID (1 << 18)
36
Catalin Marinasfaa7bc52009-05-30 14:00:14 +010037/* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */
38#define TLB_V7_UIS_PAGE (1 << 19)
39#define TLB_V7_UIS_FULL (1 << 20)
40#define TLB_V7_UIS_ASID (1 << 21)
41
Russell King43488102011-07-05 09:01:13 +010042#define TLB_BARRIER (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)
Russell King43488102011-07-05 09:01:13 +010057 * fa - Faraday (v4 with write buffer with UTLB)
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
Russell Kingf00ec482010-09-04 10:47:48 +010064#ifdef CONFIG_SMP_ON_UP
65#define MULTI_TLB 1
66#endif
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#define v4_tlb_flags (TLB_V4_U_FULL | TLB_V4_U_PAGE)
69
70#ifdef CONFIG_CPU_TLB_V4WT
71# define v4_possible_flags v4_tlb_flags
72# define v4_always_flags v4_tlb_flags
73# ifdef _TLB
74# define MULTI_TLB 1
75# else
76# define _TLB v4
77# endif
78#else
79# define v4_possible_flags 0
80# define v4_always_flags (-1UL)
81#endif
82
Russell King43488102011-07-05 09:01:13 +010083#define fa_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
Paulius Zaleckas28853ac2009-03-25 13:10:01 +020084 TLB_V4_U_FULL | TLB_V4_U_PAGE)
85
86#ifdef CONFIG_CPU_TLB_FA
87# define fa_possible_flags fa_tlb_flags
88# define fa_always_flags fa_tlb_flags
89# ifdef _TLB
90# define MULTI_TLB 1
91# else
92# define _TLB fa
93# endif
94#else
95# define fa_possible_flags 0
96# define fa_always_flags (-1UL)
97#endif
98
Linus Torvalds1da177e2005-04-16 15:20:36 -070099#define v4wbi_tlb_flags (TLB_WB | TLB_DCLEAN | \
100 TLB_V4_I_FULL | TLB_V4_D_FULL | \
101 TLB_V4_I_PAGE | TLB_V4_D_PAGE)
102
103#ifdef CONFIG_CPU_TLB_V4WBI
104# define v4wbi_possible_flags v4wbi_tlb_flags
105# define v4wbi_always_flags v4wbi_tlb_flags
106# ifdef _TLB
107# define MULTI_TLB 1
108# else
109# define _TLB v4wbi
110# endif
111#else
112# define v4wbi_possible_flags 0
113# define v4wbi_always_flags (-1UL)
114#endif
115
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200116#define fr_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_L2CLEAN_FR | \
117 TLB_V4_I_FULL | TLB_V4_D_FULL | \
118 TLB_V4_I_PAGE | TLB_V4_D_PAGE)
119
120#ifdef CONFIG_CPU_TLB_FEROCEON
121# define fr_possible_flags fr_tlb_flags
122# define fr_always_flags fr_tlb_flags
123# ifdef _TLB
124# define MULTI_TLB 1
125# else
126# define _TLB v4wbi
127# endif
128#else
129# define fr_possible_flags 0
130# define fr_always_flags (-1UL)
131#endif
132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133#define v4wb_tlb_flags (TLB_WB | TLB_DCLEAN | \
134 TLB_V4_I_FULL | TLB_V4_D_FULL | \
135 TLB_V4_D_PAGE)
136
137#ifdef CONFIG_CPU_TLB_V4WB
138# define v4wb_possible_flags v4wb_tlb_flags
139# define v4wb_always_flags v4wb_tlb_flags
140# ifdef _TLB
141# define MULTI_TLB 1
142# else
143# define _TLB v4wb
144# endif
145#else
146# define v4wb_possible_flags 0
147# define v4wb_always_flags (-1UL)
148#endif
149
Russell King43488102011-07-05 09:01:13 +0100150#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 TLB_V6_I_FULL | TLB_V6_D_FULL | \
152 TLB_V6_I_PAGE | TLB_V6_D_PAGE | \
153 TLB_V6_I_ASID | TLB_V6_D_ASID)
154
155#ifdef CONFIG_CPU_TLB_V6
156# define v6wbi_possible_flags v6wbi_tlb_flags
157# define v6wbi_always_flags v6wbi_tlb_flags
158# ifdef _TLB
159# define MULTI_TLB 1
160# else
161# define _TLB v6wbi
162# endif
163#else
164# define v6wbi_possible_flags 0
165# define v6wbi_always_flags (-1UL)
166#endif
167
Russell King43488102011-07-05 09:01:13 +0100168#define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100169 TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
Russell King43488102011-07-05 09:01:13 +0100170#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100171 TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID)
Catalin Marinasfaa7bc52009-05-30 14:00:14 +0100172
Catalin Marinas2ccdd1e2007-05-18 11:25:31 +0100173#ifdef CONFIG_CPU_TLB_V7
Russell Kingf00ec482010-09-04 10:47:48 +0100174
175# ifdef CONFIG_SMP_ON_UP
176# define v7wbi_possible_flags (v7wbi_tlb_flags_smp | v7wbi_tlb_flags_up)
177# define v7wbi_always_flags (v7wbi_tlb_flags_smp & v7wbi_tlb_flags_up)
178# elif defined(CONFIG_SMP)
179# define v7wbi_possible_flags v7wbi_tlb_flags_smp
180# define v7wbi_always_flags v7wbi_tlb_flags_smp
181# else
182# define v7wbi_possible_flags v7wbi_tlb_flags_up
183# define v7wbi_always_flags v7wbi_tlb_flags_up
184# endif
Catalin Marinas2ccdd1e2007-05-18 11:25:31 +0100185# ifdef _TLB
186# define MULTI_TLB 1
187# else
188# define _TLB v7wbi
189# endif
190#else
191# define v7wbi_possible_flags 0
192# define v7wbi_always_flags (-1UL)
193#endif
194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195#ifndef _TLB
196#error Unknown TLB model
197#endif
198
199#ifndef __ASSEMBLY__
200
Alexey Dobriyane8edc6e2007-05-21 01:22:52 +0400201#include <linux/sched.h>
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203struct cpu_tlb_fns {
204 void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
205 void (*flush_kern_range)(unsigned long, unsigned long);
206 unsigned long tlb_flags;
207};
208
209/*
210 * Select the calling method
211 */
212#ifdef MULTI_TLB
213
214#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range
215#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range
216
217#else
218
219#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range)
220#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range)
221
222extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
223extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
224
225#endif
226
227extern struct cpu_tlb_fns cpu_tlb;
228
229#define __cpu_tlb_flags cpu_tlb.tlb_flags
230
231/*
232 * TLB Management
233 * ==============
234 *
235 * The arch/arm/mm/tlb-*.S files implement these methods.
236 *
237 * The TLB specific code is expected to perform whatever tests it
238 * needs to determine if it should invalidate the TLB for each
239 * call. Start addresses are inclusive and end addresses are
240 * exclusive; it is safe to round these addresses down.
241 *
242 * flush_tlb_all()
243 *
244 * Invalidate the entire TLB.
245 *
246 * flush_tlb_mm(mm)
247 *
248 * Invalidate all TLB entries in a particular address
249 * space.
250 * - mm - mm_struct describing address space
251 *
252 * flush_tlb_range(mm,start,end)
253 *
254 * Invalidate a range of TLB entries in the specified
255 * address space.
256 * - mm - mm_struct describing address space
257 * - start - start address (may not be aligned)
258 * - end - end address (exclusive, may not be aligned)
259 *
260 * flush_tlb_page(vaddr,vma)
261 *
262 * Invalidate the specified page in the specified address range.
263 * - vaddr - virtual address (may not be aligned)
264 * - vma - vma_struct describing address range
265 *
266 * flush_kern_tlb_page(kaddr)
267 *
268 * Invalidate the TLB entry for the specified page. The address
269 * will be in the kernels virtual memory space. Current uses
270 * only require the D-TLB to be invalidated.
271 * - kaddr - Kernel virtual memory address
272 */
273
274/*
275 * We optimise the code below by:
276 * - building a set of TLB flags that might be set in __cpu_tlb_flags
277 * - building a set of TLB flags that will always be set in __cpu_tlb_flags
278 * - if we're going to need __cpu_tlb_flags, access it once and only once
279 *
280 * This allows us to build optimal assembly for the single-CPU type case,
281 * and as close to optimal given the compiler constrants for multi-CPU
282 * case. We could do better for the multi-CPU case if the compiler
283 * implemented the "%?" method, but this has been discontinued due to too
284 * many people getting it wrong.
285 */
Russell King357c9c12012-05-04 12:04:26 +0100286#define possible_tlb_flags (v4_possible_flags | \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 v4wbi_possible_flags | \
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200288 fr_possible_flags | \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 v4wb_possible_flags | \
Paulius Zaleckas28853ac2009-03-25 13:10:01 +0200290 fa_possible_flags | \
Paul Walmsley61db7fb2008-08-12 00:04:15 +0100291 v6wbi_possible_flags | \
292 v7wbi_possible_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Russell King357c9c12012-05-04 12:04:26 +0100294#define always_tlb_flags (v4_always_flags & \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 v4wbi_always_flags & \
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200296 fr_always_flags & \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 v4wb_always_flags & \
Paulius Zaleckas28853ac2009-03-25 13:10:01 +0200298 fa_always_flags & \
Paul Walmsley61db7fb2008-08-12 00:04:15 +0100299 v6wbi_always_flags & \
300 v7wbi_always_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
303
Russell King87067a92012-02-04 10:55:38 +0000304#define __tlb_op(f, insnarg, arg) \
305 do { \
306 if (always_tlb_flags & (f)) \
307 asm("mcr " insnarg \
308 : : "r" (arg) : "cc"); \
309 else if (possible_tlb_flags & (f)) \
310 asm("tst %1, %2\n\t" \
311 "mcrne " insnarg \
312 : : "r" (arg), "r" (__tlb_flag), "Ir" (f) \
313 : "cc"); \
314 } while (0)
315
316#define tlb_op(f, regs, arg) __tlb_op(f, "p15, 0, %0, " regs, arg)
317#define tlb_l2_op(f, regs, arg) __tlb_op(f, "p15, 1, %0, " regs, arg)
318
Russell King603fff52005-06-28 13:40:39 +0100319static inline void local_flush_tlb_all(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 const int zero = 0;
322 const unsigned int __tlb_flag = __cpu_tlb_flags;
323
324 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100325 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Russell King87067a92012-02-04 10:55:38 +0000327 tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
328 tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero);
329 tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero);
330 tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero);
331 tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero);
Catalin Marinase6a5d662007-02-05 14:47:51 +0100332
Russell King43488102011-07-05 09:01:13 +0100333 if (tlb_flag(TLB_BARRIER)) {
Catalin Marinasb8349b52010-05-07 18:03:05 +0100334 dsb();
335 isb();
336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337}
338
Russell King603fff52005-06-28 13:40:39 +0100339static inline void local_flush_tlb_mm(struct mm_struct *mm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
341 const int zero = 0;
342 const int asid = ASID(mm);
343 const unsigned int __tlb_flag = __cpu_tlb_flags;
344
345 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100346 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Russell King87067a92012-02-04 10:55:38 +0000348 if (possible_tlb_flags & (TLB_V3_FULL|TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
349 if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
350 tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
351 tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero);
352 tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero);
353 tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero);
354 }
355 put_cpu();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
357
Russell King87067a92012-02-04 10:55:38 +0000358 tlb_op(TLB_V6_U_ASID, "c8, c7, 2", asid);
359 tlb_op(TLB_V6_D_ASID, "c8, c6, 2", asid);
360 tlb_op(TLB_V6_I_ASID, "c8, c5, 2", asid);
Will Deaconcdf357f2010-08-05 11:20:51 +0100361#ifdef CONFIG_ARM_ERRATA_720789
Russell King87067a92012-02-04 10:55:38 +0000362 tlb_op(TLB_V7_UIS_ASID, "c8, c3, 0", zero);
Will Deaconcdf357f2010-08-05 11:20:51 +0100363#else
Russell King87067a92012-02-04 10:55:38 +0000364 tlb_op(TLB_V7_UIS_ASID, "c8, c3, 2", asid);
Will Deaconcdf357f2010-08-05 11:20:51 +0100365#endif
Catalin Marinase6a5d662007-02-05 14:47:51 +0100366
Russell King43488102011-07-05 09:01:13 +0100367 if (tlb_flag(TLB_BARRIER))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100368 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369}
370
371static inline void
Russell King603fff52005-06-28 13:40:39 +0100372local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 const int zero = 0;
375 const unsigned int __tlb_flag = __cpu_tlb_flags;
376
377 uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
378
379 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100380 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Russell King87067a92012-02-04 10:55:38 +0000382 if (possible_tlb_flags & (TLB_V3_PAGE|TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
383 cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
384 tlb_op(TLB_V3_PAGE, "c6, c0, 0", uaddr);
385 tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr);
386 tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", uaddr);
387 tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", uaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100389 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 }
391
Russell King87067a92012-02-04 10:55:38 +0000392 tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", uaddr);
393 tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", uaddr);
394 tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", uaddr);
Will Deaconcdf357f2010-08-05 11:20:51 +0100395#ifdef CONFIG_ARM_ERRATA_720789
Russell King87067a92012-02-04 10:55:38 +0000396 tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK);
Will Deaconcdf357f2010-08-05 11:20:51 +0100397#else
Russell King87067a92012-02-04 10:55:38 +0000398 tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", uaddr);
Will Deaconcdf357f2010-08-05 11:20:51 +0100399#endif
Catalin Marinase6a5d662007-02-05 14:47:51 +0100400
Russell King43488102011-07-05 09:01:13 +0100401 if (tlb_flag(TLB_BARRIER))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100402 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
Russell King603fff52005-06-28 13:40:39 +0100405static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
407 const int zero = 0;
408 const unsigned int __tlb_flag = __cpu_tlb_flags;
409
410 kaddr &= PAGE_MASK;
411
412 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100413 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Russell King87067a92012-02-04 10:55:38 +0000415 tlb_op(TLB_V3_PAGE, "c6, c0, 0", kaddr);
416 tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr);
417 tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr);
418 tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
Daniel Jacobowitz6a39dd62006-08-30 15:02:08 +0100420 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Russell King87067a92012-02-04 10:55:38 +0000422 tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", kaddr);
423 tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", kaddr);
424 tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", kaddr);
425 tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr);
Catalin Marinas6a0e2432006-03-07 14:42:27 +0000426
Russell King43488102011-07-05 09:01:13 +0100427 if (tlb_flag(TLB_BARRIER)) {
Catalin Marinasb8349b52010-05-07 18:03:05 +0100428 dsb();
429 isb();
430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431}
432
433/*
434 * flush_pmd_entry
435 *
436 * Flush a PMD entry (word aligned, or double-word aligned) to
437 * RAM if the TLB for the CPU we are running on requires this.
438 * This is typically used when we are creating PMD entries.
439 *
440 * clean_pmd_entry
441 *
442 * Clean (but don't drain the write buffer) if the CPU requires
443 * these operations. This is typically used when we are removing
444 * PMD entries.
445 */
Catalin Marinas442e70c2011-09-05 17:51:56 +0100446static inline void flush_pmd_entry(void *pmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 const unsigned int __tlb_flag = __cpu_tlb_flags;
449
Russell King87067a92012-02-04 10:55:38 +0000450 tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd);
451 tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd);
Lennert Buytenhek99c6dc12008-06-22 22:45:04 +0200452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 if (tlb_flag(TLB_WB))
Catalin Marinase6a5d662007-02-05 14:47:51 +0100454 dsb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455}
456
Catalin Marinas442e70c2011-09-05 17:51:56 +0100457static inline void clean_pmd_entry(void *pmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 const unsigned int __tlb_flag = __cpu_tlb_flags;
460
Russell King87067a92012-02-04 10:55:38 +0000461 tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd);
462 tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
Russell King87067a92012-02-04 10:55:38 +0000465#undef tlb_op
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466#undef tlb_flag
467#undef always_tlb_flags
468#undef possible_tlb_flags
469
470/*
471 * Convert calls to our calling convention.
472 */
Russell King603fff52005-06-28 13:40:39 +0100473#define local_flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
474#define local_flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
475
476#ifndef CONFIG_SMP
477#define flush_tlb_all local_flush_tlb_all
478#define flush_tlb_mm local_flush_tlb_mm
479#define flush_tlb_page local_flush_tlb_page
480#define flush_tlb_kernel_page local_flush_tlb_kernel_page
481#define flush_tlb_range local_flush_tlb_range
482#define flush_tlb_kernel_range local_flush_tlb_kernel_range
483#else
484extern void flush_tlb_all(void);
485extern void flush_tlb_mm(struct mm_struct *mm);
486extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
487extern void flush_tlb_kernel_page(unsigned long kaddr);
488extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
489extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
490#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492/*
Catalin Marinasc0177802010-09-13 15:57:36 +0100493 * If PG_dcache_clean is not set for the page, we need to ensure that any
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 * cache entries for the kernels virtual memory range are written
Catalin Marinas60121912010-09-13 15:58:06 +0100495 * back to the page. On ARMv6 and later, the cache coherency is handled via
496 * the set_pte_at() function.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 */
Catalin Marinas60121912010-09-13 15:58:06 +0100498#if __LINUX_ARM_ARCH__ < 6
Russell King4b3073e2009-12-18 16:40:18 +0000499extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
500 pte_t *ptep);
Catalin Marinas60121912010-09-13 15:58:06 +0100501#else
502static inline void update_mmu_cache(struct vm_area_struct *vma,
503 unsigned long addr, pte_t *ptep)
504{
505}
506#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508#endif
509
Hyok S. Choi01579032006-02-24 21:41:25 +0000510#endif /* CONFIG_MMU */
511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512#endif