Branch data Line data Source code
1 : : /*
2 : : * arch/arm/include/asm/tlb.h
3 : : *
4 : : * Copyright (C) 2002 Russell King
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License version 2 as
8 : : * published by the Free Software Foundation.
9 : : *
10 : : * Experimentation shows that on a StrongARM, it appears to be faster
11 : : * to use the "invalidate whole tlb" rather than "invalidate single
12 : : * tlb" for this.
13 : : *
14 : : * This appears true for both the process fork+exit case, as well as
15 : : * the munmap-large-area case.
16 : : */
17 : : #ifndef __ASMARM_TLB_H
18 : : #define __ASMARM_TLB_H
19 : :
20 : : #include <asm/cacheflush.h>
21 : :
22 : : #ifndef CONFIG_MMU
23 : :
24 : : #include <linux/pagemap.h>
25 : :
26 : : #define tlb_flush(tlb) ((void) tlb)
27 : :
28 : : #include <asm-generic/tlb.h>
29 : :
30 : : #else /* !CONFIG_MMU */
31 : :
32 : : #include <linux/swap.h>
33 : : #include <asm/pgalloc.h>
34 : : #include <asm/tlbflush.h>
35 : :
36 : : #define MMU_GATHER_BUNDLE 8
37 : :
38 : : /*
39 : : * TLB handling. This allows us to remove pages from the page
40 : : * tables, and efficiently handle the TLB issues.
41 : : */
42 : : struct mmu_gather {
43 : : struct mm_struct *mm;
44 : : unsigned int fullmm;
45 : : struct vm_area_struct *vma;
46 : : unsigned long start, end;
47 : : unsigned long range_start;
48 : : unsigned long range_end;
49 : : unsigned int nr;
50 : : unsigned int max;
51 : : struct page **pages;
52 : : struct page *local[MMU_GATHER_BUNDLE];
53 : : };
54 : :
55 : : DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
56 : :
57 : : /*
58 : : * This is unnecessarily complex. There's three ways the TLB shootdown
59 : : * code is used:
60 : : * 1. Unmapping a range of vmas. See zap_page_range(), unmap_region().
61 : : * tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
62 : : * tlb->vma will be non-NULL.
63 : : * 2. Unmapping all vmas. See exit_mmap().
64 : : * tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
65 : : * tlb->vma will be non-NULL. Additionally, page tables will be freed.
66 : : * 3. Unmapping argument pages. See shift_arg_pages().
67 : : * tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
68 : : * tlb->vma will be NULL.
69 : : */
70 : : static inline void tlb_flush(struct mmu_gather *tlb)
71 : : {
72 [ + - ][ + - ]: 2007039 : if (tlb->fullmm || !tlb->vma)
[ + + ][ - + ]
[ + - ][ + ]
[ + ][ + + ]
[ + + ][ - + ]
[ - + ][ # # ]
[ + ][ + ]
73 : 1164683 : flush_tlb_mm(tlb->mm);
74 [ - + ][ + + ]: 842356 : else if (tlb->range_end > 0) {
[ + + ][ + - ]
[ # # ]
75 : 271122 : flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end);
76 : 271119 : tlb->range_start = TASK_SIZE;
77 : 271119 : tlb->range_end = 0;
78 : : }
79 : : }
80 : :
81 : : static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
82 : : {
83 [ + + + + ]: 65234450 : if (!tlb->fullmm) {
[ + + ]
84 [ + + ][ + + ]: 1347428 : if (addr < tlb->range_start)
[ - + ]
85 : 271122 : tlb->range_start = addr;
86 [ + + ][ + - ]: 1347428 : if (addr + PAGE_SIZE > tlb->range_end)
[ + - ]
87 : 1347396 : tlb->range_end = addr + PAGE_SIZE;
88 : : }
89 : : }
90 : :
91 : : static inline void __tlb_alloc_page(struct mmu_gather *tlb)
92 : : {
93 : 1569522 : unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
94 : :
95 [ + # # + : 1575142 : if (addr) {
+ + # # #
# # # ]
96 : 1569621 : tlb->pages = (void *)addr;
97 : 1569621 : tlb->max = PAGE_SIZE / sizeof(struct page *);
98 : : }
99 : : }
100 : :
101 : : static inline void tlb_flush_mmu(struct mmu_gather *tlb)
102 : : {
103 : : tlb_flush(tlb);
104 : 1579167 : free_pages_and_swap_cache(tlb->pages, tlb->nr);
105 : 1579134 : tlb->nr = 0;
106 [ - + - + : 1579134 : if (tlb->pages == tlb->local)
- + - + ]
107 : : __tlb_alloc_page(tlb);
108 : : }
109 : :
110 : : static inline void
111 : : tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
112 : : {
113 : 1569522 : tlb->mm = mm;
114 : 1569522 : tlb->fullmm = !(start | (end+1));
115 : 1569522 : tlb->start = start;
116 : 1569522 : tlb->end = end;
117 : 1569522 : tlb->vma = NULL;
118 : 1569522 : tlb->max = ARRAY_SIZE(tlb->local);
119 : 1569522 : tlb->pages = tlb->local;
120 : 1569522 : tlb->nr = 0;
121 : : __tlb_alloc_page(tlb);
122 : : }
123 : :
124 : : static inline void
125 : : tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
126 : : {
127 : : tlb_flush_mmu(tlb);
128 : :
129 : : /* keep the page table cache within bounds */
130 : : check_pgt_cache();
131 : :
132 [ + + ][ + ]: 1569650 : if (tlb->pages != tlb->local)
133 : 1569676 : free_pages((unsigned long)tlb->pages, 0);
134 : : }
135 : :
136 : : /*
137 : : * Memorize the range for the TLB flush.
138 : : */
139 : : static inline void
140 : : tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
141 : : {
142 : : tlb_add_flush(tlb, addr);
143 : : }
144 : :
145 : : /*
146 : : * In the case of tlb vma handling, we can optimise these away in the
147 : : * case where we're doing a full MM flush. When we're doing a munmap,
148 : : * the vmas are adjusted to only cover the region to be torn down.
149 : : */
150 : : static inline void
151 : : tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
152 : : {
153 [ + + ]: 20311069 : if (!tlb->fullmm) {
154 : 427868 : flush_cache_range(vma, vma->vm_start, vma->vm_end);
155 : 427771 : tlb->vma = vma;
156 : 427771 : tlb->range_start = TASK_SIZE;
157 : 427771 : tlb->range_end = 0;
158 : : }
159 : : }
160 : :
161 : : static inline void
162 : : tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
163 : : {
164 [ + + ]: 20311254 : if (!tlb->fullmm)
165 : : tlb_flush(tlb);
166 : : }
167 : :
168 : : static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
169 : : {
170 : 62664294 : tlb->pages[tlb->nr++] = page;
171 : : VM_BUG_ON(tlb->nr > tlb->max);
172 : 62664294 : return tlb->max - tlb->nr;
173 : : }
174 : :
175 : : static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
176 : : {
177 [ + ]: 2493540 : if (!__tlb_remove_page(tlb, page))
178 : : tlb_flush_mmu(tlb);
179 : : }
180 : :
181 : : static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
182 : : unsigned long addr)
183 : : {
184 : : pgtable_page_dtor(pte);
185 : :
186 : : #ifdef CONFIG_ARM_LPAE
187 : : tlb_add_flush(tlb, addr);
188 : : #else
189 : : /*
190 : : * With the classic ARM MMU, a pte page has two corresponding pmd
191 : : * entries, each covering 1MB.
192 : : */
193 : 2493540 : addr &= PMD_MASK;
194 : 2493540 : tlb_add_flush(tlb, addr + SZ_1M - PAGE_SIZE);
195 : 2493540 : tlb_add_flush(tlb, addr + SZ_1M);
196 : : #endif
197 : :
198 : : tlb_remove_page(tlb, pte);
199 : : }
200 : :
201 : : static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
202 : : unsigned long addr)
203 : : {
204 : : #ifdef CONFIG_ARM_LPAE
205 : : tlb_add_flush(tlb, addr);
206 : : tlb_remove_page(tlb, virt_to_page(pmdp));
207 : : #endif
208 : : }
209 : :
210 : : static inline void
211 : : tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
212 : : {
213 : : tlb_add_flush(tlb, addr);
214 : : }
215 : :
216 : : #define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
217 : : #define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr)
218 : : #define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp)
219 : :
220 : : #define tlb_migrate_finish(mm) do { } while (0)
221 : :
222 : : #endif /* CONFIG_MMU */
223 : : #endif
|