14baa9922SRussell King /* 24baa9922SRussell King * arch/arm/include/asm/tlb.h 34baa9922SRussell King * 44baa9922SRussell King * Copyright (C) 2002 Russell King 54baa9922SRussell King * 64baa9922SRussell King * This program is free software; you can redistribute it and/or modify 74baa9922SRussell King * it under the terms of the GNU General Public License version 2 as 84baa9922SRussell King * published by the Free Software Foundation. 94baa9922SRussell King * 104baa9922SRussell King * Experimentation shows that on a StrongARM, it appears to be faster 114baa9922SRussell King * to use the "invalidate whole tlb" rather than "invalidate single 124baa9922SRussell King * tlb" for this. 134baa9922SRussell King * 144baa9922SRussell King * This appears true for both the process fork+exit case, as well as 154baa9922SRussell King * the munmap-large-area case. 164baa9922SRussell King */ 174baa9922SRussell King #ifndef __ASMARM_TLB_H 184baa9922SRussell King #define __ASMARM_TLB_H 194baa9922SRussell King 204baa9922SRussell King #include <asm/cacheflush.h> 214baa9922SRussell King 224baa9922SRussell King #ifndef CONFIG_MMU 234baa9922SRussell King 244baa9922SRussell King #include <linux/pagemap.h> 254baa9922SRussell King #include <asm-generic/tlb.h> 264baa9922SRussell King 274baa9922SRussell King #else /* !CONFIG_MMU */ 284baa9922SRussell King 29*06824ba8SRussell King #include <linux/swap.h> 304baa9922SRussell King #include <asm/pgalloc.h> 31*06824ba8SRussell King #include <asm/tlbflush.h> 32*06824ba8SRussell King 33*06824ba8SRussell King /* 34*06824ba8SRussell King * We need to delay page freeing for SMP as other CPUs can access pages 35*06824ba8SRussell King * which have been removed but not yet had their TLB entries invalidated. 36*06824ba8SRussell King * Also, as ARMv7 speculative prefetch can drag new entries into the TLB, 37*06824ba8SRussell King * we need to apply this same delaying tactic to ensure correct operation. 38*06824ba8SRussell King */ 39*06824ba8SRussell King #if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7) 40*06824ba8SRussell King #define tlb_fast_mode(tlb) 0 41*06824ba8SRussell King #define FREE_PTE_NR 500 42*06824ba8SRussell King #else 43*06824ba8SRussell King #define tlb_fast_mode(tlb) 1 44*06824ba8SRussell King #define FREE_PTE_NR 0 45*06824ba8SRussell King #endif 464baa9922SRussell King 474baa9922SRussell King /* 484baa9922SRussell King * TLB handling. This allows us to remove pages from the page 494baa9922SRussell King * tables, and efficiently handle the TLB issues. 504baa9922SRussell King */ 514baa9922SRussell King struct mmu_gather { 524baa9922SRussell King struct mm_struct *mm; 534baa9922SRussell King unsigned int fullmm; 54*06824ba8SRussell King struct vm_area_struct *vma; 557fccfc00SAaro Koskinen unsigned long range_start; 567fccfc00SAaro Koskinen unsigned long range_end; 57*06824ba8SRussell King unsigned int nr; 58*06824ba8SRussell King struct page *pages[FREE_PTE_NR]; 594baa9922SRussell King }; 604baa9922SRussell King 614baa9922SRussell King DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); 624baa9922SRussell King 63*06824ba8SRussell King /* 64*06824ba8SRussell King * This is unnecessarily complex. There's three ways the TLB shootdown 65*06824ba8SRussell King * code is used: 66*06824ba8SRussell King * 1. Unmapping a range of vmas. See zap_page_range(), unmap_region(). 67*06824ba8SRussell King * tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called. 68*06824ba8SRussell King * tlb->vma will be non-NULL. 69*06824ba8SRussell King * 2. Unmapping all vmas. See exit_mmap(). 70*06824ba8SRussell King * tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called. 71*06824ba8SRussell King * tlb->vma will be non-NULL. Additionally, page tables will be freed. 72*06824ba8SRussell King * 3. Unmapping argument pages. See shift_arg_pages(). 73*06824ba8SRussell King * tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called. 74*06824ba8SRussell King * tlb->vma will be NULL. 75*06824ba8SRussell King */ 76*06824ba8SRussell King static inline void tlb_flush(struct mmu_gather *tlb) 77*06824ba8SRussell King { 78*06824ba8SRussell King if (tlb->fullmm || !tlb->vma) 79*06824ba8SRussell King flush_tlb_mm(tlb->mm); 80*06824ba8SRussell King else if (tlb->range_end > 0) { 81*06824ba8SRussell King flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end); 82*06824ba8SRussell King tlb->range_start = TASK_SIZE; 83*06824ba8SRussell King tlb->range_end = 0; 84*06824ba8SRussell King } 85*06824ba8SRussell King } 86*06824ba8SRussell King 87*06824ba8SRussell King static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr) 88*06824ba8SRussell King { 89*06824ba8SRussell King if (!tlb->fullmm) { 90*06824ba8SRussell King if (addr < tlb->range_start) 91*06824ba8SRussell King tlb->range_start = addr; 92*06824ba8SRussell King if (addr + PAGE_SIZE > tlb->range_end) 93*06824ba8SRussell King tlb->range_end = addr + PAGE_SIZE; 94*06824ba8SRussell King } 95*06824ba8SRussell King } 96*06824ba8SRussell King 97*06824ba8SRussell King static inline void tlb_flush_mmu(struct mmu_gather *tlb) 98*06824ba8SRussell King { 99*06824ba8SRussell King tlb_flush(tlb); 100*06824ba8SRussell King if (!tlb_fast_mode(tlb)) { 101*06824ba8SRussell King free_pages_and_swap_cache(tlb->pages, tlb->nr); 102*06824ba8SRussell King tlb->nr = 0; 103*06824ba8SRussell King } 104*06824ba8SRussell King } 105*06824ba8SRussell King 1064baa9922SRussell King static inline struct mmu_gather * 1074baa9922SRussell King tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) 1084baa9922SRussell King { 1094baa9922SRussell King struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); 1104baa9922SRussell King 1114baa9922SRussell King tlb->mm = mm; 1124baa9922SRussell King tlb->fullmm = full_mm_flush; 113*06824ba8SRussell King tlb->vma = NULL; 114*06824ba8SRussell King tlb->nr = 0; 1154baa9922SRussell King 1164baa9922SRussell King return tlb; 1174baa9922SRussell King } 1184baa9922SRussell King 1194baa9922SRussell King static inline void 1204baa9922SRussell King tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) 1214baa9922SRussell King { 122*06824ba8SRussell King tlb_flush_mmu(tlb); 1234baa9922SRussell King 1244baa9922SRussell King /* keep the page table cache within bounds */ 1254baa9922SRussell King check_pgt_cache(); 1264baa9922SRussell King 1274baa9922SRussell King put_cpu_var(mmu_gathers); 1284baa9922SRussell King } 1294baa9922SRussell King 1307fccfc00SAaro Koskinen /* 1317fccfc00SAaro Koskinen * Memorize the range for the TLB flush. 1327fccfc00SAaro Koskinen */ 1337fccfc00SAaro Koskinen static inline void 1347fccfc00SAaro Koskinen tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr) 1357fccfc00SAaro Koskinen { 136*06824ba8SRussell King tlb_add_flush(tlb, addr); 1377fccfc00SAaro Koskinen } 1384baa9922SRussell King 1394baa9922SRussell King /* 1404baa9922SRussell King * In the case of tlb vma handling, we can optimise these away in the 1414baa9922SRussell King * case where we're doing a full MM flush. When we're doing a munmap, 1424baa9922SRussell King * the vmas are adjusted to only cover the region to be torn down. 1434baa9922SRussell King */ 1444baa9922SRussell King static inline void 1454baa9922SRussell King tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) 1464baa9922SRussell King { 1477fccfc00SAaro Koskinen if (!tlb->fullmm) { 1484baa9922SRussell King flush_cache_range(vma, vma->vm_start, vma->vm_end); 149*06824ba8SRussell King tlb->vma = vma; 1507fccfc00SAaro Koskinen tlb->range_start = TASK_SIZE; 1517fccfc00SAaro Koskinen tlb->range_end = 0; 1527fccfc00SAaro Koskinen } 1534baa9922SRussell King } 1544baa9922SRussell King 1554baa9922SRussell King static inline void 1564baa9922SRussell King tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) 1574baa9922SRussell King { 158*06824ba8SRussell King if (!tlb->fullmm) 159*06824ba8SRussell King tlb_flush(tlb); 1604baa9922SRussell King } 1614baa9922SRussell King 162*06824ba8SRussell King static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) 163*06824ba8SRussell King { 164*06824ba8SRussell King if (tlb_fast_mode(tlb)) { 165*06824ba8SRussell King free_page_and_swap_cache(page); 166*06824ba8SRussell King } else { 167*06824ba8SRussell King tlb->pages[tlb->nr++] = page; 168*06824ba8SRussell King if (tlb->nr >= FREE_PTE_NR) 169*06824ba8SRussell King tlb_flush_mmu(tlb); 170*06824ba8SRussell King } 171*06824ba8SRussell King } 172*06824ba8SRussell King 173*06824ba8SRussell King static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, 174*06824ba8SRussell King unsigned long addr) 175*06824ba8SRussell King { 176*06824ba8SRussell King pgtable_page_dtor(pte); 177*06824ba8SRussell King tlb_add_flush(tlb, addr); 178*06824ba8SRussell King tlb_remove_page(tlb, pte); 179*06824ba8SRussell King } 180*06824ba8SRussell King 181*06824ba8SRussell King #define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr) 1829e1b32caSBenjamin Herrenschmidt #define pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, pmdp) 1834baa9922SRussell King 1844baa9922SRussell King #define tlb_migrate_finish(mm) do { } while (0) 1854baa9922SRussell King 1864baa9922SRussell King #endif /* CONFIG_MMU */ 1874baa9922SRussell King #endif 188