aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/tlbflush.h13
-rw-r--r--arch/x86/mm/tlb.c30
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
126static 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);
139extern void flush_tlb_page(struct vm_area_struct *, unsigned long); 145extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
140extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, 146extern 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);
148extern 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
171static 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
267static 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
277void 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
268static ssize_t tlbflush_read_file(struct file *file, char __user *user_buf, 298static 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)