Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

LoongArch: Allow usage of LSX/LASX in the kernel

Allow usage of LSX/LASX in the kernel by extending kernel_fpu_begin()
and kernel_fpu_end().

Reviewed-by: WANG Xuerui <git@xen0n.name>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>

+51 -4
+51 -4
arch/loongarch/kernel/kfpu.c
··· 8 8 #include <asm/fpu.h> 9 9 #include <asm/smp.h> 10 10 11 + static unsigned int euen_mask = CSR_EUEN_FPEN; 12 + 13 + /* 14 + * The critical section between kernel_fpu_begin() and kernel_fpu_end() 15 + * is non-reentrant. It is the caller's responsibility to avoid reentrance. 16 + * See drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c as an example. 17 + */ 11 18 static DEFINE_PER_CPU(bool, in_kernel_fpu); 19 + static DEFINE_PER_CPU(unsigned int, euen_current); 12 20 13 21 void kernel_fpu_begin(void) 14 22 { 23 + unsigned int *euen_curr; 24 + 15 25 preempt_disable(); 16 26 17 27 WARN_ON(this_cpu_read(in_kernel_fpu)); 18 28 19 29 this_cpu_write(in_kernel_fpu, true); 30 + euen_curr = this_cpu_ptr(&euen_current); 20 31 21 - if (!is_fpu_owner()) 22 - enable_fpu(); 32 + *euen_curr = csr_xchg32(euen_mask, euen_mask, LOONGARCH_CSR_EUEN); 33 + 34 + #ifdef CONFIG_CPU_HAS_LASX 35 + if (*euen_curr & CSR_EUEN_LASXEN) 36 + _save_lasx(&current->thread.fpu); 23 37 else 38 + #endif 39 + #ifdef CONFIG_CPU_HAS_LSX 40 + if (*euen_curr & CSR_EUEN_LSXEN) 41 + _save_lsx(&current->thread.fpu); 42 + else 43 + #endif 44 + if (*euen_curr & CSR_EUEN_FPEN) 24 45 _save_fp(&current->thread.fpu); 25 46 26 47 write_fcsr(LOONGARCH_FCSR0, 0); ··· 50 29 51 30 void kernel_fpu_end(void) 52 31 { 32 + unsigned int *euen_curr; 33 + 53 34 WARN_ON(!this_cpu_read(in_kernel_fpu)); 54 35 55 - if (!is_fpu_owner()) 56 - disable_fpu(); 36 + euen_curr = this_cpu_ptr(&euen_current); 37 + 38 + #ifdef CONFIG_CPU_HAS_LASX 39 + if (*euen_curr & CSR_EUEN_LASXEN) 40 + _restore_lasx(&current->thread.fpu); 57 41 else 42 + #endif 43 + #ifdef CONFIG_CPU_HAS_LSX 44 + if (*euen_curr & CSR_EUEN_LSXEN) 45 + _restore_lsx(&current->thread.fpu); 46 + else 47 + #endif 48 + if (*euen_curr & CSR_EUEN_FPEN) 58 49 _restore_fp(&current->thread.fpu); 50 + 51 + *euen_curr = csr_xchg32(*euen_curr, euen_mask, LOONGARCH_CSR_EUEN); 59 52 60 53 this_cpu_write(in_kernel_fpu, false); 61 54 62 55 preempt_enable(); 63 56 } 64 57 EXPORT_SYMBOL_GPL(kernel_fpu_end); 58 + 59 + static int __init init_euen_mask(void) 60 + { 61 + if (cpu_has_lsx) 62 + euen_mask |= CSR_EUEN_LSXEN; 63 + 64 + if (cpu_has_lasx) 65 + euen_mask |= CSR_EUEN_LASXEN; 66 + 67 + return 0; 68 + } 69 + arch_initcall(init_euen_mask);