diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-22 14:42:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-22 14:42:28 -0400 |
commit | a065de0d257779ed1b8ee6e0c005ad6b1d989cef (patch) | |
tree | 04621d978868b8cb9c183e3e1d70929491128c19 /arch | |
parent | 3992c0321258bdff3666cbaf5225f538ad61a548 (diff) | |
parent | a7101d152665817bf7cafc47e7f5dcb1f54664fe (diff) |
Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/asm changes from Ingo Molnar:
"Assorted single-commit improvements, as usual"
* 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/mm/mtrr: Slightly simplify print_mtrr_state()
x86/mm/mtrr: Fix alignment determination in range_to_mtrr()
x86/copy_user_generic: Optimize copy_user_generic with CPU erms feature
x86/alternatives: Use atomic_xchg() instead atomic_dec_and_test() for stop_machine_text_poke()
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/alternative.h | 74 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess_64.h | 11 | ||||
-rw-r--r-- | arch/x86/kernel/alternative.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/cleanup.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/generic.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/x8664_ksyms_64.c | 1 |
6 files changed, 75 insertions, 25 deletions
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 49331bedc158..70780689599a 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h | |||
@@ -75,23 +75,54 @@ static inline int alternatives_text_reserved(void *start, void *end) | |||
75 | } | 75 | } |
76 | #endif /* CONFIG_SMP */ | 76 | #endif /* CONFIG_SMP */ |
77 | 77 | ||
78 | #define OLDINSTR(oldinstr) "661:\n\t" oldinstr "\n662:\n" | ||
79 | |||
80 | #define b_replacement(number) "663"#number | ||
81 | #define e_replacement(number) "664"#number | ||
82 | |||
83 | #define alt_slen "662b-661b" | ||
84 | #define alt_rlen(number) e_replacement(number)"f-"b_replacement(number)"f" | ||
85 | |||
86 | #define ALTINSTR_ENTRY(feature, number) \ | ||
87 | " .long 661b - .\n" /* label */ \ | ||
88 | " .long " b_replacement(number)"f - .\n" /* new instruction */ \ | ||
89 | " .word " __stringify(feature) "\n" /* feature bit */ \ | ||
90 | " .byte " alt_slen "\n" /* source len */ \ | ||
91 | " .byte " alt_rlen(number) "\n" /* replacement len */ | ||
92 | |||
93 | #define DISCARD_ENTRY(number) /* rlen <= slen */ \ | ||
94 | " .byte 0xff + (" alt_rlen(number) ") - (" alt_slen ")\n" | ||
95 | |||
96 | #define ALTINSTR_REPLACEMENT(newinstr, feature, number) /* replacement */ \ | ||
97 | b_replacement(number)":\n\t" newinstr "\n" e_replacement(number) ":\n\t" | ||
98 | |||
78 | /* alternative assembly primitive: */ | 99 | /* alternative assembly primitive: */ |
79 | #define ALTERNATIVE(oldinstr, newinstr, feature) \ | 100 | #define ALTERNATIVE(oldinstr, newinstr, feature) \ |
80 | \ | 101 | OLDINSTR(oldinstr) \ |
81 | "661:\n\t" oldinstr "\n662:\n" \ | 102 | ".section .altinstructions,\"a\"\n" \ |
82 | ".section .altinstructions,\"a\"\n" \ | 103 | ALTINSTR_ENTRY(feature, 1) \ |
83 | " .long 661b - .\n" /* label */ \ | 104 | ".previous\n" \ |
84 | " .long 663f - .\n" /* new instruction */ \ | 105 | ".section .discard,\"aw\",@progbits\n" \ |
85 | " .word " __stringify(feature) "\n" /* feature bit */ \ | 106 | DISCARD_ENTRY(1) \ |
86 | " .byte 662b-661b\n" /* sourcelen */ \ | 107 | ".previous\n" \ |
87 | " .byte 664f-663f\n" /* replacementlen */ \ | 108 | ".section .altinstr_replacement, \"ax\"\n" \ |
88 | ".previous\n" \ | 109 | ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ |
89 | ".section .discard,\"aw\",@progbits\n" \ | 110 | ".previous" |
90 | " .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */ \ | 111 | |
91 | ".previous\n" \ | 112 | #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ |
92 | ".section .altinstr_replacement, \"ax\"\n" \ | 113 | OLDINSTR(oldinstr) \ |
93 | "663:\n\t" newinstr "\n664:\n" /* replacement */ \ | 114 | ".section .altinstructions,\"a\"\n" \ |
94 | ".previous" | 115 | ALTINSTR_ENTRY(feature1, 1) \ |
116 | ALTINSTR_ENTRY(feature2, 2) \ | ||
117 | ".previous\n" \ | ||
118 | ".section .discard,\"aw\",@progbits\n" \ | ||
119 | DISCARD_ENTRY(1) \ | ||
120 | DISCARD_ENTRY(2) \ | ||
121 | ".previous\n" \ | ||
122 | ".section .altinstr_replacement, \"ax\"\n" \ | ||
123 | ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ | ||
124 | ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ | ||
125 | ".previous" | ||
95 | 126 | ||
96 | /* | 127 | /* |
97 | * This must be included *after* the definition of ALTERNATIVE due to | 128 | * This must be included *after* the definition of ALTERNATIVE due to |
@@ -140,6 +171,19 @@ static inline int alternatives_text_reserved(void *start, void *end) | |||
140 | : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) | 171 | : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) |
141 | 172 | ||
142 | /* | 173 | /* |
174 | * Like alternative_call, but there are two features and respective functions. | ||
175 | * If CPU has feature2, function2 is used. | ||
176 | * Otherwise, if CPU has feature1, function1 is used. | ||
177 | * Otherwise, old function is used. | ||
178 | */ | ||
179 | #define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \ | ||
180 | output, input...) \ | ||
181 | asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\ | ||
182 | "call %P[new2]", feature2) \ | ||
183 | : output : [old] "i" (oldfunc), [new1] "i" (newfunc1), \ | ||
184 | [new2] "i" (newfunc2), ## input) | ||
185 | |||
186 | /* | ||
143 | * use this macro(s) if you need more than one output parameter | 187 | * use this macro(s) if you need more than one output parameter |
144 | * in alternative_io | 188 | * in alternative_io |
145 | */ | 189 | */ |
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 8e796fbbf9c6..d8def8b3dba0 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h | |||
@@ -17,6 +17,8 @@ | |||
17 | 17 | ||
18 | /* Handles exceptions in both to and from, but doesn't do access_ok */ | 18 | /* Handles exceptions in both to and from, but doesn't do access_ok */ |
19 | __must_check unsigned long | 19 | __must_check unsigned long |
20 | copy_user_enhanced_fast_string(void *to, const void *from, unsigned len); | ||
21 | __must_check unsigned long | ||
20 | copy_user_generic_string(void *to, const void *from, unsigned len); | 22 | copy_user_generic_string(void *to, const void *from, unsigned len); |
21 | __must_check unsigned long | 23 | __must_check unsigned long |
22 | copy_user_generic_unrolled(void *to, const void *from, unsigned len); | 24 | copy_user_generic_unrolled(void *to, const void *from, unsigned len); |
@@ -26,9 +28,16 @@ copy_user_generic(void *to, const void *from, unsigned len) | |||
26 | { | 28 | { |
27 | unsigned ret; | 29 | unsigned ret; |
28 | 30 | ||
29 | alternative_call(copy_user_generic_unrolled, | 31 | /* |
32 | * If CPU has ERMS feature, use copy_user_enhanced_fast_string. | ||
33 | * Otherwise, if CPU has rep_good feature, use copy_user_generic_string. | ||
34 | * Otherwise, use copy_user_generic_unrolled. | ||
35 | */ | ||
36 | alternative_call_2(copy_user_generic_unrolled, | ||
30 | copy_user_generic_string, | 37 | copy_user_generic_string, |
31 | X86_FEATURE_REP_GOOD, | 38 | X86_FEATURE_REP_GOOD, |
39 | copy_user_enhanced_fast_string, | ||
40 | X86_FEATURE_ERMS, | ||
32 | ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from), | 41 | ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from), |
33 | "=d" (len)), | 42 | "=d" (len)), |
34 | "1" (to), "2" (from), "3" (len) | 43 | "1" (to), "2" (from), "3" (len) |
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 1f84794f0759..53231a045d3d 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -664,7 +664,7 @@ static int __kprobes stop_machine_text_poke(void *data) | |||
664 | struct text_poke_param *p; | 664 | struct text_poke_param *p; |
665 | int i; | 665 | int i; |
666 | 666 | ||
667 | if (atomic_dec_and_test(&stop_machine_first)) { | 667 | if (atomic_xchg(&stop_machine_first, 0)) { |
668 | for (i = 0; i < tpp->nparams; i++) { | 668 | for (i = 0; i < tpp->nparams; i++) { |
669 | p = &tpp->params[i]; | 669 | p = &tpp->params[i]; |
670 | text_poke(p->addr, p->opcode, p->len); | 670 | text_poke(p->addr, p->opcode, p->len); |
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c index bdda2e6c673b..35ffda5d0727 100644 --- a/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c | |||
@@ -258,11 +258,11 @@ range_to_mtrr(unsigned int reg, unsigned long range_startk, | |||
258 | 258 | ||
259 | /* Compute the maximum size with which we can make a range: */ | 259 | /* Compute the maximum size with which we can make a range: */ |
260 | if (range_startk) | 260 | if (range_startk) |
261 | max_align = ffs(range_startk) - 1; | 261 | max_align = __ffs(range_startk); |
262 | else | 262 | else |
263 | max_align = 32; | 263 | max_align = BITS_PER_LONG - 1; |
264 | 264 | ||
265 | align = fls(range_sizek) - 1; | 265 | align = __fls(range_sizek); |
266 | if (align > max_align) | 266 | if (align > max_align) |
267 | align = max_align; | 267 | align = max_align; |
268 | 268 | ||
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 75772ae6c65f..e9fe907cd249 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c | |||
@@ -361,11 +361,7 @@ static void __init print_mtrr_state(void) | |||
361 | } | 361 | } |
362 | pr_debug("MTRR variable ranges %sabled:\n", | 362 | pr_debug("MTRR variable ranges %sabled:\n", |
363 | mtrr_state.enabled & 2 ? "en" : "dis"); | 363 | mtrr_state.enabled & 2 ? "en" : "dis"); |
364 | if (size_or_mask & 0xffffffffUL) | 364 | high_width = (__ffs64(size_or_mask) - (32 - PAGE_SHIFT) + 3) / 4; |
365 | high_width = ffs(size_or_mask & 0xffffffffUL) - 1; | ||
366 | else | ||
367 | high_width = ffs(size_or_mask>>32) + 32 - 1; | ||
368 | high_width = (high_width - (32 - PAGE_SHIFT) + 3) / 4; | ||
369 | 365 | ||
370 | for (i = 0; i < num_var_ranges; ++i) { | 366 | for (i = 0; i < num_var_ranges; ++i) { |
371 | if (mtrr_state.var_ranges[i].mask_lo & (1 << 11)) | 367 | if (mtrr_state.var_ranges[i].mask_lo & (1 << 11)) |
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c index 9796c2f3d074..6020f6f5927c 100644 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ b/arch/x86/kernel/x8664_ksyms_64.c | |||
@@ -28,6 +28,7 @@ EXPORT_SYMBOL(__put_user_8); | |||
28 | 28 | ||
29 | EXPORT_SYMBOL(copy_user_generic_string); | 29 | EXPORT_SYMBOL(copy_user_generic_string); |
30 | EXPORT_SYMBOL(copy_user_generic_unrolled); | 30 | EXPORT_SYMBOL(copy_user_generic_unrolled); |
31 | EXPORT_SYMBOL(copy_user_enhanced_fast_string); | ||
31 | EXPORT_SYMBOL(__copy_user_nocache); | 32 | EXPORT_SYMBOL(__copy_user_nocache); |
32 | EXPORT_SYMBOL(_copy_from_user); | 33 | EXPORT_SYMBOL(_copy_from_user); |
33 | EXPORT_SYMBOL(_copy_to_user); | 34 | EXPORT_SYMBOL(_copy_to_user); |