[PATCH] riscv: Optimize __runtime_fixup_mask for masks with <= 11 bits
From: Charlie Jenkins
Date: Fri Jul 10 2026 - 02:18:09 EST
---
arch/riscv/include/asm/insn.h | 2 ++
arch/riscv/include/asm/runtime-const.h | 29 ++++++++++++++++++++++++--
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index c3005573e8c9..0a34cd7305d0 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -141,6 +141,7 @@
#define RVG_OPCODE_JALR 0x67
#define RVG_OPCODE_JAL 0x6f
#define RVG_OPCODE_SYSTEM 0x73
+#define RVG_OPCODE_ANDI 0x13
#define RVG_SYSTEM_CSR_OFF 20
#define RVG_SYSTEM_CSR_MASK GENMASK(12, 0)
@@ -175,6 +176,7 @@
#define RVG_FUNCT3_BGE 0x5
#define RVG_FUNCT3_BLTU 0x6
#define RVG_FUNCT3_BGEU 0x7
+#define RVG_FUNCT3_ANDI 0x7
/* parts of funct3 code for C extension*/
#define RVC_FUNCT3_C_BEQZ 0x6
diff --git a/arch/riscv/include/asm/runtime-const.h b/arch/riscv/include/asm/runtime-const.h
index dbf96c937dbb..24a9b13081f7 100644
--- a/arch/riscv/include/asm/runtime-const.h
+++ b/arch/riscv/include/asm/runtime-const.h
@@ -9,6 +9,7 @@
#include <asm/asm.h>
#include <asm/alternative.h>
#include <asm/cacheflush.h>
+#include <asm/insn.h>
#include <asm/insn-def.h>
#include <linux/memory.h>
#include <asm/text-patching.h>
@@ -302,8 +303,32 @@ static inline void __runtime_fixup_mask(void *where, unsigned long val)
*/
BUG_ON(!val || width > 31 || (GENMASK(width - 1, 0) != val));
- __runtime_fixup_shift(where, 32 - width);
- __runtime_fixup_shift(where + 4, 32 - width);
+ /*
+ * A riscv 'andi' instruction can fit an 11 bit immediate, so the mask
+ * can be directly applied. Otherwise fall back to SRLI + SLLI.
+ */
+ if (width < 11) {
+ __le16 *parcel = where;
+ u32 insn;
+ __le32 res, nop;
+
+ insn = (u32)le16_to_cpu(parcel[0]) | (u32)le16_to_cpu(parcel[1]) << 16;
+
+ /* Replace the slli/slliw with an andi */
+ insn &= 0x000fcf80;
+ insn |= val << 20 | RV_ENCODE_FUNCT3(ANDI) | RVG_OPCODE_ANDI;
+
+ res = cpu_to_le32(insn);
+ /* Replace the srli/srliw with a nop */
+ nop = cpu_to_le32(RISCV_INSN_NOP4);
+ mutex_lock(&text_mutex);
+ patch_text_nosync(where, &res, sizeof(insn));
+ patch_text_nosync(where + 4, &nop, sizeof(insn));
+ mutex_unlock(&text_mutex);
+ } else {
+ __runtime_fixup_shift(where, 32 - width);
+ __runtime_fixup_shift(where + 4, 32 - width);
+ }
}
static inline void runtime_const_fixup(void (*fn)(void *, unsigned long),
--
2.54.0
I would prefer including this, but I am happy to approve this
regardless.
Reviewed-by: Charlie Jenkins <thecharlesjenkins@xxxxxxxxx>
Tested-by: Charlie Jenkins <thecharlesjenkins@xxxxxxxxx>
--
- Charlie