[PATCH v3 1/3] LoongArch: Add CPUCFG2 DIV32 feature detection
From: Tiezhu Yang
Date: Fri Oct 16 2026 - 04:11:49 EST
The LoongArch Architecture Manual defines a hardware capability bit
CPUCFG2_DIV32 (bit 26 of CPUCFG 0x2). When this bit is set to 1, it
indicates that on 64-bit machines, the division and mod instructions
(DIV.W[U] and MOD.W[U]) will ignore the upper 32 bits of the input
registers and only compute based on the lower 32 bits.
On certain CPU cores without this feature, these 32-bit instructions
require both input operands to be properly sign-extended. Otherwise,
the hardware execution results can be randomly meaningless values.
Add CPU_FEATURE_DIV32 to detect and export this hardware capability
via elf_hwcap and cpu_has_div32. This provides the infrastructure
for subsystems like BPF JIT to safely choose either native 32-bit
instructions or fallback instruction sequences based on the actual
CPU hardware capabilities.
Signed-off-by: Tiezhu Yang <yangtiezhu@xxxxxxxxxxx>
---
arch/loongarch/include/asm/cpu-features.h | 1 +
arch/loongarch/include/asm/cpu.h | 2 ++
arch/loongarch/include/uapi/asm/hwcap.h | 1 +
arch/loongarch/kernel/cpu-probe.c | 4 ++++
arch/loongarch/kernel/proc.c | 2 ++
5 files changed, 10 insertions(+)
diff --git a/arch/loongarch/include/asm/cpu-features.h b/arch/loongarch/include/asm/cpu-features.h
index 62059c5551b9..3e7cf1987171 100644
--- a/arch/loongarch/include/asm/cpu-features.h
+++ b/arch/loongarch/include/asm/cpu-features.h
@@ -69,5 +69,6 @@
#define cpu_has_msgint cpu_opt(LOONGARCH_CPU_MSGINT)
#define cpu_has_avecint cpu_opt(LOONGARCH_CPU_AVECINT)
#define cpu_has_redirectint cpu_opt(LOONGARCH_CPU_REDIRECTINT)
+#define cpu_has_div32 cpu_opt(LOONGARCH_CPU_DIV32)
#endif /* __ASM_CPU_FEATURES_H */
diff --git a/arch/loongarch/include/asm/cpu.h b/arch/loongarch/include/asm/cpu.h
index 91b96938861e..d1cf5dd5eceb 100644
--- a/arch/loongarch/include/asm/cpu.h
+++ b/arch/loongarch/include/asm/cpu.h
@@ -127,6 +127,7 @@ static inline char *id_to_core_name(unsigned int id)
#define CPU_FEATURE_MSGINT 31 /* CPU has MSG interrupt */
#define CPU_FEATURE_AVECINT 32 /* CPU has AVEC interrupt */
#define CPU_FEATURE_REDIRECTINT 33 /* CPU has interrupt remapping */
+#define CPU_FEATURE_DIV32 34 /* CPU has DIV32 feature */
#define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG)
#define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM)
@@ -162,5 +163,6 @@ static inline char *id_to_core_name(unsigned int id)
#define LOONGARCH_CPU_MSGINT BIT_ULL(CPU_FEATURE_MSGINT)
#define LOONGARCH_CPU_AVECINT BIT_ULL(CPU_FEATURE_AVECINT)
#define LOONGARCH_CPU_REDIRECTINT BIT_ULL(CPU_FEATURE_REDIRECTINT)
+#define LOONGARCH_CPU_DIV32 BIT_ULL(CPU_FEATURE_DIV32)
#endif /* _ASM_CPU_H */
diff --git a/arch/loongarch/include/uapi/asm/hwcap.h b/arch/loongarch/include/uapi/asm/hwcap.h
index 90e96113ba51..00bf93683c74 100644
--- a/arch/loongarch/include/uapi/asm/hwcap.h
+++ b/arch/loongarch/include/uapi/asm/hwcap.h
@@ -20,5 +20,6 @@
#define HWCAP_LOONGARCH_LSPW (1 << 14)
#define HWCAP_LOONGARCH_SCQ (1 << 15)
#define HWCAP_LOONGARCH_LAM_BH (1 << 16)
+#define HWCAP_LOONGARCH_DIV32 (1 << 17)
#endif /* _UAPI_ASM_HWCAP_H */
diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c
index 74d31f260dfd..c50fcba805f7 100644
--- a/arch/loongarch/kernel/cpu-probe.c
+++ b/arch/loongarch/kernel/cpu-probe.c
@@ -236,6 +236,10 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
elf_hwcap |= HWCAP_LOONGARCH_LBT_MIPS;
}
#endif
+ if (config & CPUCFG2_DIV32) {
+ c->options |= LOONGARCH_CPU_DIV32;
+ elf_hwcap |= HWCAP_LOONGARCH_DIV32;
+ }
config = read_cpucfg(LOONGARCH_CPUCFG6);
if (config & CPUCFG6_PMP)
diff --git a/arch/loongarch/kernel/proc.c b/arch/loongarch/kernel/proc.c
index d4ce5b585453..c8d6f397de55 100644
--- a/arch/loongarch/kernel/proc.c
+++ b/arch/loongarch/kernel/proc.c
@@ -94,6 +94,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_puts(m, " lbt_arm");
if (cpu_has_lbt_mips)
seq_puts(m, " lbt_mips");
+ if (cpu_has_div32)
+ seq_puts(m, " div32");
seq_puts(m, "\n");
seq_printf(m, "Hardware Watchpoint\t: %s", str_yes_no(cpu_has_watch));
--
2.42.0