0001
0002
0003
0004
0005
0006 #ifndef _ASM_FPU_H
0007 #define _ASM_FPU_H
0008
0009 #include <linux/sched.h>
0010 #include <linux/sched/task_stack.h>
0011 #include <linux/ptrace.h>
0012 #include <linux/thread_info.h>
0013 #include <linux/bitops.h>
0014
0015 #include <asm/mipsregs.h>
0016 #include <asm/cpu.h>
0017 #include <asm/cpu-features.h>
0018 #include <asm/fpu_emulator.h>
0019 #include <asm/hazards.h>
0020 #include <asm/ptrace.h>
0021 #include <asm/processor.h>
0022 #include <asm/current.h>
0023 #include <asm/msa.h>
0024
0025 #ifdef CONFIG_MIPS_MT_FPAFF
0026 #include <asm/mips_mt.h>
0027 #endif
0028
0029
0030
0031
0032
0033
0034 enum fpu_mode {
0035 FPU_32BIT = 0,
0036 FPU_64BIT,
0037 FPU_AS_IS,
0038 FPU_HYBRID,
0039
0040 #define FPU_FR_MASK 0x1
0041 };
0042
0043 #ifdef CONFIG_MIPS_FP_SUPPORT
0044
0045 extern void _save_fp(struct task_struct *);
0046 extern void _restore_fp(struct task_struct *);
0047
0048 #define __disable_fpu() \
0049 do { \
0050 clear_c0_status(ST0_CU1); \
0051 disable_fpu_hazard(); \
0052 } while (0)
0053
0054 static inline int __enable_fpu(enum fpu_mode mode)
0055 {
0056 int fr;
0057
0058 switch (mode) {
0059 case FPU_AS_IS:
0060
0061 set_c0_status(ST0_CU1);
0062 enable_fpu_hazard();
0063 return 0;
0064
0065 case FPU_HYBRID:
0066 if (!cpu_has_fre)
0067 return SIGFPE;
0068
0069
0070 set_c0_config5(MIPS_CONF5_FRE);
0071 goto fr_common;
0072
0073 case FPU_64BIT:
0074 #if !(defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR5) || \
0075 defined(CONFIG_CPU_MIPSR6) || defined(CONFIG_64BIT))
0076
0077 return SIGFPE;
0078 #endif
0079
0080 case FPU_32BIT:
0081 if (cpu_has_fre) {
0082
0083 clear_c0_config5(MIPS_CONF5_FRE);
0084 }
0085 fr_common:
0086
0087 fr = (int)mode & FPU_FR_MASK;
0088 change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0));
0089 enable_fpu_hazard();
0090
0091
0092 if (!!(read_c0_status() & ST0_FR) == !!fr)
0093 return 0;
0094
0095
0096 __disable_fpu();
0097 return SIGFPE;
0098
0099 default:
0100 BUG();
0101 }
0102
0103 return SIGFPE;
0104 }
0105
0106 #define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU)
0107
0108 static inline int __is_fpu_owner(void)
0109 {
0110 return test_thread_flag(TIF_USEDFPU);
0111 }
0112
0113 static inline int is_fpu_owner(void)
0114 {
0115 return cpu_has_fpu && __is_fpu_owner();
0116 }
0117
0118 static inline int __own_fpu(void)
0119 {
0120 enum fpu_mode mode;
0121 int ret;
0122
0123 if (test_thread_flag(TIF_HYBRID_FPREGS))
0124 mode = FPU_HYBRID;
0125 else
0126 mode = !test_thread_flag(TIF_32BIT_FPREGS);
0127
0128 ret = __enable_fpu(mode);
0129 if (ret)
0130 return ret;
0131
0132 KSTK_STATUS(current) |= ST0_CU1;
0133 if (mode == FPU_64BIT || mode == FPU_HYBRID)
0134 KSTK_STATUS(current) |= ST0_FR;
0135 else
0136 KSTK_STATUS(current) &= ~ST0_FR;
0137
0138 set_thread_flag(TIF_USEDFPU);
0139 return 0;
0140 }
0141
0142 static inline int own_fpu_inatomic(int restore)
0143 {
0144 int ret = 0;
0145
0146 if (cpu_has_fpu && !__is_fpu_owner()) {
0147 ret = __own_fpu();
0148 if (restore && !ret)
0149 _restore_fp(current);
0150 }
0151 return ret;
0152 }
0153
0154 static inline int own_fpu(int restore)
0155 {
0156 int ret;
0157
0158 preempt_disable();
0159 ret = own_fpu_inatomic(restore);
0160 preempt_enable();
0161 return ret;
0162 }
0163
0164 static inline void lose_fpu_inatomic(int save, struct task_struct *tsk)
0165 {
0166 if (is_msa_enabled()) {
0167 if (save) {
0168 save_msa(tsk);
0169 tsk->thread.fpu.fcr31 =
0170 read_32bit_cp1_register(CP1_STATUS);
0171 }
0172 disable_msa();
0173 clear_tsk_thread_flag(tsk, TIF_USEDMSA);
0174 __disable_fpu();
0175 } else if (is_fpu_owner()) {
0176 if (save)
0177 _save_fp(tsk);
0178 __disable_fpu();
0179 } else {
0180
0181 WARN(read_c0_status() & ST0_CU1,
0182 "Orphaned FPU left enabled");
0183 }
0184 KSTK_STATUS(tsk) &= ~ST0_CU1;
0185 clear_tsk_thread_flag(tsk, TIF_USEDFPU);
0186 }
0187
0188 static inline void lose_fpu(int save)
0189 {
0190 preempt_disable();
0191 lose_fpu_inatomic(save, current);
0192 preempt_enable();
0193 }
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 static inline bool init_fp_ctx(struct task_struct *target)
0207 {
0208
0209 if (tsk_used_math(target))
0210 return false;
0211
0212
0213 memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr));
0214
0215
0216
0217
0218
0219
0220
0221
0222 set_stopped_child_used_math(target);
0223
0224 return true;
0225 }
0226
0227 static inline void save_fp(struct task_struct *tsk)
0228 {
0229 if (cpu_has_fpu)
0230 _save_fp(tsk);
0231 }
0232
0233 static inline void restore_fp(struct task_struct *tsk)
0234 {
0235 if (cpu_has_fpu)
0236 _restore_fp(tsk);
0237 }
0238
0239 static inline union fpureg *get_fpu_regs(struct task_struct *tsk)
0240 {
0241 if (tsk == current) {
0242 preempt_disable();
0243 if (is_fpu_owner())
0244 _save_fp(current);
0245 preempt_enable();
0246 }
0247
0248 return tsk->thread.fpu.fpr;
0249 }
0250
0251 #else
0252
0253
0254
0255
0256
0257
0258 static inline int __enable_fpu(enum fpu_mode mode)
0259 {
0260 return SIGILL;
0261 }
0262
0263 static inline void __disable_fpu(void)
0264 {
0265
0266 }
0267
0268
0269 static inline int is_fpu_owner(void)
0270 {
0271 return 0;
0272 }
0273
0274 static inline void clear_fpu_owner(void)
0275 {
0276
0277 }
0278
0279 static inline int own_fpu_inatomic(int restore)
0280 {
0281 return SIGILL;
0282 }
0283
0284 static inline int own_fpu(int restore)
0285 {
0286 return SIGILL;
0287 }
0288
0289 static inline void lose_fpu_inatomic(int save, struct task_struct *tsk)
0290 {
0291
0292 }
0293
0294 static inline void lose_fpu(int save)
0295 {
0296
0297 }
0298
0299 static inline bool init_fp_ctx(struct task_struct *target)
0300 {
0301 return false;
0302 }
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312 extern void save_fp(struct task_struct *tsk)
0313 __compiletime_error("save_fp() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
0314
0315 extern void _save_fp(struct task_struct *)
0316 __compiletime_error("_save_fp() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
0317
0318 extern void restore_fp(struct task_struct *tsk)
0319 __compiletime_error("restore_fp() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
0320
0321 extern void _restore_fp(struct task_struct *)
0322 __compiletime_error("_restore_fp() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
0323
0324 extern union fpureg *get_fpu_regs(struct task_struct *tsk)
0325 __compiletime_error("get_fpu_regs() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
0326
0327 #endif
0328 #endif