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