Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/mm/radix: Implement tlb mmu gather flush efficiently

Now that we track page size in mmu_gather, we can use address based
tlbie format when doing a tlb_flush(). We don't do this if we are
invalidating the full address space.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Aneesh Kumar K.V and committed by
Michael Ellerman
8cb8140c e2985fd9

+60 -1
+2
arch/powerpc/include/asm/book3s/64/tlbflush-radix.h
··· 10 10 return mmu_psize_defs[psize].ap; 11 11 } 12 12 13 + extern void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start, 14 + unsigned long end, int psize); 13 15 extern void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 14 16 unsigned long end); 15 17 extern void radix__flush_tlb_kernel_range(unsigned long start, unsigned long end);
+58 -1
arch/powerpc/mm/tlb-radix.c
··· 299 299 300 300 void radix__tlb_flush(struct mmu_gather *tlb) 301 301 { 302 + int psize = 0; 302 303 struct mm_struct *mm = tlb->mm; 303 - radix__flush_tlb_mm(mm); 304 + int page_size = tlb->page_size; 305 + 306 + psize = radix_get_mmu_psize(page_size); 307 + /* 308 + * if page size is not something we understand, do a full mm flush 309 + */ 310 + if (psize != -1 && !tlb->fullmm && !tlb->need_flush_all) 311 + radix__flush_tlb_range_psize(mm, tlb->start, tlb->end, psize); 312 + else 313 + radix__flush_tlb_mm(mm); 314 + } 315 + 316 + #define TLB_FLUSH_ALL -1UL 317 + /* 318 + * Number of pages above which we will do a bcast tlbie. Just a 319 + * number at this point copied from x86 320 + */ 321 + static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33; 322 + 323 + void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start, 324 + unsigned long end, int psize) 325 + { 326 + unsigned long pid; 327 + unsigned long addr; 328 + int local = mm_is_core_local(mm); 329 + unsigned long ap = mmu_get_ap(psize); 330 + int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); 331 + unsigned long page_size = 1UL << mmu_psize_defs[psize].shift; 332 + 333 + 334 + preempt_disable(); 335 + pid = mm ? mm->context.id : 0; 336 + if (unlikely(pid == MMU_NO_CONTEXT)) 337 + goto err_out; 338 + 339 + if (end == TLB_FLUSH_ALL || 340 + (end - start) > tlb_single_page_flush_ceiling * page_size) { 341 + if (local) 342 + _tlbiel_pid(pid, RIC_FLUSH_TLB); 343 + else 344 + _tlbie_pid(pid, RIC_FLUSH_TLB); 345 + goto err_out; 346 + } 347 + for (addr = start; addr < end; addr += page_size) { 348 + 349 + if (local) 350 + _tlbiel_va(addr, pid, ap, RIC_FLUSH_TLB); 351 + else { 352 + if (lock_tlbie) 353 + raw_spin_lock(&native_tlbie_lock); 354 + _tlbie_va(addr, pid, ap, RIC_FLUSH_TLB); 355 + if (lock_tlbie) 356 + raw_spin_unlock(&native_tlbie_lock); 357 + } 358 + } 359 + err_out: 360 + preempt_enable(); 304 361 } 305 362 306 363 void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa,