summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2015-07-24 09:09:55 -0400
committerIngo Molnar <mingo@kernel.org>2015-08-03 05:34:15 -0400
commit11276d5306b8e5b438a36bbff855fe792d7eaa61 (patch)
tree9ddfc5e1bec6174e838cce8eb67af9e911c4e5f8 /arch
parent706249c222f68471b6f8e9e8e9b77665c404b226 (diff)
locking/static_keys: Add a new static_key interface
There are various problems and short-comings with the current static_key interface: - static_key_{true,false}() read like a branch depending on the key value, instead of the actual likely/unlikely branch depending on init value. - static_key_{true,false}() are, as stated above, tied to the static_key init values STATIC_KEY_INIT_{TRUE,FALSE}. - we're limited to the 2 (out of 4) possible options that compile to a default NOP because that's what our arch_static_branch() assembly emits. So provide a new static_key interface: DEFINE_STATIC_KEY_TRUE(name); DEFINE_STATIC_KEY_FALSE(name); Which define a key of different types with an initial true/false value. Then allow: static_branch_likely() static_branch_unlikely() to take a key of either type and emit the right instruction for the case. This means adding a second arch_static_branch_jump() assembly helper which emits a JMP per default. In order to determine the right instruction for the right state, encode the branch type in the LSB of jump_entry::key. This is the final step in removing the naming confusion that has led to a stream of avoidable bugs such as: a833581e372a ("x86, perf: Fix static_key bug in load_mm_cr4()") ... but it also allows new static key combinations that will give us performance enhancements in the subsequent patches. Tested-by: Rabin Vincent <rabin@rab.in> # arm Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Michael Ellerman <mpe@ellerman.id.au> # ppc Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com> # s390 Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/jump_label.h25
-rw-r--r--arch/arm64/include/asm/jump_label.h18
-rw-r--r--arch/mips/include/asm/jump_label.h19
-rw-r--r--arch/powerpc/include/asm/jump_label.h19
-rw-r--r--arch/s390/include/asm/jump_label.h19
-rw-r--r--arch/sparc/include/asm/jump_label.h35
-rw-r--r--arch/x86/include/asm/jump_label.h21
7 files changed, 129 insertions, 27 deletions
diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h
index 5f337dc5c108..34f7b6980d21 100644
--- a/arch/arm/include/asm/jump_label.h
+++ b/arch/arm/include/asm/jump_label.h
@@ -4,23 +4,32 @@
4#ifndef __ASSEMBLY__ 4#ifndef __ASSEMBLY__
5 5
6#include <linux/types.h> 6#include <linux/types.h>
7#include <asm/unified.h>
7 8
8#define JUMP_LABEL_NOP_SIZE 4 9#define JUMP_LABEL_NOP_SIZE 4
9 10
10#ifdef CONFIG_THUMB2_KERNEL 11static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
11#define JUMP_LABEL_NOP "nop.w" 12{
12#else 13 asm_volatile_goto("1:\n\t"
13#define JUMP_LABEL_NOP "nop" 14 WASM(nop) "\n\t"
14#endif 15 ".pushsection __jump_table, \"aw\"\n\t"
16 ".word 1b, %l[l_yes], %c0\n\t"
17 ".popsection\n\t"
18 : : "i" (&((char *)key)[branch]) : : l_yes);
19
20 return false;
21l_yes:
22 return true;
23}
15 24
16static __always_inline bool arch_static_branch(struct static_key *key) 25static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
17{ 26{
18 asm_volatile_goto("1:\n\t" 27 asm_volatile_goto("1:\n\t"
19 JUMP_LABEL_NOP "\n\t" 28 WASM(b) " %l[l_yes]\n\t"
20 ".pushsection __jump_table, \"aw\"\n\t" 29 ".pushsection __jump_table, \"aw\"\n\t"
21 ".word 1b, %l[l_yes], %c0\n\t" 30 ".word 1b, %l[l_yes], %c0\n\t"
22 ".popsection\n\t" 31 ".popsection\n\t"
23 : : "i" (key) : : l_yes); 32 : : "i" (&((char *)key)[branch]) : : l_yes);
24 33
25 return false; 34 return false;
26l_yes: 35l_yes:
diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h
index c0e5165c2f76..1b5e0e843c3a 100644
--- a/arch/arm64/include/asm/jump_label.h
+++ b/arch/arm64/include/asm/jump_label.h
@@ -26,14 +26,28 @@
26 26
27#define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE 27#define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE
28 28
29static __always_inline bool arch_static_branch(struct static_key *key) 29static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
30{ 30{
31 asm goto("1: nop\n\t" 31 asm goto("1: nop\n\t"
32 ".pushsection __jump_table, \"aw\"\n\t" 32 ".pushsection __jump_table, \"aw\"\n\t"
33 ".align 3\n\t" 33 ".align 3\n\t"
34 ".quad 1b, %l[l_yes], %c0\n\t" 34 ".quad 1b, %l[l_yes], %c0\n\t"
35 ".popsection\n\t" 35 ".popsection\n\t"
36 : : "i"(key) : : l_yes); 36 : : "i"(&((char *)key)[branch]) : : l_yes);
37
38 return false;
39l_yes:
40 return true;
41}
42
43static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
44{
45 asm goto("1: b %l[l_yes]\n\t"
46 ".pushsection __jump_table, \"aw\"\n\t"
47 ".align 3\n\t"
48 ".quad 1b, %l[l_yes], %c0\n\t"
49 ".popsection\n\t"
50 : : "i"(&((char *)key)[branch]) : : l_yes);
37 51
38 return false; 52 return false;
39l_yes: 53l_yes:
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h
index 608aa57799c8..e77672539e8e 100644
--- a/arch/mips/include/asm/jump_label.h
+++ b/arch/mips/include/asm/jump_label.h
@@ -26,14 +26,29 @@
26#define NOP_INSN "nop" 26#define NOP_INSN "nop"
27#endif 27#endif
28 28
29static __always_inline bool arch_static_branch(struct static_key *key) 29static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
30{ 30{
31 asm_volatile_goto("1:\t" NOP_INSN "\n\t" 31 asm_volatile_goto("1:\t" NOP_INSN "\n\t"
32 "nop\n\t" 32 "nop\n\t"
33 ".pushsection __jump_table, \"aw\"\n\t" 33 ".pushsection __jump_table, \"aw\"\n\t"
34 WORD_INSN " 1b, %l[l_yes], %0\n\t" 34 WORD_INSN " 1b, %l[l_yes], %0\n\t"
35 ".popsection\n\t" 35 ".popsection\n\t"
36 : : "i" (key) : : l_yes); 36 : : "i" (&((char *)key)[branch]) : : l_yes);
37
38 return false;
39l_yes:
40 return true;
41}
42
43static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
44{
45 asm_volatile_goto("1:\tj %l[l_yes]\n\t"
46 "nop\n\t"
47 ".pushsection __jump_table, \"aw\"\n\t"
48 WORD_INSN " 1b, %l[l_yes], %0\n\t"
49 ".popsection\n\t"
50 : : "i" (&((char *)key)[branch]) : : l_yes);
51
37 return false; 52 return false;
38l_yes: 53l_yes:
39 return true; 54 return true;
diff --git a/arch/powerpc/include/asm/jump_label.h b/arch/powerpc/include/asm/jump_label.h
index efbf9a322a23..47e155f15433 100644
--- a/arch/powerpc/include/asm/jump_label.h
+++ b/arch/powerpc/include/asm/jump_label.h
@@ -18,14 +18,29 @@
18#define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG) 18#define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG)
19#define JUMP_LABEL_NOP_SIZE 4 19#define JUMP_LABEL_NOP_SIZE 4
20 20
21static __always_inline bool arch_static_branch(struct static_key *key) 21static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
22{ 22{
23 asm_volatile_goto("1:\n\t" 23 asm_volatile_goto("1:\n\t"
24 "nop\n\t" 24 "nop\n\t"
25 ".pushsection __jump_table, \"aw\"\n\t" 25 ".pushsection __jump_table, \"aw\"\n\t"
26 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t" 26 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
27 ".popsection \n\t" 27 ".popsection \n\t"
28 : : "i" (key) : : l_yes); 28 : : "i" (&((char *)key)[branch]) : : l_yes);
29
30 return false;
31l_yes:
32 return true;
33}
34
35static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
36{
37 asm_volatile_goto("1:\n\t"
38 "b %l[l_yes]\n\t"
39 ".pushsection __jump_table, \"aw\"\n\t"
40 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
41 ".popsection \n\t"
42 : : "i" (&((char *)key)[branch]) : : l_yes);
43
29 return false; 44 return false;
30l_yes: 45l_yes:
31 return true; 46 return true;
diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h
index 69972b7957ee..7f9fd5e3f1bf 100644
--- a/arch/s390/include/asm/jump_label.h
+++ b/arch/s390/include/asm/jump_label.h
@@ -12,14 +12,29 @@
12 * We use a brcl 0,2 instruction for jump labels at compile time so it 12 * We use a brcl 0,2 instruction for jump labels at compile time so it
13 * can be easily distinguished from a hotpatch generated instruction. 13 * can be easily distinguished from a hotpatch generated instruction.
14 */ 14 */
15static __always_inline bool arch_static_branch(struct static_key *key) 15static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
16{ 16{
17 asm_volatile_goto("0: brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n" 17 asm_volatile_goto("0: brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"
18 ".pushsection __jump_table, \"aw\"\n" 18 ".pushsection __jump_table, \"aw\"\n"
19 ".balign 8\n" 19 ".balign 8\n"
20 ".quad 0b, %l[label], %0\n" 20 ".quad 0b, %l[label], %0\n"
21 ".popsection\n" 21 ".popsection\n"
22 : : "X" (key) : : label); 22 : : "X" (&((char *)key)[branch]) : : label);
23
24 return false;
25label:
26 return true;
27}
28
29static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
30{
31 asm_volatile_goto("0: brcl 15, %l[label]\n"
32 ".pushsection __jump_table, \"aw\"\n"
33 ".balign 8\n"
34 ".quad 0b, %l[label], %0\n"
35 ".popsection\n"
36 : : "X" (&((char *)key)[branch]) : : label);
37
23 return false; 38 return false;
24label: 39label:
25 return true; 40 return true;
diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h
index cc9b04a2b11b..62d0354d1727 100644
--- a/arch/sparc/include/asm/jump_label.h
+++ b/arch/sparc/include/asm/jump_label.h
@@ -7,16 +7,33 @@
7 7
8#define JUMP_LABEL_NOP_SIZE 4 8#define JUMP_LABEL_NOP_SIZE 4
9 9
10static __always_inline bool arch_static_branch(struct static_key *key) 10static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
11{ 11{
12 asm_volatile_goto("1:\n\t" 12 asm_volatile_goto("1:\n\t"
13 "nop\n\t" 13 "nop\n\t"
14 "nop\n\t" 14 "nop\n\t"
15 ".pushsection __jump_table, \"aw\"\n\t" 15 ".pushsection __jump_table, \"aw\"\n\t"
16 ".align 4\n\t" 16 ".align 4\n\t"
17 ".word 1b, %l[l_yes], %c0\n\t" 17 ".word 1b, %l[l_yes], %c0\n\t"
18 ".popsection \n\t" 18 ".popsection \n\t"
19 : : "i" (key) : : l_yes); 19 : : "i" (&((char *)key)[branch]) : : l_yes);
20
21 return false;
22l_yes:
23 return true;
24}
25
26static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
27{
28 asm_volatile_goto("1:\n\t"
29 "b %l[l_yes]\n\t"
30 "nop\n\t"
31 ".pushsection __jump_table, \"aw\"\n\t"
32 ".align 4\n\t"
33 ".word 1b, %l[l_yes], %c0\n\t"
34 ".popsection \n\t"
35 : : "i" (&((char *)key)[branch]) : : l_yes);
36
20 return false; 37 return false;
21l_yes: 38l_yes:
22 return true; 39 return true;
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index a4c1cf7e93f8..28d7a857f9d1 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -16,7 +16,7 @@
16# define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC 16# define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC
17#endif 17#endif
18 18
19static __always_inline bool arch_static_branch(struct static_key *key) 19static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
20{ 20{
21 asm_volatile_goto("1:" 21 asm_volatile_goto("1:"
22 ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t" 22 ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t"
@@ -24,7 +24,24 @@ static __always_inline bool arch_static_branch(struct static_key *key)
24 _ASM_ALIGN "\n\t" 24 _ASM_ALIGN "\n\t"
25 _ASM_PTR "1b, %l[l_yes], %c0 \n\t" 25 _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
26 ".popsection \n\t" 26 ".popsection \n\t"
27 : : "i" (key) : : l_yes); 27 : : "i" (&((char *)key)[branch]) : : l_yes);
28
29 return false;
30l_yes:
31 return true;
32}
33
34static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
35{
36 asm_volatile_goto("1:"
37 ".byte 0xe9\n\t .long %l[l_yes] - 2f\n\t"
38 "2:\n\t"
39 ".pushsection __jump_table, \"aw\" \n\t"
40 _ASM_ALIGN "\n\t"
41 _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
42 ".popsection \n\t"
43 : : "i" (&((char *)key)[branch]) : : l_yes);
44
28 return false; 45 return false;
29l_yes: 46l_yes:
30 return true; 47 return true;