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> 2558e9c47fSRussell King 2658e9c47fSRussell King #define tlb_flush(tlb) ((void) tlb) 2758e9c47fSRussell King 284baa9922SRussell King #include <asm-generic/tlb.h> 294baa9922SRussell King 304baa9922SRussell King #else /* !CONFIG_MMU */ 314baa9922SRussell King 3206824ba8SRussell King #include <linux/swap.h> 334baa9922SRussell King #include <asm/pgalloc.h> 3406824ba8SRussell King #include <asm/tlbflush.h> 3506824ba8SRussell King 3606824ba8SRussell King /* 3706824ba8SRussell King * We need to delay page freeing for SMP as other CPUs can access pages 3806824ba8SRussell King * which have been removed but not yet had their TLB entries invalidated. 3906824ba8SRussell King * Also, as ARMv7 speculative prefetch can drag new entries into the TLB, 4006824ba8SRussell King * we need to apply this same delaying tactic to ensure correct operation. 4106824ba8SRussell King */ 4206824ba8SRussell King #if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7) 4306824ba8SRussell King #define tlb_fast_mode(tlb) 0 4406824ba8SRussell King #else 4506824ba8SRussell King #define tlb_fast_mode(tlb) 1 4606824ba8SRussell King #endif 474baa9922SRussell King 489e14f674SPeter Zijlstra #define MMU_GATHER_BUNDLE 8 499e14f674SPeter Zijlstra 504baa9922SRussell King /* 514baa9922SRussell King * TLB handling. This allows us to remove pages from the page 524baa9922SRussell King * tables, and efficiently handle the TLB issues. 534baa9922SRussell King */ 544baa9922SRussell King struct mmu_gather { 554baa9922SRussell King struct mm_struct *mm; 564baa9922SRussell King unsigned int fullmm; 5706824ba8SRussell King struct vm_area_struct *vma; 587fccfc00SAaro Koskinen unsigned long range_start; 597fccfc00SAaro Koskinen unsigned long range_end; 6006824ba8SRussell King unsigned int nr; 619e14f674SPeter Zijlstra unsigned int max; 629e14f674SPeter Zijlstra struct page **pages; 639e14f674SPeter Zijlstra struct page *local[MMU_GATHER_BUNDLE]; 644baa9922SRussell King }; 654baa9922SRussell King 664baa9922SRussell King DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); 674baa9922SRussell King 6806824ba8SRussell King /* 6906824ba8SRussell King * This is unnecessarily complex. There's three ways the TLB shootdown 7006824ba8SRussell King * code is used: 7106824ba8SRussell King * 1. Unmapping a range of vmas. See zap_page_range(), unmap_region(). 7206824ba8SRussell King * tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called. 7306824ba8SRussell King * tlb->vma will be non-NULL. 7406824ba8SRussell King * 2. Unmapping all vmas. See exit_mmap(). 7506824ba8SRussell King * tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called. 7606824ba8SRussell King * tlb->vma will be non-NULL. Additionally, page tables will be freed. 7706824ba8SRussell King * 3. Unmapping argument pages. See shift_arg_pages(). 7806824ba8SRussell King * tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called. 7906824ba8SRussell King * tlb->vma will be NULL. 8006824ba8SRussell King */ 8106824ba8SRussell King static inline void tlb_flush(struct mmu_gather *tlb) 8206824ba8SRussell King { 8306824ba8SRussell King if (tlb->fullmm || !tlb->vma) 8406824ba8SRussell King flush_tlb_mm(tlb->mm); 8506824ba8SRussell King else if (tlb->range_end > 0) { 8606824ba8SRussell King flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end); 8706824ba8SRussell King tlb->range_start = TASK_SIZE; 8806824ba8SRussell King tlb->range_end = 0; 8906824ba8SRussell King } 9006824ba8SRussell King } 9106824ba8SRussell King 9206824ba8SRussell King static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr) 9306824ba8SRussell King { 9406824ba8SRussell King if (!tlb->fullmm) { 9506824ba8SRussell King if (addr < tlb->range_start) 9606824ba8SRussell King tlb->range_start = addr; 9706824ba8SRussell King if (addr + PAGE_SIZE > tlb->range_end) 9806824ba8SRussell King tlb->range_end = addr + PAGE_SIZE; 9906824ba8SRussell King } 10006824ba8SRussell King } 10106824ba8SRussell King 1029e14f674SPeter Zijlstra static inline void __tlb_alloc_page(struct mmu_gather *tlb) 1039e14f674SPeter Zijlstra { 1049e14f674SPeter Zijlstra unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); 1059e14f674SPeter Zijlstra 1069e14f674SPeter Zijlstra if (addr) { 1079e14f674SPeter Zijlstra tlb->pages = (void *)addr; 1089e14f674SPeter Zijlstra tlb->max = PAGE_SIZE / sizeof(struct page *); 1099e14f674SPeter Zijlstra } 1109e14f674SPeter Zijlstra } 1119e14f674SPeter Zijlstra 11206824ba8SRussell King static inline void tlb_flush_mmu(struct mmu_gather *tlb) 11306824ba8SRussell King { 11406824ba8SRussell King tlb_flush(tlb); 11506824ba8SRussell King if (!tlb_fast_mode(tlb)) { 11606824ba8SRussell King free_pages_and_swap_cache(tlb->pages, tlb->nr); 11706824ba8SRussell King tlb->nr = 0; 1189e14f674SPeter Zijlstra if (tlb->pages == tlb->local) 1199e14f674SPeter Zijlstra __tlb_alloc_page(tlb); 12006824ba8SRussell King } 12106824ba8SRussell King } 12206824ba8SRussell King 1239e14f674SPeter Zijlstra static inline void 1249e14f674SPeter Zijlstra tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int fullmm) 1254baa9922SRussell King { 1264baa9922SRussell King tlb->mm = mm; 1279e14f674SPeter Zijlstra tlb->fullmm = fullmm; 12806824ba8SRussell King tlb->vma = NULL; 1299e14f674SPeter Zijlstra tlb->max = ARRAY_SIZE(tlb->local); 1309e14f674SPeter Zijlstra tlb->pages = tlb->local; 13106824ba8SRussell King tlb->nr = 0; 1329e14f674SPeter Zijlstra __tlb_alloc_page(tlb); 1334baa9922SRussell King } 1344baa9922SRussell King 1354baa9922SRussell King static inline void 1364baa9922SRussell King tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) 1374baa9922SRussell King { 13806824ba8SRussell King tlb_flush_mmu(tlb); 1394baa9922SRussell King 1404baa9922SRussell King /* keep the page table cache within bounds */ 1414baa9922SRussell King check_pgt_cache(); 1424baa9922SRussell King 1439e14f674SPeter Zijlstra if (tlb->pages != tlb->local) 1449e14f674SPeter Zijlstra free_pages((unsigned long)tlb->pages, 0); 1454baa9922SRussell King } 1464baa9922SRussell King 1477fccfc00SAaro Koskinen /* 1487fccfc00SAaro Koskinen * Memorize the range for the TLB flush. 1497fccfc00SAaro Koskinen */ 1507fccfc00SAaro Koskinen static inline void 1517fccfc00SAaro Koskinen tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr) 1527fccfc00SAaro Koskinen { 15306824ba8SRussell King tlb_add_flush(tlb, addr); 1547fccfc00SAaro Koskinen } 1554baa9922SRussell King 1564baa9922SRussell King /* 1574baa9922SRussell King * In the case of tlb vma handling, we can optimise these away in the 1584baa9922SRussell King * case where we're doing a full MM flush. When we're doing a munmap, 1594baa9922SRussell King * the vmas are adjusted to only cover the region to be torn down. 1604baa9922SRussell King */ 1614baa9922SRussell King static inline void 1624baa9922SRussell King tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) 1634baa9922SRussell King { 1647fccfc00SAaro Koskinen if (!tlb->fullmm) { 1654baa9922SRussell King flush_cache_range(vma, vma->vm_start, vma->vm_end); 16606824ba8SRussell King tlb->vma = vma; 1677fccfc00SAaro Koskinen tlb->range_start = TASK_SIZE; 1687fccfc00SAaro Koskinen tlb->range_end = 0; 1697fccfc00SAaro Koskinen } 1704baa9922SRussell King } 1714baa9922SRussell King 1724baa9922SRussell King static inline void 1734baa9922SRussell King tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) 1744baa9922SRussell King { 17506824ba8SRussell King if (!tlb->fullmm) 17606824ba8SRussell King tlb_flush(tlb); 1774baa9922SRussell King } 1784baa9922SRussell King 1799e14f674SPeter Zijlstra static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) 18006824ba8SRussell King { 18106824ba8SRussell King if (tlb_fast_mode(tlb)) { 18206824ba8SRussell King free_page_and_swap_cache(page); 1839e14f674SPeter Zijlstra return 1; /* avoid calling tlb_flush_mmu */ 18406824ba8SRussell King } 1859e14f674SPeter Zijlstra 1869e14f674SPeter Zijlstra tlb->pages[tlb->nr++] = page; 1879e14f674SPeter Zijlstra VM_BUG_ON(tlb->nr > tlb->max); 1889e14f674SPeter Zijlstra return tlb->max - tlb->nr; 1899e14f674SPeter Zijlstra } 1909e14f674SPeter Zijlstra 1919e14f674SPeter Zijlstra static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) 1929e14f674SPeter Zijlstra { 1939e14f674SPeter Zijlstra if (!__tlb_remove_page(tlb, page)) 1949e14f674SPeter Zijlstra tlb_flush_mmu(tlb); 19506824ba8SRussell King } 19606824ba8SRussell King 19706824ba8SRussell King static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, 19806824ba8SRussell King unsigned long addr) 19906824ba8SRussell King { 20006824ba8SRussell King pgtable_page_dtor(pte); 2016d3ec1aeSCatalin Marinas 202df547e08SWill Deacon #ifdef CONFIG_ARM_LPAE 203df547e08SWill Deacon tlb_add_flush(tlb, addr); 204df547e08SWill Deacon #else 2056d3ec1aeSCatalin Marinas /* 2066d3ec1aeSCatalin Marinas * With the classic ARM MMU, a pte page has two corresponding pmd 2076d3ec1aeSCatalin Marinas * entries, each covering 1MB. 2086d3ec1aeSCatalin Marinas */ 2096d3ec1aeSCatalin Marinas addr &= PMD_MASK; 2106d3ec1aeSCatalin Marinas tlb_add_flush(tlb, addr + SZ_1M - PAGE_SIZE); 2116d3ec1aeSCatalin Marinas tlb_add_flush(tlb, addr + SZ_1M); 212df547e08SWill Deacon #endif 2136d3ec1aeSCatalin Marinas 21406824ba8SRussell King tlb_remove_page(tlb, pte); 21506824ba8SRussell King } 21606824ba8SRussell King 217c9f27f10SCatalin Marinas static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, 218c9f27f10SCatalin Marinas unsigned long addr) 219c9f27f10SCatalin Marinas { 220c9f27f10SCatalin Marinas #ifdef CONFIG_ARM_LPAE 221c9f27f10SCatalin Marinas tlb_add_flush(tlb, addr); 222c9f27f10SCatalin Marinas tlb_remove_page(tlb, virt_to_page(pmdp)); 223c9f27f10SCatalin Marinas #endif 224c9f27f10SCatalin Marinas } 225c9f27f10SCatalin Marinas 226*8d962507SCatalin Marinas static inline void 227*8d962507SCatalin Marinas tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr) 228*8d962507SCatalin Marinas { 229*8d962507SCatalin Marinas tlb_add_flush(tlb, addr); 230*8d962507SCatalin Marinas } 231*8d962507SCatalin Marinas 23206824ba8SRussell King #define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr) 233c9f27f10SCatalin Marinas #define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr) 234a32618d2SRussell King #define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp) 2354baa9922SRussell King 2364baa9922SRussell King #define tlb_migrate_finish(mm) do { } while (0) 2374baa9922SRussell King 2384baa9922SRussell King #endif /* CONFIG_MMU */ 2394baa9922SRussell King #endif 240