diff options
Diffstat (limited to 'include/asm-generic/tlb.h')
-rw-r--r-- | include/asm-generic/tlb.h | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index 5672d7ea1fa0..08848050922e 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h | |||
@@ -96,10 +96,9 @@ struct mmu_gather { | |||
96 | #endif | 96 | #endif |
97 | unsigned long start; | 97 | unsigned long start; |
98 | unsigned long end; | 98 | unsigned long end; |
99 | unsigned int need_flush : 1, /* Did free PTEs */ | ||
100 | /* we are in the middle of an operation to clear | 99 | /* we are in the middle of an operation to clear |
101 | * a full mm and can make some optimizations */ | 100 | * a full mm and can make some optimizations */ |
102 | fullmm : 1, | 101 | unsigned int fullmm : 1, |
103 | /* we have performed an operation which | 102 | /* we have performed an operation which |
104 | * requires a complete flush of the tlb */ | 103 | * requires a complete flush of the tlb */ |
105 | need_flush_all : 1; | 104 | need_flush_all : 1; |
@@ -128,16 +127,54 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) | |||
128 | tlb_flush_mmu(tlb); | 127 | tlb_flush_mmu(tlb); |
129 | } | 128 | } |
130 | 129 | ||
130 | static inline void __tlb_adjust_range(struct mmu_gather *tlb, | ||
131 | unsigned long address) | ||
132 | { | ||
133 | tlb->start = min(tlb->start, address); | ||
134 | tlb->end = max(tlb->end, address + PAGE_SIZE); | ||
135 | } | ||
136 | |||
137 | static inline void __tlb_reset_range(struct mmu_gather *tlb) | ||
138 | { | ||
139 | tlb->start = TASK_SIZE; | ||
140 | tlb->end = 0; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * In the case of tlb vma handling, we can optimise these away in the | ||
145 | * case where we're doing a full MM flush. When we're doing a munmap, | ||
146 | * the vmas are adjusted to only cover the region to be torn down. | ||
147 | */ | ||
148 | #ifndef tlb_start_vma | ||
149 | #define tlb_start_vma(tlb, vma) do { } while (0) | ||
150 | #endif | ||
151 | |||
152 | #define __tlb_end_vma(tlb, vma) \ | ||
153 | do { \ | ||
154 | if (!tlb->fullmm && tlb->end) { \ | ||
155 | tlb_flush(tlb); \ | ||
156 | __tlb_reset_range(tlb); \ | ||
157 | } \ | ||
158 | } while (0) | ||
159 | |||
160 | #ifndef tlb_end_vma | ||
161 | #define tlb_end_vma __tlb_end_vma | ||
162 | #endif | ||
163 | |||
164 | #ifndef __tlb_remove_tlb_entry | ||
165 | #define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) | ||
166 | #endif | ||
167 | |||
131 | /** | 168 | /** |
132 | * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation. | 169 | * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation. |
133 | * | 170 | * |
134 | * Record the fact that pte's were really umapped in ->need_flush, so we can | 171 | * Record the fact that pte's were really unmapped by updating the range, |
135 | * later optimise away the tlb invalidate. This helps when userspace is | 172 | * so we can later optimise away the tlb invalidate. This helps when |
136 | * unmapping already-unmapped pages, which happens quite a lot. | 173 | * userspace is unmapping already-unmapped pages, which happens quite a lot. |
137 | */ | 174 | */ |
138 | #define tlb_remove_tlb_entry(tlb, ptep, address) \ | 175 | #define tlb_remove_tlb_entry(tlb, ptep, address) \ |
139 | do { \ | 176 | do { \ |
140 | tlb->need_flush = 1; \ | 177 | __tlb_adjust_range(tlb, address); \ |
141 | __tlb_remove_tlb_entry(tlb, ptep, address); \ | 178 | __tlb_remove_tlb_entry(tlb, ptep, address); \ |
142 | } while (0) | 179 | } while (0) |
143 | 180 | ||
@@ -151,27 +188,27 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) | |||
151 | 188 | ||
152 | #define tlb_remove_pmd_tlb_entry(tlb, pmdp, address) \ | 189 | #define tlb_remove_pmd_tlb_entry(tlb, pmdp, address) \ |
153 | do { \ | 190 | do { \ |
154 | tlb->need_flush = 1; \ | 191 | __tlb_adjust_range(tlb, address); \ |
155 | __tlb_remove_pmd_tlb_entry(tlb, pmdp, address); \ | 192 | __tlb_remove_pmd_tlb_entry(tlb, pmdp, address); \ |
156 | } while (0) | 193 | } while (0) |
157 | 194 | ||
158 | #define pte_free_tlb(tlb, ptep, address) \ | 195 | #define pte_free_tlb(tlb, ptep, address) \ |
159 | do { \ | 196 | do { \ |
160 | tlb->need_flush = 1; \ | 197 | __tlb_adjust_range(tlb, address); \ |
161 | __pte_free_tlb(tlb, ptep, address); \ | 198 | __pte_free_tlb(tlb, ptep, address); \ |
162 | } while (0) | 199 | } while (0) |
163 | 200 | ||
164 | #ifndef __ARCH_HAS_4LEVEL_HACK | 201 | #ifndef __ARCH_HAS_4LEVEL_HACK |
165 | #define pud_free_tlb(tlb, pudp, address) \ | 202 | #define pud_free_tlb(tlb, pudp, address) \ |
166 | do { \ | 203 | do { \ |
167 | tlb->need_flush = 1; \ | 204 | __tlb_adjust_range(tlb, address); \ |
168 | __pud_free_tlb(tlb, pudp, address); \ | 205 | __pud_free_tlb(tlb, pudp, address); \ |
169 | } while (0) | 206 | } while (0) |
170 | #endif | 207 | #endif |
171 | 208 | ||
172 | #define pmd_free_tlb(tlb, pmdp, address) \ | 209 | #define pmd_free_tlb(tlb, pmdp, address) \ |
173 | do { \ | 210 | do { \ |
174 | tlb->need_flush = 1; \ | 211 | __tlb_adjust_range(tlb, address); \ |
175 | __pmd_free_tlb(tlb, pmdp, address); \ | 212 | __pmd_free_tlb(tlb, pmdp, address); \ |
176 | } while (0) | 213 | } while (0) |
177 | 214 | ||