diff options
-rw-r--r-- | arch/x86/mm/pageattr.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 7823adab96e4..bbe691dd272e 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -52,6 +52,37 @@ static void global_flush_tlb(void) | |||
52 | on_each_cpu(flush_kernel_map, NULL, 1, 1); | 52 | on_each_cpu(flush_kernel_map, NULL, 1, 1); |
53 | } | 53 | } |
54 | 54 | ||
55 | struct clflush_data { | ||
56 | unsigned long addr; | ||
57 | int numpages; | ||
58 | }; | ||
59 | |||
60 | static void __cpa_flush_range(void *arg) | ||
61 | { | ||
62 | struct clflush_data *cld = arg; | ||
63 | |||
64 | /* | ||
65 | * We could optimize that further and do individual per page | ||
66 | * tlb invalidates for a low number of pages. Caveat: we must | ||
67 | * flush the high aliases on 64bit as well. | ||
68 | */ | ||
69 | __flush_tlb_all(); | ||
70 | |||
71 | clflush_cache_range((void *) cld->addr, cld->numpages * PAGE_SIZE); | ||
72 | } | ||
73 | |||
74 | static void cpa_flush_range(unsigned long addr, int numpages) | ||
75 | { | ||
76 | struct clflush_data cld; | ||
77 | |||
78 | BUG_ON(irqs_disabled()); | ||
79 | |||
80 | cld.addr = addr; | ||
81 | cld.numpages = numpages; | ||
82 | |||
83 | on_each_cpu(__cpa_flush_range, &cld, 1, 1); | ||
84 | } | ||
85 | |||
55 | /* | 86 | /* |
56 | * Certain areas of memory on x86 require very specific protection flags, | 87 | * Certain areas of memory on x86 require very specific protection flags, |
57 | * for example the BIOS area or kernel text. Callers don't always get this | 88 | * for example the BIOS area or kernel text. Callers don't always get this |
@@ -316,7 +347,16 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, | |||
316 | int ret = __change_page_attr_set_clr(addr, numpages, mask_set, | 347 | int ret = __change_page_attr_set_clr(addr, numpages, mask_set, |
317 | mask_clr); | 348 | mask_clr); |
318 | 349 | ||
319 | global_flush_tlb(); | 350 | /* |
351 | * On success we use clflush, when the CPU supports it to | ||
352 | * avoid the wbindv. If the CPU does not support it and in the | ||
353 | * error case we fall back to global_flush_tlb (which uses | ||
354 | * wbindv): | ||
355 | */ | ||
356 | if (!ret && cpu_has_clflush) | ||
357 | cpa_flush_range(addr, numpages); | ||
358 | else | ||
359 | global_flush_tlb(); | ||
320 | 360 | ||
321 | return ret; | 361 | return ret; |
322 | } | 362 | } |