xref: /linux/arch/alpha/include/asm/tlbflush.h (revision bb29b957eaaa15be33243550d9ee576c2d601669)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ALPHA_TLBFLUSH_H
3 #define _ALPHA_TLBFLUSH_H
4 
5 #include <linux/mm.h>
6 #include <linux/sched.h>
7 #include <asm/compiler.h>
8 
9 #ifndef __EXTERN_INLINE
10 #define __EXTERN_INLINE extern inline
11 #define __MMU_EXTERN_INLINE
12 #endif
13 
14 extern void __load_new_mm_context(struct mm_struct *);
15 
16 
17 __EXTERN_INLINE void
18 ev5_flush_tlb_current(struct mm_struct *mm)
19 {
20 	__load_new_mm_context(mm);
21 }
22 
23 /* Flush just one page in the current TLB set.  We need to be very
24    careful about the icache here, there is no way to invalidate a
25    specific icache page.  */
26 
27 __EXTERN_INLINE void
28 ev5_flush_tlb_current_page(struct mm_struct * mm,
29 			   struct vm_area_struct *vma,
30 			   unsigned long addr)
31 {
32 	if (vma->vm_flags & VM_EXEC)
33 		__load_new_mm_context(mm);
34 	else
35 		tbi(2, addr);
36 }
37 
38 
39 #define flush_tlb_current	ev5_flush_tlb_current
40 #define flush_tlb_current_page	ev5_flush_tlb_current_page
41 
42 #ifdef __MMU_EXTERN_INLINE
43 #undef __EXTERN_INLINE
44 #undef __MMU_EXTERN_INLINE
45 #endif
46 
47 /* Flush current user mapping.  */
48 static inline void
49 flush_tlb(void)
50 {
51 	flush_tlb_current(current->active_mm);
52 }
53 
54 /* Flush someone else's user mapping.  */
55 static inline void
56 flush_tlb_other(struct mm_struct *mm)
57 {
58 	unsigned long *mmc = &mm->context[smp_processor_id()];
59 	/* Check it's not zero first to avoid cacheline ping pong
60 	   when possible.  */
61 
62 	if (READ_ONCE(*mmc))
63 		WRITE_ONCE(*mmc, 0);
64 }
65 
66 #ifndef CONFIG_SMP
67 /* Flush everything (kernel mapping may also have changed
68    due to vmalloc/vfree).  */
69 static inline void flush_tlb_all(void)
70 {
71 	tbia();
72 }
73 
74 /* Flush a specified user mapping.  */
75 static inline void
76 flush_tlb_mm(struct mm_struct *mm)
77 {
78 	if (mm == current->active_mm)
79 		flush_tlb_current(mm);
80 	else
81 		flush_tlb_other(mm);
82 }
83 
84 /* Page-granular tlb flush.  */
85 static inline void
86 flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
87 {
88 	struct mm_struct *mm = vma->vm_mm;
89 
90 	/* A targeted tbi() needs a thread of MM to be current.  */
91 	if (mm == current->mm)
92 		flush_tlb_current_page(mm, vma, addr);
93 	else
94 		flush_tlb_other(mm);
95 }
96 
97 /* Flush a specified range of user mapping.  On the Alpha we flush
98    the whole user tlb.  */
99 static inline void
100 flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
101 		unsigned long end)
102 {
103 	flush_tlb_mm(vma->vm_mm);
104 }
105 
106 #else /* CONFIG_SMP */
107 
108 extern void flush_tlb_all(void);
109 extern void flush_tlb_mm(struct mm_struct *);
110 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
111 extern void flush_tlb_range(struct vm_area_struct *, unsigned long,
112 			    unsigned long);
113 
114 #endif /* CONFIG_SMP */
115 
116 static inline void flush_tlb_kernel_range(unsigned long start,
117 					unsigned long end)
118 {
119 	flush_tlb_all();
120 }
121 
122 #endif /* _ALPHA_TLBFLUSH_H */
123