162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_ARC_JUMP_LABEL_H
362306a36Sopenharmony_ci#define _ASM_ARC_JUMP_LABEL_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#ifndef __ASSEMBLY__
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/stringify.h>
862306a36Sopenharmony_ci#include <linux/types.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define JUMP_LABEL_NOP_SIZE 4
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci * NOTE about '.balign 4':
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * To make atomic update of patched instruction available we need to guarantee
1662306a36Sopenharmony_ci * that this instruction doesn't cross L1 cache line boundary.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * As of today we simply align instruction which can be patched by 4 byte using
1962306a36Sopenharmony_ci * ".balign 4" directive. In that case patched instruction is aligned with one
2062306a36Sopenharmony_ci * 16-bit NOP_S if this is required.
2162306a36Sopenharmony_ci * However 'align by 4' directive is much stricter than it actually required.
2262306a36Sopenharmony_ci * It's enough that our 32-bit instruction don't cross L1 cache line boundary /
2362306a36Sopenharmony_ci * L1 I$ fetch block boundary which can be achieved by using
2462306a36Sopenharmony_ci * ".bundle_align_mode" assembler directive. That will save us from adding
2562306a36Sopenharmony_ci * useless NOP_S padding in most of the cases.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * TODO: switch to ".bundle_align_mode" directive using whin it will be
2862306a36Sopenharmony_ci * supported by ARC toolchain.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic __always_inline bool arch_static_branch(struct static_key *key,
3262306a36Sopenharmony_ci					       bool branch)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	asm goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)"		\n"
3562306a36Sopenharmony_ci		 "1:							\n"
3662306a36Sopenharmony_ci		 "nop							\n"
3762306a36Sopenharmony_ci		 ".pushsection __jump_table, \"aw\"			\n"
3862306a36Sopenharmony_ci		 ".word 1b, %l[l_yes], %c0				\n"
3962306a36Sopenharmony_ci		 ".popsection						\n"
4062306a36Sopenharmony_ci		 : : "i" (&((char *)key)[branch]) : : l_yes);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return false;
4362306a36Sopenharmony_cil_yes:
4462306a36Sopenharmony_ci	return true;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic __always_inline bool arch_static_branch_jump(struct static_key *key,
4862306a36Sopenharmony_ci						    bool branch)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	asm goto(".balign "__stringify(JUMP_LABEL_NOP_SIZE)"		\n"
5162306a36Sopenharmony_ci		 "1:							\n"
5262306a36Sopenharmony_ci		 "b %l[l_yes]						\n"
5362306a36Sopenharmony_ci		 ".pushsection __jump_table, \"aw\"			\n"
5462306a36Sopenharmony_ci		 ".word 1b, %l[l_yes], %c0				\n"
5562306a36Sopenharmony_ci		 ".popsection						\n"
5662306a36Sopenharmony_ci		 : : "i" (&((char *)key)[branch]) : : l_yes);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return false;
5962306a36Sopenharmony_cil_yes:
6062306a36Sopenharmony_ci	return true;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_citypedef u32 jump_label_t;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct jump_entry {
6662306a36Sopenharmony_ci	jump_label_t code;
6762306a36Sopenharmony_ci	jump_label_t target;
6862306a36Sopenharmony_ci	jump_label_t key;
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#endif  /* __ASSEMBLY__ */
7262306a36Sopenharmony_ci#endif
73