162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_ALTERNATIVE_ASM_H
362306a36Sopenharmony_ci#define _ASM_ALTERNATIVE_ASM_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#ifdef __ASSEMBLY__
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <asm/asm.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * Issue one struct alt_instr descriptor entry (need to put it into
1162306a36Sopenharmony_ci * the section .altinstructions, see below). This entry contains
1262306a36Sopenharmony_ci * enough information for the alternatives patching code to patch an
1362306a36Sopenharmony_ci * instruction. See apply_alternatives().
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci.macro altinstruction_entry orig alt feature orig_len alt_len
1662306a36Sopenharmony_ci	.long \orig - .
1762306a36Sopenharmony_ci	.long \alt - .
1862306a36Sopenharmony_ci	.short \feature
1962306a36Sopenharmony_ci	.byte \orig_len
2062306a36Sopenharmony_ci	.byte \alt_len
2162306a36Sopenharmony_ci.endm
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * Define an alternative between two instructions. If @feature is
2562306a36Sopenharmony_ci * present, early code in apply_alternatives() replaces @oldinstr with
2662306a36Sopenharmony_ci * @newinstr. ".fill" directive takes care of proper instruction padding
2762306a36Sopenharmony_ci * in case @newinstr is longer than @oldinstr.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci.macro ALTERNATIVE oldinstr, newinstr, feature
3062306a36Sopenharmony_ci140 :
3162306a36Sopenharmony_ci	\oldinstr
3262306a36Sopenharmony_ci141 :
3362306a36Sopenharmony_ci	.fill - (((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)) / 4, 4, 0x03400000
3462306a36Sopenharmony_ci142 :
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	.pushsection .altinstructions, "a"
3762306a36Sopenharmony_ci	altinstruction_entry 140b, 143f, \feature, 142b-140b, 144f-143f
3862306a36Sopenharmony_ci	.popsection
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	.subsection 1
4162306a36Sopenharmony_ci143 :
4262306a36Sopenharmony_ci	\newinstr
4362306a36Sopenharmony_ci144 :
4462306a36Sopenharmony_ci	.previous
4562306a36Sopenharmony_ci.endm
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define old_len			(141b-140b)
4862306a36Sopenharmony_ci#define new_len1		(144f-143f)
4962306a36Sopenharmony_ci#define new_len2		(145f-144f)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define alt_max_short(a, b)	((a) ^ (((a) ^ (b)) & -(-((a) < (b)))))
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/*
5462306a36Sopenharmony_ci * Same as ALTERNATIVE macro above but for two alternatives. If CPU
5562306a36Sopenharmony_ci * has @feature1, it replaces @oldinstr with @newinstr1. If CPU has
5662306a36Sopenharmony_ci * @feature2, it replaces @oldinstr with @feature2.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
5962306a36Sopenharmony_ci140 :
6062306a36Sopenharmony_ci	\oldinstr
6162306a36Sopenharmony_ci141 :
6262306a36Sopenharmony_ci	.fill - ((alt_max_short(new_len1, new_len2) - (old_len)) > 0) * \
6362306a36Sopenharmony_ci		(alt_max_short(new_len1, new_len2) - (old_len)) / 4, 4, 0x03400000
6462306a36Sopenharmony_ci142 :
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	.pushsection .altinstructions, "a"
6762306a36Sopenharmony_ci	altinstruction_entry 140b, 143f, \feature1, 142b-140b, 144f-143f, 142b-141b
6862306a36Sopenharmony_ci	altinstruction_entry 140b, 144f, \feature2, 142b-140b, 145f-144f, 142b-141b
6962306a36Sopenharmony_ci	.popsection
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	.subsection 1
7262306a36Sopenharmony_ci143 :
7362306a36Sopenharmony_ci	\newinstr1
7462306a36Sopenharmony_ci144 :
7562306a36Sopenharmony_ci	\newinstr2
7662306a36Sopenharmony_ci145 :
7762306a36Sopenharmony_ci	.previous
7862306a36Sopenharmony_ci.endm
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#endif  /*  __ASSEMBLY__  */
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#endif /* _ASM_ALTERNATIVE_ASM_H */
83