diff options
Diffstat (limited to 'arch/powerpc/mm/tlb-radix.c')
-rw-r--r-- | arch/powerpc/mm/tlb-radix.c | 84 |
1 files changed, 63 insertions, 21 deletions
diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c index 54efba2fd66e..ab2f60e812e2 100644 --- a/arch/powerpc/mm/tlb-radix.c +++ b/arch/powerpc/mm/tlb-radix.c | |||
@@ -18,16 +18,20 @@ | |||
18 | 18 | ||
19 | static DEFINE_RAW_SPINLOCK(native_tlbie_lock); | 19 | static DEFINE_RAW_SPINLOCK(native_tlbie_lock); |
20 | 20 | ||
21 | static inline void __tlbiel_pid(unsigned long pid, int set) | 21 | #define RIC_FLUSH_TLB 0 |
22 | #define RIC_FLUSH_PWC 1 | ||
23 | #define RIC_FLUSH_ALL 2 | ||
24 | |||
25 | static inline void __tlbiel_pid(unsigned long pid, int set, | ||
26 | unsigned long ric) | ||
22 | { | 27 | { |
23 | unsigned long rb,rs,ric,prs,r; | 28 | unsigned long rb,rs,prs,r; |
24 | 29 | ||
25 | rb = PPC_BIT(53); /* IS = 1 */ | 30 | rb = PPC_BIT(53); /* IS = 1 */ |
26 | rb |= set << PPC_BITLSHIFT(51); | 31 | rb |= set << PPC_BITLSHIFT(51); |
27 | rs = ((unsigned long)pid) << PPC_BITLSHIFT(31); | 32 | rs = ((unsigned long)pid) << PPC_BITLSHIFT(31); |
28 | prs = 1; /* process scoped */ | 33 | prs = 1; /* process scoped */ |
29 | r = 1; /* raidx format */ | 34 | r = 1; /* raidx format */ |
30 | ric = 2; /* invalidate all the caches */ | ||
31 | 35 | ||
32 | asm volatile("ptesync": : :"memory"); | 36 | asm volatile("ptesync": : :"memory"); |
33 | asm volatile(".long 0x7c000224 | (%0 << 11) | (%1 << 16) |" | 37 | asm volatile(".long 0x7c000224 | (%0 << 11) | (%1 << 16) |" |
@@ -39,25 +43,24 @@ static inline void __tlbiel_pid(unsigned long pid, int set) | |||
39 | /* | 43 | /* |
40 | * We use 128 set in radix mode and 256 set in hpt mode. | 44 | * We use 128 set in radix mode and 256 set in hpt mode. |
41 | */ | 45 | */ |
42 | static inline void _tlbiel_pid(unsigned long pid) | 46 | static inline void _tlbiel_pid(unsigned long pid, unsigned long ric) |
43 | { | 47 | { |
44 | int set; | 48 | int set; |
45 | 49 | ||
46 | for (set = 0; set < POWER9_TLB_SETS_RADIX ; set++) { | 50 | for (set = 0; set < POWER9_TLB_SETS_RADIX ; set++) { |
47 | __tlbiel_pid(pid, set); | 51 | __tlbiel_pid(pid, set, ric); |
48 | } | 52 | } |
49 | return; | 53 | return; |
50 | } | 54 | } |
51 | 55 | ||
52 | static inline void _tlbie_pid(unsigned long pid) | 56 | static inline void _tlbie_pid(unsigned long pid, unsigned long ric) |
53 | { | 57 | { |
54 | unsigned long rb,rs,ric,prs,r; | 58 | unsigned long rb,rs,prs,r; |
55 | 59 | ||
56 | rb = PPC_BIT(53); /* IS = 1 */ | 60 | rb = PPC_BIT(53); /* IS = 1 */ |
57 | rs = pid << PPC_BITLSHIFT(31); | 61 | rs = pid << PPC_BITLSHIFT(31); |
58 | prs = 1; /* process scoped */ | 62 | prs = 1; /* process scoped */ |
59 | r = 1; /* raidx format */ | 63 | r = 1; /* raidx format */ |
60 | ric = 2; /* invalidate all the caches */ | ||
61 | 64 | ||
62 | asm volatile("ptesync": : :"memory"); | 65 | asm volatile("ptesync": : :"memory"); |
63 | asm volatile(".long 0x7c000264 | (%0 << 11) | (%1 << 16) |" | 66 | asm volatile(".long 0x7c000264 | (%0 << 11) | (%1 << 16) |" |
@@ -67,16 +70,15 @@ static inline void _tlbie_pid(unsigned long pid) | |||
67 | } | 70 | } |
68 | 71 | ||
69 | static inline void _tlbiel_va(unsigned long va, unsigned long pid, | 72 | static inline void _tlbiel_va(unsigned long va, unsigned long pid, |
70 | unsigned long ap) | 73 | unsigned long ap, unsigned long ric) |
71 | { | 74 | { |
72 | unsigned long rb,rs,ric,prs,r; | 75 | unsigned long rb,rs,prs,r; |
73 | 76 | ||
74 | rb = va & ~(PPC_BITMASK(52, 63)); | 77 | rb = va & ~(PPC_BITMASK(52, 63)); |
75 | rb |= ap << PPC_BITLSHIFT(58); | 78 | rb |= ap << PPC_BITLSHIFT(58); |
76 | rs = pid << PPC_BITLSHIFT(31); | 79 | rs = pid << PPC_BITLSHIFT(31); |
77 | prs = 1; /* process scoped */ | 80 | prs = 1; /* process scoped */ |
78 | r = 1; /* raidx format */ | 81 | r = 1; /* raidx format */ |
79 | ric = 0; /* no cluster flush yet */ | ||
80 | 82 | ||
81 | asm volatile("ptesync": : :"memory"); | 83 | asm volatile("ptesync": : :"memory"); |
82 | asm volatile(".long 0x7c000224 | (%0 << 11) | (%1 << 16) |" | 84 | asm volatile(".long 0x7c000224 | (%0 << 11) | (%1 << 16) |" |
@@ -86,16 +88,15 @@ static inline void _tlbiel_va(unsigned long va, unsigned long pid, | |||
86 | } | 88 | } |
87 | 89 | ||
88 | static inline void _tlbie_va(unsigned long va, unsigned long pid, | 90 | static inline void _tlbie_va(unsigned long va, unsigned long pid, |
89 | unsigned long ap) | 91 | unsigned long ap, unsigned long ric) |
90 | { | 92 | { |
91 | unsigned long rb,rs,ric,prs,r; | 93 | unsigned long rb,rs,prs,r; |
92 | 94 | ||
93 | rb = va & ~(PPC_BITMASK(52, 63)); | 95 | rb = va & ~(PPC_BITMASK(52, 63)); |
94 | rb |= ap << PPC_BITLSHIFT(58); | 96 | rb |= ap << PPC_BITLSHIFT(58); |
95 | rs = pid << PPC_BITLSHIFT(31); | 97 | rs = pid << PPC_BITLSHIFT(31); |
96 | prs = 1; /* process scoped */ | 98 | prs = 1; /* process scoped */ |
97 | r = 1; /* raidx format */ | 99 | r = 1; /* raidx format */ |
98 | ric = 0; /* no cluster flush yet */ | ||
99 | 100 | ||
100 | asm volatile("ptesync": : :"memory"); | 101 | asm volatile("ptesync": : :"memory"); |
101 | asm volatile(".long 0x7c000264 | (%0 << 11) | (%1 << 16) |" | 102 | asm volatile(".long 0x7c000264 | (%0 << 11) | (%1 << 16) |" |
@@ -122,11 +123,26 @@ void radix__local_flush_tlb_mm(struct mm_struct *mm) | |||
122 | preempt_disable(); | 123 | preempt_disable(); |
123 | pid = mm->context.id; | 124 | pid = mm->context.id; |
124 | if (pid != MMU_NO_CONTEXT) | 125 | if (pid != MMU_NO_CONTEXT) |
125 | _tlbiel_pid(pid); | 126 | _tlbiel_pid(pid, RIC_FLUSH_ALL); |
126 | preempt_enable(); | 127 | preempt_enable(); |
127 | } | 128 | } |
128 | EXPORT_SYMBOL(radix__local_flush_tlb_mm); | 129 | EXPORT_SYMBOL(radix__local_flush_tlb_mm); |
129 | 130 | ||
131 | void radix__local_flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr) | ||
132 | { | ||
133 | unsigned long pid; | ||
134 | struct mm_struct *mm = tlb->mm; | ||
135 | |||
136 | preempt_disable(); | ||
137 | |||
138 | pid = mm->context.id; | ||
139 | if (pid != MMU_NO_CONTEXT) | ||
140 | _tlbiel_pid(pid, RIC_FLUSH_PWC); | ||
141 | |||
142 | preempt_enable(); | ||
143 | } | ||
144 | EXPORT_SYMBOL(radix__local_flush_tlb_pwc); | ||
145 | |||
130 | void radix___local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, | 146 | void radix___local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, |
131 | unsigned long ap, int nid) | 147 | unsigned long ap, int nid) |
132 | { | 148 | { |
@@ -135,7 +151,7 @@ void radix___local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, | |||
135 | preempt_disable(); | 151 | preempt_disable(); |
136 | pid = mm ? mm->context.id : 0; | 152 | pid = mm ? mm->context.id : 0; |
137 | if (pid != MMU_NO_CONTEXT) | 153 | if (pid != MMU_NO_CONTEXT) |
138 | _tlbiel_va(vmaddr, pid, ap); | 154 | _tlbiel_va(vmaddr, pid, ap, RIC_FLUSH_TLB); |
139 | preempt_enable(); | 155 | preempt_enable(); |
140 | } | 156 | } |
141 | 157 | ||
@@ -172,16 +188,42 @@ void radix__flush_tlb_mm(struct mm_struct *mm) | |||
172 | 188 | ||
173 | if (lock_tlbie) | 189 | if (lock_tlbie) |
174 | raw_spin_lock(&native_tlbie_lock); | 190 | raw_spin_lock(&native_tlbie_lock); |
175 | _tlbie_pid(pid); | 191 | _tlbie_pid(pid, RIC_FLUSH_ALL); |
176 | if (lock_tlbie) | 192 | if (lock_tlbie) |
177 | raw_spin_unlock(&native_tlbie_lock); | 193 | raw_spin_unlock(&native_tlbie_lock); |
178 | } else | 194 | } else |
179 | _tlbiel_pid(pid); | 195 | _tlbiel_pid(pid, RIC_FLUSH_ALL); |
180 | no_context: | 196 | no_context: |
181 | preempt_enable(); | 197 | preempt_enable(); |
182 | } | 198 | } |
183 | EXPORT_SYMBOL(radix__flush_tlb_mm); | 199 | EXPORT_SYMBOL(radix__flush_tlb_mm); |
184 | 200 | ||
201 | void radix__flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr) | ||
202 | { | ||
203 | unsigned long pid; | ||
204 | struct mm_struct *mm = tlb->mm; | ||
205 | |||
206 | preempt_disable(); | ||
207 | |||
208 | pid = mm->context.id; | ||
209 | if (unlikely(pid == MMU_NO_CONTEXT)) | ||
210 | goto no_context; | ||
211 | |||
212 | if (!mm_is_core_local(mm)) { | ||
213 | int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); | ||
214 | |||
215 | if (lock_tlbie) | ||
216 | raw_spin_lock(&native_tlbie_lock); | ||
217 | _tlbie_pid(pid, RIC_FLUSH_PWC); | ||
218 | if (lock_tlbie) | ||
219 | raw_spin_unlock(&native_tlbie_lock); | ||
220 | } else | ||
221 | _tlbiel_pid(pid, RIC_FLUSH_PWC); | ||
222 | no_context: | ||
223 | preempt_enable(); | ||
224 | } | ||
225 | EXPORT_SYMBOL(radix__flush_tlb_pwc); | ||
226 | |||
185 | void radix___flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, | 227 | void radix___flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, |
186 | unsigned long ap, int nid) | 228 | unsigned long ap, int nid) |
187 | { | 229 | { |
@@ -196,11 +238,11 @@ void radix___flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, | |||
196 | 238 | ||
197 | if (lock_tlbie) | 239 | if (lock_tlbie) |
198 | raw_spin_lock(&native_tlbie_lock); | 240 | raw_spin_lock(&native_tlbie_lock); |
199 | _tlbie_va(vmaddr, pid, ap); | 241 | _tlbie_va(vmaddr, pid, ap, RIC_FLUSH_TLB); |
200 | if (lock_tlbie) | 242 | if (lock_tlbie) |
201 | raw_spin_unlock(&native_tlbie_lock); | 243 | raw_spin_unlock(&native_tlbie_lock); |
202 | } else | 244 | } else |
203 | _tlbiel_va(vmaddr, pid, ap); | 245 | _tlbiel_va(vmaddr, pid, ap, RIC_FLUSH_TLB); |
204 | bail: | 246 | bail: |
205 | preempt_enable(); | 247 | preempt_enable(); |
206 | } | 248 | } |
@@ -224,7 +266,7 @@ void radix__flush_tlb_kernel_range(unsigned long start, unsigned long end) | |||
224 | 266 | ||
225 | if (lock_tlbie) | 267 | if (lock_tlbie) |
226 | raw_spin_lock(&native_tlbie_lock); | 268 | raw_spin_lock(&native_tlbie_lock); |
227 | _tlbie_pid(0); | 269 | _tlbie_pid(0, RIC_FLUSH_ALL); |
228 | if (lock_tlbie) | 270 | if (lock_tlbie) |
229 | raw_spin_unlock(&native_tlbie_lock); | 271 | raw_spin_unlock(&native_tlbie_lock); |
230 | } | 272 | } |