1
2
3
4
5
6
7
8
9
10#ifndef _ASMARM_TLBFLUSH_H
11#define _ASMARM_TLBFLUSH_H
12
13#ifdef CONFIG_MMU
14
15#include <asm/glue.h>
16
17#define TLB_V4_U_PAGE (1 << 1)
18#define TLB_V4_D_PAGE (1 << 2)
19#define TLB_V4_I_PAGE (1 << 3)
20#define TLB_V6_U_PAGE (1 << 4)
21#define TLB_V6_D_PAGE (1 << 5)
22#define TLB_V6_I_PAGE (1 << 6)
23
24#define TLB_V4_U_FULL (1 << 9)
25#define TLB_V4_D_FULL (1 << 10)
26#define TLB_V4_I_FULL (1 << 11)
27#define TLB_V6_U_FULL (1 << 12)
28#define TLB_V6_D_FULL (1 << 13)
29#define TLB_V6_I_FULL (1 << 14)
30
31#define TLB_V6_U_ASID (1 << 16)
32#define TLB_V6_D_ASID (1 << 17)
33#define TLB_V6_I_ASID (1 << 18)
34
35#define TLB_V6_BP (1 << 19)
36
37
38#define TLB_V7_UIS_PAGE (1 << 20)
39#define TLB_V7_UIS_FULL (1 << 21)
40#define TLB_V7_UIS_ASID (1 << 22)
41#define TLB_V7_UIS_BP (1 << 23)
42
43#define TLB_BARRIER (1 << 28)
44#define TLB_L2CLEAN_FR (1 << 29)
45#define TLB_DCLEAN (1 << 30)
46#define TLB_WB (1 << 31)
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61#undef _TLB
62#undef MULTI_TLB
63
64#ifdef CONFIG_SMP_ON_UP
65#define MULTI_TLB 1
66#endif
67
68#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
83#define fa_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
84 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
99#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
116#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
133#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
150#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
151 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 TLB_V6_BP)
155
156#ifdef CONFIG_CPU_TLB_V6
157# define v6wbi_possible_flags v6wbi_tlb_flags
158# define v6wbi_always_flags v6wbi_tlb_flags
159# ifdef _TLB
160# define MULTI_TLB 1
161# else
162# define _TLB v6wbi
163# endif
164#else
165# define v6wbi_possible_flags 0
166# define v6wbi_always_flags (-1UL)
167#endif
168
169#define v7wbi_tlb_flags_smp (TLB_WB | TLB_BARRIER | \
170 TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | \
171 TLB_V7_UIS_ASID | TLB_V7_UIS_BP)
172#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
173 TLB_V6_U_FULL | TLB_V6_U_PAGE | \
174 TLB_V6_U_ASID | TLB_V6_BP)
175
176#ifdef CONFIG_CPU_TLB_V7
177
178# ifdef CONFIG_SMP_ON_UP
179# define v7wbi_possible_flags (v7wbi_tlb_flags_smp | v7wbi_tlb_flags_up)
180# define v7wbi_always_flags (v7wbi_tlb_flags_smp & v7wbi_tlb_flags_up)
181# elif defined(CONFIG_SMP)
182# define v7wbi_possible_flags v7wbi_tlb_flags_smp
183# define v7wbi_always_flags v7wbi_tlb_flags_smp
184# else
185# define v7wbi_possible_flags v7wbi_tlb_flags_up
186# define v7wbi_always_flags v7wbi_tlb_flags_up
187# endif
188# ifdef _TLB
189# define MULTI_TLB 1
190# else
191# define _TLB v7wbi
192# endif
193#else
194# define v7wbi_possible_flags 0
195# define v7wbi_always_flags (-1UL)
196#endif
197
198#ifndef _TLB
199#error Unknown TLB model
200#endif
201
202#ifndef __ASSEMBLY__
203
204#include <linux/sched.h>
205
206struct cpu_tlb_fns {
207 void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
208 void (*flush_kern_range)(unsigned long, unsigned long);
209 unsigned long tlb_flags;
210};
211
212
213
214
215#ifdef MULTI_TLB
216
217#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range
218#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range
219
220#else
221
222#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range)
223#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range)
224
225extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
226extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
227
228#endif
229
230extern struct cpu_tlb_fns cpu_tlb;
231
232#define __cpu_tlb_flags cpu_tlb.tlb_flags
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289#define possible_tlb_flags (v4_possible_flags | \
290 v4wbi_possible_flags | \
291 fr_possible_flags | \
292 v4wb_possible_flags | \
293 fa_possible_flags | \
294 v6wbi_possible_flags | \
295 v7wbi_possible_flags)
296
297#define always_tlb_flags (v4_always_flags & \
298 v4wbi_always_flags & \
299 fr_always_flags & \
300 v4wb_always_flags & \
301 fa_always_flags & \
302 v6wbi_always_flags & \
303 v7wbi_always_flags)
304
305#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
306
307#define __tlb_op(f, insnarg, arg) \
308 do { \
309 if (always_tlb_flags & (f)) \
310 asm("mcr " insnarg \
311 : : "r" (arg) : "cc"); \
312 else if (possible_tlb_flags & (f)) \
313 asm("tst %1, %2\n\t" \
314 "mcrne " insnarg \
315 : : "r" (arg), "r" (__tlb_flag), "Ir" (f) \
316 : "cc"); \
317 } while (0)
318
319#define tlb_op(f, regs, arg) __tlb_op(f, "p15, 0, %0, " regs, arg)
320#define tlb_l2_op(f, regs, arg) __tlb_op(f, "p15, 1, %0, " regs, arg)
321
322static inline void __local_flush_tlb_all(void)
323{
324 const int zero = 0;
325 const unsigned int __tlb_flag = __cpu_tlb_flags;
326
327 tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero);
328 tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero);
329 tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero);
330}
331
332static inline void local_flush_tlb_all(void)
333{
334 const int zero = 0;
335 const unsigned int __tlb_flag = __cpu_tlb_flags;
336
337 if (tlb_flag(TLB_WB))
338 dsb(nshst);
339
340 __local_flush_tlb_all();
341 tlb_op(TLB_V7_UIS_FULL, "c8, c7, 0", zero);
342
343 if (tlb_flag(TLB_BARRIER)) {
344 dsb(nsh);
345 isb();
346 }
347}
348
349static inline void __flush_tlb_all(void)
350{
351 const int zero = 0;
352 const unsigned int __tlb_flag = __cpu_tlb_flags;
353
354 if (tlb_flag(TLB_WB))
355 dsb(ishst);
356
357 __local_flush_tlb_all();
358 tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero);
359
360 if (tlb_flag(TLB_BARRIER)) {
361 dsb(ish);
362 isb();
363 }
364}
365
366static inline void __local_flush_tlb_mm(struct mm_struct *mm)
367{
368 const int zero = 0;
369 const int asid = ASID(mm);
370 const unsigned int __tlb_flag = __cpu_tlb_flags;
371
372 if (possible_tlb_flags & (TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
373 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) {
374 tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero);
375 tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero);
376 tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero);
377 }
378 }
379
380 tlb_op(TLB_V6_U_ASID, "c8, c7, 2", asid);
381 tlb_op(TLB_V6_D_ASID, "c8, c6, 2", asid);
382 tlb_op(TLB_V6_I_ASID, "c8, c5, 2", asid);
383}
384
385static inline void local_flush_tlb_mm(struct mm_struct *mm)
386{
387 const int asid = ASID(mm);
388 const unsigned int __tlb_flag = __cpu_tlb_flags;
389
390 if (tlb_flag(TLB_WB))
391 dsb(nshst);
392
393 __local_flush_tlb_mm(mm);
394 tlb_op(TLB_V7_UIS_ASID, "c8, c7, 2", asid);
395
396 if (tlb_flag(TLB_BARRIER))
397 dsb(nsh);
398}
399
400static inline void __flush_tlb_mm(struct mm_struct *mm)
401{
402 const unsigned int __tlb_flag = __cpu_tlb_flags;
403
404 if (tlb_flag(TLB_WB))
405 dsb(ishst);
406
407 __local_flush_tlb_mm(mm);
408#ifdef CONFIG_ARM_ERRATA_720789
409 tlb_op(TLB_V7_UIS_ASID, "c8, c3, 0", 0);
410#else
411 tlb_op(TLB_V7_UIS_ASID, "c8, c3, 2", ASID(mm));
412#endif
413
414 if (tlb_flag(TLB_BARRIER))
415 dsb(ish);
416}
417
418static inline void
419__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
420{
421 const int zero = 0;
422 const unsigned int __tlb_flag = __cpu_tlb_flags;
423
424 uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
425
426 if (possible_tlb_flags & (TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
427 cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
428 tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr);
429 tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", uaddr);
430 tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", uaddr);
431 if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
432 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
433 }
434
435 tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", uaddr);
436 tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", uaddr);
437 tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", uaddr);
438}
439
440static inline void
441local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
442{
443 const unsigned int __tlb_flag = __cpu_tlb_flags;
444
445 uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
446
447 if (tlb_flag(TLB_WB))
448 dsb(nshst);
449
450 __local_flush_tlb_page(vma, uaddr);
451 tlb_op(TLB_V7_UIS_PAGE, "c8, c7, 1", uaddr);
452
453 if (tlb_flag(TLB_BARRIER))
454 dsb(nsh);
455}
456
457static inline void
458__flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
459{
460 const unsigned int __tlb_flag = __cpu_tlb_flags;
461
462 uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
463
464 if (tlb_flag(TLB_WB))
465 dsb(ishst);
466
467 __local_flush_tlb_page(vma, uaddr);
468#ifdef CONFIG_ARM_ERRATA_720789
469 tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK);
470#else
471 tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", uaddr);
472#endif
473
474 if (tlb_flag(TLB_BARRIER))
475 dsb(ish);
476}
477
478static inline void __local_flush_tlb_kernel_page(unsigned long kaddr)
479{
480 const int zero = 0;
481 const unsigned int __tlb_flag = __cpu_tlb_flags;
482
483 tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr);
484 tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr);
485 tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr);
486 if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
487 asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
488
489 tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", kaddr);
490 tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", kaddr);
491 tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", kaddr);
492}
493
494static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
495{
496 const unsigned int __tlb_flag = __cpu_tlb_flags;
497
498 kaddr &= PAGE_MASK;
499
500 if (tlb_flag(TLB_WB))
501 dsb(nshst);
502
503 __local_flush_tlb_kernel_page(kaddr);
504 tlb_op(TLB_V7_UIS_PAGE, "c8, c7, 1", kaddr);
505
506 if (tlb_flag(TLB_BARRIER)) {
507 dsb(nsh);
508 isb();
509 }
510}
511
512static inline void __flush_tlb_kernel_page(unsigned long kaddr)
513{
514 const unsigned int __tlb_flag = __cpu_tlb_flags;
515
516 kaddr &= PAGE_MASK;
517
518 if (tlb_flag(TLB_WB))
519 dsb(ishst);
520
521 __local_flush_tlb_kernel_page(kaddr);
522 tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr);
523
524 if (tlb_flag(TLB_BARRIER)) {
525 dsb(ish);
526 isb();
527 }
528}
529
530
531
532
533
534static inline void __local_flush_bp_all(void)
535{
536 const int zero = 0;
537 const unsigned int __tlb_flag = __cpu_tlb_flags;
538
539 if (tlb_flag(TLB_V6_BP))
540 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero));
541}
542
543static inline void local_flush_bp_all(void)
544{
545 const int zero = 0;
546 const unsigned int __tlb_flag = __cpu_tlb_flags;
547
548 __local_flush_bp_all();
549 if (tlb_flag(TLB_V7_UIS_BP))
550 asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero));
551}
552
553static inline void __flush_bp_all(void)
554{
555 const int zero = 0;
556 const unsigned int __tlb_flag = __cpu_tlb_flags;
557
558 __local_flush_bp_all();
559 if (tlb_flag(TLB_V7_UIS_BP))
560 asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero));
561}
562
563#include <asm/cputype.h>
564#ifdef CONFIG_ARM_ERRATA_798181
565static inline int erratum_a15_798181(void)
566{
567 unsigned int midr = read_cpuid_id();
568
569
570 if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
571 return 0;
572 return 1;
573}
574
575static inline void dummy_flush_tlb_a15_erratum(void)
576{
577
578
579
580 asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0));
581 dsb(ish);
582}
583#else
584static inline int erratum_a15_798181(void)
585{
586 return 0;
587}
588
589static inline void dummy_flush_tlb_a15_erratum(void)
590{
591}
592#endif
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607static inline void flush_pmd_entry(void *pmd)
608{
609 const unsigned int __tlb_flag = __cpu_tlb_flags;
610
611 tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd);
612 tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd);
613
614 if (tlb_flag(TLB_WB))
615 dsb(ishst);
616}
617
618static inline void clean_pmd_entry(void *pmd)
619{
620 const unsigned int __tlb_flag = __cpu_tlb_flags;
621
622 tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd);
623 tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd);
624}
625
626#undef tlb_op
627#undef tlb_flag
628#undef always_tlb_flags
629#undef possible_tlb_flags
630
631
632
633
634#define local_flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
635#define local_flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
636
637#ifndef CONFIG_SMP
638#define flush_tlb_all local_flush_tlb_all
639#define flush_tlb_mm local_flush_tlb_mm
640#define flush_tlb_page local_flush_tlb_page
641#define flush_tlb_kernel_page local_flush_tlb_kernel_page
642#define flush_tlb_range local_flush_tlb_range
643#define flush_tlb_kernel_range local_flush_tlb_kernel_range
644#define flush_bp_all local_flush_bp_all
645#else
646extern void flush_tlb_all(void);
647extern void flush_tlb_mm(struct mm_struct *mm);
648extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
649extern void flush_tlb_kernel_page(unsigned long kaddr);
650extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
651extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
652extern void flush_bp_all(void);
653#endif
654
655
656
657
658
659
660
661#if __LINUX_ARM_ARCH__ < 6
662extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
663 pte_t *ptep);
664#else
665static inline void update_mmu_cache(struct vm_area_struct *vma,
666 unsigned long addr, pte_t *ptep)
667{
668}
669#endif
670
671#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
672
673#endif
674
675#elif defined(CONFIG_SMP)
676
677#ifndef __ASSEMBLY__
678
679#include <linux/mm_types.h>
680
681static inline void local_flush_tlb_all(void) { }
682static inline void local_flush_tlb_mm(struct mm_struct *mm) { }
683static inline void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) { }
684static inline void local_flush_tlb_kernel_page(unsigned long kaddr) { }
685static inline void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { }
686static inline void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) { }
687static inline void local_flush_bp_all(void) { }
688
689extern void flush_tlb_all(void);
690extern void flush_tlb_mm(struct mm_struct *mm);
691extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
692extern void flush_tlb_kernel_page(unsigned long kaddr);
693extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
694extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
695extern void flush_bp_all(void);
696#endif
697
698#endif
699
700#endif
701