1283c16a2SPaolo Abeni /* SPDX-License-Identifier: GPL-2.0 */
2283c16a2SPaolo Abeni #ifndef _LINUX_INDIRECT_CALL_WRAPPER_H
3283c16a2SPaolo Abeni #define _LINUX_INDIRECT_CALL_WRAPPER_H
4283c16a2SPaolo Abeni 
5283c16a2SPaolo Abeni #ifdef CONFIG_RETPOLINE
6283c16a2SPaolo Abeni 
7283c16a2SPaolo Abeni /*
8283c16a2SPaolo Abeni  * INDIRECT_CALL_$NR - wrapper for indirect calls with $NR known builtin
9283c16a2SPaolo Abeni  *  @f: function pointer
10283c16a2SPaolo Abeni  *  @f$NR: builtin functions names, up to $NR of them
11283c16a2SPaolo Abeni  *  @__VA_ARGS__: arguments for @f
12283c16a2SPaolo Abeni  *
13283c16a2SPaolo Abeni  * Avoid retpoline overhead for known builtin, checking @f vs each of them and
14283c16a2SPaolo Abeni  * eventually invoking directly the builtin function. The functions are check
15283c16a2SPaolo Abeni  * in the given order. Fallback to the indirect call.
16283c16a2SPaolo Abeni  */
17283c16a2SPaolo Abeni #define INDIRECT_CALL_1(f, f1, ...)					\
18283c16a2SPaolo Abeni 	({								\
19283c16a2SPaolo Abeni 		likely(f == f1) ? f1(__VA_ARGS__) : f(__VA_ARGS__);	\
20283c16a2SPaolo Abeni 	})
21283c16a2SPaolo Abeni #define INDIRECT_CALL_2(f, f2, f1, ...)					\
22283c16a2SPaolo Abeni 	({								\
23283c16a2SPaolo Abeni 		likely(f == f2) ? f2(__VA_ARGS__) :			\
24283c16a2SPaolo Abeni 				  INDIRECT_CALL_1(f, f1, __VA_ARGS__);	\
25283c16a2SPaolo Abeni 	})
26e678e9ddSBrian Vazquez #define INDIRECT_CALL_3(f, f3, f2, f1, ...)					\
27e678e9ddSBrian Vazquez 	({									\
28e678e9ddSBrian Vazquez 		likely(f == f3) ? f3(__VA_ARGS__) :				\
29e678e9ddSBrian Vazquez 				  INDIRECT_CALL_2(f, f2, f1, __VA_ARGS__);	\
30e678e9ddSBrian Vazquez 	})
31e678e9ddSBrian Vazquez #define INDIRECT_CALL_4(f, f4, f3, f2, f1, ...)					\
32e678e9ddSBrian Vazquez 	({									\
33e678e9ddSBrian Vazquez 		likely(f == f4) ? f4(__VA_ARGS__) :				\
34e678e9ddSBrian Vazquez 				  INDIRECT_CALL_3(f, f3, f2, f1, __VA_ARGS__);	\
35e678e9ddSBrian Vazquez 	})
36283c16a2SPaolo Abeni 
37283c16a2SPaolo Abeni #define INDIRECT_CALLABLE_DECLARE(f)	f
38283c16a2SPaolo Abeni #define INDIRECT_CALLABLE_SCOPE
39*00538594SBrian Vazquez #define EXPORT_INDIRECT_CALLABLE(f)	EXPORT_SYMBOL(f)
40283c16a2SPaolo Abeni 
41283c16a2SPaolo Abeni #else
42c03b0358SPaolo Abeni #define INDIRECT_CALL_1(f, f1, ...) f(__VA_ARGS__)
43c03b0358SPaolo Abeni #define INDIRECT_CALL_2(f, f2, f1, ...) f(__VA_ARGS__)
44e678e9ddSBrian Vazquez #define INDIRECT_CALL_3(f, f3, f2, f1, ...) f(__VA_ARGS__)
45e678e9ddSBrian Vazquez #define INDIRECT_CALL_4(f, f4, f3, f2, f1, ...) f(__VA_ARGS__)
46283c16a2SPaolo Abeni #define INDIRECT_CALLABLE_DECLARE(f)
47283c16a2SPaolo Abeni #define INDIRECT_CALLABLE_SCOPE		static
48*00538594SBrian Vazquez #define EXPORT_INDIRECT_CALLABLE(f)
49283c16a2SPaolo Abeni #endif
50283c16a2SPaolo Abeni 
51283c16a2SPaolo Abeni /*
52283c16a2SPaolo Abeni  * We can use INDIRECT_CALL_$NR for ipv6 related functions only if ipv6 is
53283c16a2SPaolo Abeni  * builtin, this macro simplify dealing with indirect calls with only ipv4/ipv6
54283c16a2SPaolo Abeni  * alternatives
55283c16a2SPaolo Abeni  */
56283c16a2SPaolo Abeni #if IS_BUILTIN(CONFIG_IPV6)
57283c16a2SPaolo Abeni #define INDIRECT_CALL_INET(f, f2, f1, ...) \
58283c16a2SPaolo Abeni 	INDIRECT_CALL_2(f, f2, f1, __VA_ARGS__)
59283c16a2SPaolo Abeni #elif IS_ENABLED(CONFIG_INET)
60283c16a2SPaolo Abeni #define INDIRECT_CALL_INET(f, f2, f1, ...) INDIRECT_CALL_1(f, f1, __VA_ARGS__)
61283c16a2SPaolo Abeni #else
62283c16a2SPaolo Abeni #define INDIRECT_CALL_INET(f, f2, f1, ...) f(__VA_ARGS__)
63283c16a2SPaolo Abeni #endif
64283c16a2SPaolo Abeni 
65283c16a2SPaolo Abeni #if IS_ENABLED(CONFIG_INET)
66 #define INDIRECT_CALL_INET_1(f, f1, ...) INDIRECT_CALL_1(f, f1, __VA_ARGS__)
67 #else
68 #define INDIRECT_CALL_INET_1(f, f1, ...) f(__VA_ARGS__)
69 #endif
70 
71 #endif
72