|
@@ -107,12 +107,12 @@ static inline int static_key_count(struct static_key *key)
|
|
|
|
|
|
static __always_inline bool static_key_false(struct static_key *key)
|
|
|
{
|
|
|
- return arch_static_branch(key);
|
|
|
+ return arch_static_branch(key, false);
|
|
|
}
|
|
|
|
|
|
static __always_inline bool static_key_true(struct static_key *key)
|
|
|
{
|
|
|
- return !static_key_false(key);
|
|
|
+ return !arch_static_branch(key, true);
|
|
|
}
|
|
|
|
|
|
extern struct jump_entry __start___jump_table[];
|
|
@@ -130,12 +130,12 @@ extern void static_key_slow_inc(struct static_key *key);
|
|
|
extern void static_key_slow_dec(struct static_key *key);
|
|
|
extern void jump_label_apply_nops(struct module *mod);
|
|
|
|
|
|
-#define STATIC_KEY_INIT_TRUE ((struct static_key) \
|
|
|
+#define STATIC_KEY_INIT_TRUE \
|
|
|
{ .enabled = ATOMIC_INIT(1), \
|
|
|
- .entries = (void *)JUMP_TYPE_TRUE })
|
|
|
-#define STATIC_KEY_INIT_FALSE ((struct static_key) \
|
|
|
+ .entries = (void *)JUMP_TYPE_TRUE }
|
|
|
+#define STATIC_KEY_INIT_FALSE \
|
|
|
{ .enabled = ATOMIC_INIT(0), \
|
|
|
- .entries = (void *)JUMP_TYPE_FALSE })
|
|
|
+ .entries = (void *)JUMP_TYPE_FALSE }
|
|
|
|
|
|
#else /* !HAVE_JUMP_LABEL */
|
|
|
|
|
@@ -183,10 +183,8 @@ static inline int jump_label_apply_nops(struct module *mod)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-#define STATIC_KEY_INIT_TRUE ((struct static_key) \
|
|
|
- { .enabled = ATOMIC_INIT(1) })
|
|
|
-#define STATIC_KEY_INIT_FALSE ((struct static_key) \
|
|
|
- { .enabled = ATOMIC_INIT(0) })
|
|
|
+#define STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) }
|
|
|
+#define STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) }
|
|
|
|
|
|
#endif /* HAVE_JUMP_LABEL */
|
|
|
|
|
@@ -218,6 +216,137 @@ static inline void static_key_disable(struct static_key *key)
|
|
|
static_key_slow_dec(key);
|
|
|
}
|
|
|
|
|
|
+/* -------------------------------------------------------------------------- */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Two type wrappers around static_key, such that we can use compile time
|
|
|
+ * type differentiation to emit the right code.
|
|
|
+ *
|
|
|
+ * All the below code is macros in order to play type games.
|
|
|
+ */
|
|
|
+
|
|
|
+struct static_key_true {
|
|
|
+ struct static_key key;
|
|
|
+};
|
|
|
+
|
|
|
+struct static_key_false {
|
|
|
+ struct static_key key;
|
|
|
+};
|
|
|
+
|
|
|
+#define STATIC_KEY_TRUE_INIT (struct static_key_true) { .key = STATIC_KEY_INIT_TRUE, }
|
|
|
+#define STATIC_KEY_FALSE_INIT (struct static_key_false){ .key = STATIC_KEY_INIT_FALSE, }
|
|
|
+
|
|
|
+#define DEFINE_STATIC_KEY_TRUE(name) \
|
|
|
+ struct static_key_true name = STATIC_KEY_TRUE_INIT
|
|
|
+
|
|
|
+#define DEFINE_STATIC_KEY_FALSE(name) \
|
|
|
+ struct static_key_false name = STATIC_KEY_FALSE_INIT
|
|
|
+
|
|
|
+#ifdef HAVE_JUMP_LABEL
|
|
|
+
|
|
|
+/*
|
|
|
+ * Combine the right initial value (type) with the right branch order
|
|
|
+ * to generate the desired result.
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * type\branch| likely (1) | unlikely (0)
|
|
|
+ * -----------+-----------------------+------------------
|
|
|
+ * | |
|
|
|
+ * true (1) | ... | ...
|
|
|
+ * | NOP | JMP L
|
|
|
+ * | <br-stmts> | 1: ...
|
|
|
+ * | L: ... |
|
|
|
+ * | |
|
|
|
+ * | | L: <br-stmts>
|
|
|
+ * | | jmp 1b
|
|
|
+ * | |
|
|
|
+ * -----------+-----------------------+------------------
|
|
|
+ * | |
|
|
|
+ * false (0) | ... | ...
|
|
|
+ * | JMP L | NOP
|
|
|
+ * | <br-stmts> | 1: ...
|
|
|
+ * | L: ... |
|
|
|
+ * | |
|
|
|
+ * | | L: <br-stmts>
|
|
|
+ * | | jmp 1b
|
|
|
+ * | |
|
|
|
+ * -----------+-----------------------+------------------
|
|
|
+ *
|
|
|
+ * The initial value is encoded in the LSB of static_key::entries,
|
|
|
+ * type: 0 = false, 1 = true.
|
|
|
+ *
|
|
|
+ * The branch type is encoded in the LSB of jump_entry::key,
|
|
|
+ * branch: 0 = unlikely, 1 = likely.
|
|
|
+ *
|
|
|
+ * This gives the following logic table:
|
|
|
+ *
|
|
|
+ * enabled type branch instuction
|
|
|
+ * -----------------------------+-----------
|
|
|
+ * 0 0 0 | NOP
|
|
|
+ * 0 0 1 | JMP
|
|
|
+ * 0 1 0 | NOP
|
|
|
+ * 0 1 1 | JMP
|
|
|
+ *
|
|
|
+ * 1 0 0 | JMP
|
|
|
+ * 1 0 1 | NOP
|
|
|
+ * 1 1 0 | JMP
|
|
|
+ * 1 1 1 | NOP
|
|
|
+ *
|
|
|
+ * Which gives the following functions:
|
|
|
+ *
|
|
|
+ * dynamic: instruction = enabled ^ branch
|
|
|
+ * static: instruction = type ^ branch
|
|
|
+ *
|
|
|
+ * See jump_label_type() / jump_label_init_type().
|
|
|
+ */
|
|
|
+
|
|
|
+extern bool ____wrong_branch_error(void);
|
|
|
+
|
|
|
+#define static_branch_likely(x) \
|
|
|
+({ \
|
|
|
+ bool branch; \
|
|
|
+ if (__builtin_types_compatible_p(typeof(*x), struct static_key_true)) \
|
|
|
+ branch = !arch_static_branch(&(x)->key, true); \
|
|
|
+ else if (__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \
|
|
|
+ branch = !arch_static_branch_jump(&(x)->key, true); \
|
|
|
+ else \
|
|
|
+ branch = ____wrong_branch_error(); \
|
|
|
+ branch; \
|
|
|
+})
|
|
|
+
|
|
|
+#define static_branch_unlikely(x) \
|
|
|
+({ \
|
|
|
+ bool branch; \
|
|
|
+ if (__builtin_types_compatible_p(typeof(*x), struct static_key_true)) \
|
|
|
+ branch = arch_static_branch_jump(&(x)->key, false); \
|
|
|
+ else if (__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \
|
|
|
+ branch = arch_static_branch(&(x)->key, false); \
|
|
|
+ else \
|
|
|
+ branch = ____wrong_branch_error(); \
|
|
|
+ branch; \
|
|
|
+})
|
|
|
+
|
|
|
+#else /* !HAVE_JUMP_LABEL */
|
|
|
+
|
|
|
+#define static_branch_likely(x) likely(static_key_enabled(&(x)->key))
|
|
|
+#define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key))
|
|
|
+
|
|
|
+#endif /* HAVE_JUMP_LABEL */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Advanced usage; refcount, branch is enabled when: count != 0
|
|
|
+ */
|
|
|
+
|
|
|
+#define static_branch_inc(x) static_key_slow_inc(&(x)->key)
|
|
|
+#define static_branch_dec(x) static_key_slow_dec(&(x)->key)
|
|
|
+
|
|
|
+/*
|
|
|
+ * Normal usage; boolean enable/disable.
|
|
|
+ */
|
|
|
+
|
|
|
+#define static_branch_enable(x) static_key_enable(&(x)->key)
|
|
|
+#define static_branch_disable(x) static_key_disable(&(x)->key)
|
|
|
+
|
|
|
#endif /* _LINUX_JUMP_LABEL_H */
|
|
|
|
|
|
#endif /* __ASSEMBLY__ */
|