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 --- 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