20
20
#include <asm/pgalloc.h>
21
21
#include <asm/tlbflush.h>
22
22
23
+ #ifdef CONFIG_MMU
24
+
23
25
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
24
26
/*
25
27
* Semi RCU freeing of the page directories.
@@ -97,12 +99,30 @@ struct mmu_gather {
97
99
#endif
98
100
unsigned long start ;
99
101
unsigned long end ;
100
- /* we are in the middle of an operation to clear
101
- * a full mm and can make some optimizations */
102
- unsigned int fullmm : 1 ,
103
- /* we have performed an operation which
104
- * requires a complete flush of the tlb */
105
- need_flush_all : 1 ;
102
+ /*
103
+ * we are in the middle of an operation to clear
104
+ * a full mm and can make some optimizations
105
+ */
106
+ unsigned int fullmm : 1 ;
107
+
108
+ /*
109
+ * we have performed an operation which
110
+ * requires a complete flush of the tlb
111
+ */
112
+ unsigned int need_flush_all : 1 ;
113
+
114
+ /*
115
+ * we have removed page directories
116
+ */
117
+ unsigned int freed_tables : 1 ;
118
+
119
+ /*
120
+ * at which levels have we cleared entries?
121
+ */
122
+ unsigned int cleared_ptes : 1 ;
123
+ unsigned int cleared_pmds : 1 ;
124
+ unsigned int cleared_puds : 1 ;
125
+ unsigned int cleared_p4ds : 1 ;
106
126
107
127
struct mmu_gather_batch * active ;
108
128
struct mmu_gather_batch local ;
@@ -118,6 +138,7 @@ void arch_tlb_gather_mmu(struct mmu_gather *tlb,
118
138
void tlb_flush_mmu (struct mmu_gather * tlb );
119
139
void arch_tlb_finish_mmu (struct mmu_gather * tlb ,
120
140
unsigned long start , unsigned long end , bool force );
141
+ void tlb_flush_mmu_free (struct mmu_gather * tlb );
121
142
extern bool __tlb_remove_page_size (struct mmu_gather * tlb , struct page * page ,
122
143
int page_size );
123
144
@@ -137,6 +158,11 @@ static inline void __tlb_reset_range(struct mmu_gather *tlb)
137
158
tlb -> start = TASK_SIZE ;
138
159
tlb -> end = 0 ;
139
160
}
161
+ tlb -> freed_tables = 0 ;
162
+ tlb -> cleared_ptes = 0 ;
163
+ tlb -> cleared_pmds = 0 ;
164
+ tlb -> cleared_puds = 0 ;
165
+ tlb -> cleared_p4ds = 0 ;
140
166
}
141
167
142
168
static inline void tlb_flush_mmu_tlbonly (struct mmu_gather * tlb )
@@ -186,6 +212,25 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,
186
212
}
187
213
#endif
188
214
215
+ static inline unsigned long tlb_get_unmap_shift (struct mmu_gather * tlb )
216
+ {
217
+ if (tlb -> cleared_ptes )
218
+ return PAGE_SHIFT ;
219
+ if (tlb -> cleared_pmds )
220
+ return PMD_SHIFT ;
221
+ if (tlb -> cleared_puds )
222
+ return PUD_SHIFT ;
223
+ if (tlb -> cleared_p4ds )
224
+ return P4D_SHIFT ;
225
+
226
+ return PAGE_SHIFT ;
227
+ }
228
+
229
+ static inline unsigned long tlb_get_unmap_size (struct mmu_gather * tlb )
230
+ {
231
+ return 1UL << tlb_get_unmap_shift (tlb );
232
+ }
233
+
189
234
/*
190
235
* In the case of tlb vma handling, we can optimise these away in the
191
236
* case where we're doing a full MM flush. When we're doing a munmap,
@@ -219,13 +264,19 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,
219
264
#define tlb_remove_tlb_entry (tlb , ptep , address ) \
220
265
do { \
221
266
__tlb_adjust_range(tlb, address, PAGE_SIZE); \
267
+ tlb->cleared_ptes = 1; \
222
268
__tlb_remove_tlb_entry(tlb, ptep, address); \
223
269
} while (0)
224
270
225
- #define tlb_remove_huge_tlb_entry (h , tlb , ptep , address ) \
226
- do { \
227
- __tlb_adjust_range(tlb, address, huge_page_size(h)); \
228
- __tlb_remove_tlb_entry(tlb, ptep, address); \
271
+ #define tlb_remove_huge_tlb_entry (h , tlb , ptep , address ) \
272
+ do { \
273
+ unsigned long _sz = huge_page_size(h); \
274
+ __tlb_adjust_range(tlb, address, _sz); \
275
+ if (_sz == PMD_SIZE) \
276
+ tlb->cleared_pmds = 1; \
277
+ else if (_sz == PUD_SIZE) \
278
+ tlb->cleared_puds = 1; \
279
+ __tlb_remove_tlb_entry(tlb, ptep, address); \
229
280
} while (0)
230
281
231
282
/**
@@ -239,6 +290,7 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,
239
290
#define tlb_remove_pmd_tlb_entry (tlb , pmdp , address ) \
240
291
do { \
241
292
__tlb_adjust_range(tlb, address, HPAGE_PMD_SIZE); \
293
+ tlb->cleared_pmds = 1; \
242
294
__tlb_remove_pmd_tlb_entry(tlb, pmdp, address); \
243
295
} while (0)
244
296
@@ -253,6 +305,7 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,
253
305
#define tlb_remove_pud_tlb_entry (tlb , pudp , address ) \
254
306
do { \
255
307
__tlb_adjust_range(tlb, address, HPAGE_PUD_SIZE); \
308
+ tlb->cleared_puds = 1; \
256
309
__tlb_remove_pud_tlb_entry(tlb, pudp, address); \
257
310
} while (0)
258
311
@@ -278,14 +331,18 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,
278
331
#define pte_free_tlb (tlb , ptep , address ) \
279
332
do { \
280
333
__tlb_adjust_range(tlb, address, PAGE_SIZE); \
334
+ tlb->freed_tables = 1; \
335
+ tlb->cleared_pmds = 1; \
281
336
__pte_free_tlb(tlb, ptep, address); \
282
337
} while (0)
283
338
#endif
284
339
285
340
#ifndef pmd_free_tlb
286
341
#define pmd_free_tlb (tlb , pmdp , address ) \
287
342
do { \
288
- __tlb_adjust_range(tlb, address, PAGE_SIZE); \
343
+ __tlb_adjust_range(tlb, address, PAGE_SIZE); \
344
+ tlb->freed_tables = 1; \
345
+ tlb->cleared_puds = 1; \
289
346
__pmd_free_tlb(tlb, pmdp, address); \
290
347
} while (0)
291
348
#endif
@@ -295,6 +352,8 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,
295
352
#define pud_free_tlb (tlb , pudp , address ) \
296
353
do { \
297
354
__tlb_adjust_range(tlb, address, PAGE_SIZE); \
355
+ tlb->freed_tables = 1; \
356
+ tlb->cleared_p4ds = 1; \
298
357
__pud_free_tlb(tlb, pudp, address); \
299
358
} while (0)
300
359
#endif
@@ -304,12 +363,15 @@ static inline void tlb_remove_check_page_size_change(struct mmu_gather *tlb,
304
363
#ifndef p4d_free_tlb
305
364
#define p4d_free_tlb (tlb , pudp , address ) \
306
365
do { \
307
- __tlb_adjust_range(tlb, address, PAGE_SIZE); \
366
+ __tlb_adjust_range(tlb, address, PAGE_SIZE); \
367
+ tlb->freed_tables = 1; \
308
368
__p4d_free_tlb(tlb, pudp, address); \
309
369
} while (0)
310
370
#endif
311
371
#endif
312
372
373
+ #endif /* CONFIG_MMU */
374
+
313
375
#define tlb_migrate_finish (mm ) do {} while (0)
314
376
315
377
#endif /* _ASM_GENERIC__TLB_H */
0 commit comments