88#include <asm/fpu.h>
99#include <asm/smp.h>
1010
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+ */
1118static DEFINE_PER_CPU (bool , in_kernel_fpu ) ;
19+ static DEFINE_PER_CPU (unsigned int , euen_current ) ;
1220
1321void kernel_fpu_begin (void )
1422{
23+ unsigned int * euen_curr ;
24+
1525 preempt_disable ();
1626
1727 WARN_ON (this_cpu_read (in_kernel_fpu ));
1828
1929 this_cpu_write (in_kernel_fpu , true);
30+ euen_curr = this_cpu_ptr (& euen_current );
2031
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 );
37+ else
38+ #endif
39+ #ifdef CONFIG_CPU_HAS_LSX
40+ if (* euen_curr & CSR_EUEN_LSXEN )
41+ _save_lsx (& current -> thread .fpu );
2342 else
43+ #endif
44+ if (* euen_curr & CSR_EUEN_FPEN )
2445 _save_fp (& current -> thread .fpu );
2546
2647 write_fcsr (LOONGARCH_FCSR0 , 0 );
@@ -29,15 +50,41 @@ EXPORT_SYMBOL_GPL(kernel_fpu_begin);
2950
3051void kernel_fpu_end (void )
3152{
53+ unsigned int * euen_curr ;
54+
3255 WARN_ON (!this_cpu_read (in_kernel_fpu ));
3356
34- if (!is_fpu_owner ())
35- disable_fpu ();
57+ euen_curr = this_cpu_ptr (& euen_current );
58+
59+ #ifdef CONFIG_CPU_HAS_LASX
60+ if (* euen_curr & CSR_EUEN_LASXEN )
61+ _restore_lasx (& current -> thread .fpu );
3662 else
63+ #endif
64+ #ifdef CONFIG_CPU_HAS_LSX
65+ if (* euen_curr & CSR_EUEN_LSXEN )
66+ _restore_lsx (& current -> thread .fpu );
67+ else
68+ #endif
69+ if (* euen_curr & CSR_EUEN_FPEN )
3770 _restore_fp (& current -> thread .fpu );
3871
72+ * euen_curr = csr_xchg32 (* euen_curr , euen_mask , LOONGARCH_CSR_EUEN );
73+
3974 this_cpu_write (in_kernel_fpu , false);
4075
4176 preempt_enable ();
4277}
4378EXPORT_SYMBOL_GPL (kernel_fpu_end );
79+
80+ static int __init init_euen_mask (void )
81+ {
82+ if (cpu_has_lsx )
83+ euen_mask |= CSR_EUEN_LSXEN ;
84+
85+ if (cpu_has_lasx )
86+ euen_mask |= CSR_EUEN_LASXEN ;
87+
88+ return 0 ;
89+ }
90+ arch_initcall (init_euen_mask );
0 commit comments