diff options
-rw-r--r-- | arch/x86/include/asm/tlbflush.h | 13 | ||||
-rw-r--r-- | arch/x86/mm/tlb.c | 30 |
2 files changed, 37 insertions, 6 deletions
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 621b959e1dbf..b5a27bd77669 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h | |||
@@ -123,6 +123,12 @@ static inline void reset_lazy_tlbstate(void) | |||
123 | { | 123 | { |
124 | } | 124 | } |
125 | 125 | ||
126 | static inline void flush_tlb_kernel_range(unsigned long start, | ||
127 | unsigned long end) | ||
128 | { | ||
129 | flush_tlb_all(); | ||
130 | } | ||
131 | |||
126 | #else /* SMP */ | 132 | #else /* SMP */ |
127 | 133 | ||
128 | #include <asm/smp.h> | 134 | #include <asm/smp.h> |
@@ -139,6 +145,7 @@ extern void flush_tlb_current_task(void); | |||
139 | extern void flush_tlb_page(struct vm_area_struct *, unsigned long); | 145 | extern void flush_tlb_page(struct vm_area_struct *, unsigned long); |
140 | extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, | 146 | extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, |
141 | unsigned long end, unsigned long vmflag); | 147 | unsigned long end, unsigned long vmflag); |
148 | extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); | ||
142 | 149 | ||
143 | #define flush_tlb() flush_tlb_current_task() | 150 | #define flush_tlb() flush_tlb_current_task() |
144 | 151 | ||
@@ -168,10 +175,4 @@ static inline void reset_lazy_tlbstate(void) | |||
168 | native_flush_tlb_others(mask, mm, start, end) | 175 | native_flush_tlb_others(mask, mm, start, end) |
169 | #endif | 176 | #endif |
170 | 177 | ||
171 | static inline void flush_tlb_kernel_range(unsigned long start, | ||
172 | unsigned long end) | ||
173 | { | ||
174 | flush_tlb_all(); | ||
175 | } | ||
176 | |||
177 | #endif /* _ASM_X86_TLBFLUSH_H */ | 178 | #endif /* _ASM_X86_TLBFLUSH_H */ |
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 2b5f506a7655..613cd83e8c0c 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c | |||
@@ -264,6 +264,36 @@ void flush_tlb_all(void) | |||
264 | on_each_cpu(do_flush_tlb_all, NULL, 1); | 264 | on_each_cpu(do_flush_tlb_all, NULL, 1); |
265 | } | 265 | } |
266 | 266 | ||
267 | static void do_kernel_range_flush(void *info) | ||
268 | { | ||
269 | struct flush_tlb_info *f = info; | ||
270 | unsigned long addr; | ||
271 | |||
272 | /* flush range by one by one 'invlpg' */ | ||
273 | for (addr = f->flush_start; addr < f->flush_end; addr += PAGE_SIZE) | ||
274 | __flush_tlb_single(addr); | ||
275 | } | ||
276 | |||
277 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
278 | { | ||
279 | unsigned act_entries; | ||
280 | struct flush_tlb_info info; | ||
281 | |||
282 | /* In modern CPU, last level tlb used for both data/ins */ | ||
283 | act_entries = tlb_lld_4k[ENTRIES]; | ||
284 | |||
285 | /* Balance as user space task's flush, a bit conservative */ | ||
286 | if (end == TLB_FLUSH_ALL || tlb_flushall_shift == -1 || | ||
287 | (end - start) >> PAGE_SHIFT > act_entries >> tlb_flushall_shift) | ||
288 | |||
289 | on_each_cpu(do_flush_tlb_all, NULL, 1); | ||
290 | else { | ||
291 | info.flush_start = start; | ||
292 | info.flush_end = end; | ||
293 | on_each_cpu(do_kernel_range_flush, &info, 1); | ||
294 | } | ||
295 | } | ||
296 | |||
267 | #ifdef CONFIG_DEBUG_TLBFLUSH | 297 | #ifdef CONFIG_DEBUG_TLBFLUSH |
268 | static ssize_t tlbflush_read_file(struct file *file, char __user *user_buf, | 298 | static ssize_t tlbflush_read_file(struct file *file, char __user *user_buf, |
269 | size_t count, loff_t *ppos) | 299 | size_t count, loff_t *ppos) |