From: Tiezhu Yang Date: Wed, 22 Apr 2026 07:45:34 +0000 (+0800) Subject: LoongArch: BPF: Support 8 and 16 bit read-modify-write instructions X-Git-Tag: v7.1-rc1~28^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc935c190c7967070506a2795575adc7f9f501ef;p=thirdparty%2Fkernel%2Flinux.git LoongArch: BPF: Support 8 and 16 bit read-modify-write instructions The 8 and 16 bit read-modify-write instructions {amadd/amswap}.{b/h} were newly added in the latest LoongArch Reference Manual, use them to avoid the error of unknown opcode if possible. Acked-by: Hengqi Chen Signed-off-by: Tiezhu Yang Signed-off-by: Huacai Chen --- diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index fefda4050a20..6bd2d20a9f2d 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -363,10 +363,28 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) switch (imm) { /* lock *(size *)(dst + off) = src */ case BPF_ADD: - if (isdw) - emit_insn(ctx, amaddd, t2, t1, src); - else + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amadd.b instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amaddb, t2, t1, src); + break; + case BPF_H: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amadd.h instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amaddh, t2, t1, src); + break; + case BPF_W: emit_insn(ctx, amaddw, t2, t1, src); + break; + case BPF_DW: + emit_insn(ctx, amaddd, t2, t1, src); + break; + } break; case BPF_AND: if (isdw) @@ -388,11 +406,30 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) break; /* src = atomic_fetch_(dst + off, src) */ case BPF_ADD | BPF_FETCH: - if (isdw) { - emit_insn(ctx, amaddd, src, t1, t3); - } else { + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amadd.b instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amaddb, src, t1, t3); + emit_zext_32(ctx, src, true); + break; + case BPF_H: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amadd.h instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amaddh, src, t1, t3); + emit_zext_32(ctx, src, true); + break; + case BPF_W: emit_insn(ctx, amaddw, src, t1, t3); emit_zext_32(ctx, src, true); + break; + case BPF_DW: + emit_insn(ctx, amaddd, src, t1, t3); + break; } break; case BPF_AND | BPF_FETCH: @@ -421,11 +458,30 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) break; /* src = atomic_xchg(dst + off, src); */ case BPF_XCHG: - if (isdw) { - emit_insn(ctx, amswapd, src, t1, t3); - } else { + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amswap.b instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amswapb, src, t1, t3); + emit_zext_32(ctx, src, true); + break; + case BPF_H: + if (!cpu_has_lam_bh) { + pr_err_once("bpf-jit: amswap.h instruction is not supported\n"); + return -EINVAL; + } + emit_insn(ctx, amswaph, src, t1, t3); + emit_zext_32(ctx, src, true); + break; + case BPF_W: emit_insn(ctx, amswapw, src, t1, t3); emit_zext_32(ctx, src, true); + break; + case BPF_DW: + emit_insn(ctx, amswapd, src, t1, t3); + break; } break; /* r0 = atomic_cmpxchg(dst + off, r0, src); */ @@ -1259,6 +1315,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext return ret; break; + /* Atomics */ + case BPF_STX | BPF_ATOMIC | BPF_B: + case BPF_STX | BPF_ATOMIC | BPF_H: case BPF_STX | BPF_ATOMIC | BPF_W: case BPF_STX | BPF_ATOMIC | BPF_DW: ret = emit_atomic_rmw(insn, ctx);