aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2016-06-08 10:25:51 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2016-06-10 02:14:52 -0400
commita145abf12c9f7d30d8c330c9d8a97428cbf0589b (patch)
treefd6299b45426739853fc7b4da91fd62d7fdf3a74 /arch/powerpc/mm
parent36194812a4063dd2a72070aec3ee7890d135a587 (diff)
powerpc/mm/radix: Flush page walk cache when freeing page table
Even though a tlb_flush() does a flush with invalidate all cache, we can end up doing an RCU page table free before calling tlb_flush(). That means we can have page walk cache entries even after we free the page table pages. This can result in us doing wrong page table walk. Avoid this by doing pwc flush on every page table free. We can't batch the pwc flush, because the rcu call back function where we free the page table pages doesn't have information of the mmu gather. Thus we have to do a pwc on every page table page freed. Note: I also removed the dummy tlb_flush_pgtable call functions for hash 32. Fixes: 1a472c9dba6b ("powerpc/mm/radix: Add tlbflush routines") Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/tlb-radix.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c
index 71083621884e..ab2f60e812e2 100644
--- a/arch/powerpc/mm/tlb-radix.c
+++ b/arch/powerpc/mm/tlb-radix.c
@@ -128,6 +128,21 @@ void radix__local_flush_tlb_mm(struct mm_struct *mm)
128} 128}
129EXPORT_SYMBOL(radix__local_flush_tlb_mm); 129EXPORT_SYMBOL(radix__local_flush_tlb_mm);
130 130
131void 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}
144EXPORT_SYMBOL(radix__local_flush_tlb_pwc);
145
131void radix___local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, 146void radix___local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
132 unsigned long ap, int nid) 147 unsigned long ap, int nid)
133{ 148{
@@ -183,6 +198,32 @@ no_context:
183} 198}
184EXPORT_SYMBOL(radix__flush_tlb_mm); 199EXPORT_SYMBOL(radix__flush_tlb_mm);
185 200
201void 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);
222no_context:
223 preempt_enable();
224}
225EXPORT_SYMBOL(radix__flush_tlb_pwc);
226
186void radix___flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, 227void radix___flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
187 unsigned long ap, int nid) 228 unsigned long ap, int nid)
188{ 229{