162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/* Copyright (C) 2018 Cadence Design Systems Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#ifndef _ASM_XTENSA_JUMP_LABEL_H
562306a36Sopenharmony_ci#define _ASM_XTENSA_JUMP_LABEL_H
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifndef __ASSEMBLY__
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/types.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define JUMP_LABEL_NOP_SIZE 3
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic __always_inline bool arch_static_branch(struct static_key *key,
1462306a36Sopenharmony_ci					       bool branch)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	asm goto("1:\n\t"
1762306a36Sopenharmony_ci			  "_nop\n\t"
1862306a36Sopenharmony_ci			  ".pushsection __jump_table,  \"aw\"\n\t"
1962306a36Sopenharmony_ci			  ".word 1b, %l[l_yes], %c0\n\t"
2062306a36Sopenharmony_ci			  ".popsection\n\t"
2162306a36Sopenharmony_ci			  : :  "i" (&((char *)key)[branch]) :  : l_yes);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	return false;
2462306a36Sopenharmony_cil_yes:
2562306a36Sopenharmony_ci	return true;
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic __always_inline bool arch_static_branch_jump(struct static_key *key,
2962306a36Sopenharmony_ci						    bool branch)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	/*
3262306a36Sopenharmony_ci	 * Xtensa assembler will mark certain points in the code
3362306a36Sopenharmony_ci	 * as unreachable, so that later assembler or linker relaxation
3462306a36Sopenharmony_ci	 * passes could use them. A spot right after the J instruction
3562306a36Sopenharmony_ci	 * is one such point. Assembler and/or linker may insert padding
3662306a36Sopenharmony_ci	 * or literals here, breaking code flow in case the J instruction
3762306a36Sopenharmony_ci	 * is later replaced with NOP. Put a label right after the J to
3862306a36Sopenharmony_ci	 * make it reachable and wrap both into a no-transform block
3962306a36Sopenharmony_ci	 * to avoid any assembler interference with this.
4062306a36Sopenharmony_ci	 */
4162306a36Sopenharmony_ci	asm goto("1:\n\t"
4262306a36Sopenharmony_ci			  ".begin no-transform\n\t"
4362306a36Sopenharmony_ci			  "_j %l[l_yes]\n\t"
4462306a36Sopenharmony_ci			  "2:\n\t"
4562306a36Sopenharmony_ci			  ".end no-transform\n\t"
4662306a36Sopenharmony_ci			  ".pushsection __jump_table,  \"aw\"\n\t"
4762306a36Sopenharmony_ci			  ".word 1b, %l[l_yes], %c0\n\t"
4862306a36Sopenharmony_ci			  ".popsection\n\t"
4962306a36Sopenharmony_ci			  : :  "i" (&((char *)key)[branch]) :  : l_yes);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return false;
5262306a36Sopenharmony_cil_yes:
5362306a36Sopenharmony_ci	return true;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_citypedef u32 jump_label_t;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct jump_entry {
5962306a36Sopenharmony_ci	jump_label_t code;
6062306a36Sopenharmony_ci	jump_label_t target;
6162306a36Sopenharmony_ci	jump_label_t key;
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#endif  /* __ASSEMBLY__ */
6562306a36Sopenharmony_ci#endif
66