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) |
