root/arch/mips/include/asm/fpu.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. __enable_fpu
  2. __is_fpu_owner
  3. is_fpu_owner
  4. __own_fpu
  5. own_fpu_inatomic
  6. own_fpu
  7. lose_fpu_inatomic
  8. lose_fpu
  9. init_fp_ctx
  10. save_fp
  11. restore_fp
  12. get_fpu_regs
  13. __enable_fpu
  14. __disable_fpu
  15. is_fpu_owner
  16. clear_fpu_owner
  17. own_fpu_inatomic
  18. own_fpu
  19. lose_fpu_inatomic
  20. lose_fpu
  21. init_fp_ctx

   1 /* SPDX-License-Identifier: GPL-2.0-or-later */
   2 /*
   3  * Copyright (C) 2002 MontaVista Software Inc.
   4  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
   5  */
   6 #ifndef _ASM_FPU_H
   7 #define _ASM_FPU_H
   8 
   9 #include <linux/sched.h>
  10 #include <linux/sched/task_stack.h>
  11 #include <linux/ptrace.h>
  12 #include <linux/thread_info.h>
  13 #include <linux/bitops.h>
  14 
  15 #include <asm/mipsregs.h>
  16 #include <asm/cpu.h>
  17 #include <asm/cpu-features.h>
  18 #include <asm/fpu_emulator.h>
  19 #include <asm/hazards.h>
  20 #include <asm/ptrace.h>
  21 #include <asm/processor.h>
  22 #include <asm/current.h>
  23 #include <asm/msa.h>
  24 
  25 #ifdef CONFIG_MIPS_MT_FPAFF
  26 #include <asm/mips_mt.h>
  27 #endif
  28 
  29 /*
  30  * This enum specifies a mode in which we want the FPU to operate, for cores
  31  * which implement the Status.FR bit. Note that the bottom bit of the value
  32  * purposefully matches the desired value of the Status.FR bit.
  33  */
  34 enum fpu_mode {
  35         FPU_32BIT = 0,          /* FR = 0 */
  36         FPU_64BIT,              /* FR = 1, FRE = 0 */
  37         FPU_AS_IS,
  38         FPU_HYBRID,             /* FR = 1, FRE = 1 */
  39 
  40 #define FPU_FR_MASK             0x1
  41 };
  42 
  43 #ifdef CONFIG_MIPS_FP_SUPPORT
  44 
  45 extern void _save_fp(struct task_struct *);
  46 extern void _restore_fp(struct task_struct *);
  47 
  48 #define __disable_fpu()                                                 \
  49 do {                                                                    \
  50         clear_c0_status(ST0_CU1);                                       \
  51         disable_fpu_hazard();                                           \
  52 } while (0)
  53 
  54 static inline int __enable_fpu(enum fpu_mode mode)
  55 {
  56         int fr;
  57 
  58         switch (mode) {
  59         case FPU_AS_IS:
  60                 /* just enable the FPU in its current mode */
  61                 set_c0_status(ST0_CU1);
  62                 enable_fpu_hazard();
  63                 return 0;
  64 
  65         case FPU_HYBRID:
  66                 if (!cpu_has_fre)
  67                         return SIGFPE;
  68 
  69                 /* set FRE */
  70                 set_c0_config5(MIPS_CONF5_FRE);
  71                 goto fr_common;
  72 
  73         case FPU_64BIT:
  74 #if !(defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) \
  75       || defined(CONFIG_64BIT))
  76                 /* we only have a 32-bit FPU */
  77                 return SIGFPE;
  78 #endif
  79                 /* fall through */
  80         case FPU_32BIT:
  81                 if (cpu_has_fre) {
  82                         /* clear FRE */
  83                         clear_c0_config5(MIPS_CONF5_FRE);
  84                 }
  85 fr_common:
  86                 /* set CU1 & change FR appropriately */
  87                 fr = (int)mode & FPU_FR_MASK;
  88                 change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0));
  89                 enable_fpu_hazard();
  90 
  91                 /* check FR has the desired value */
  92                 if (!!(read_c0_status() & ST0_FR) == !!fr)
  93                         return 0;
  94 
  95                 /* unsupported FR value */
  96                 __disable_fpu();
  97                 return SIGFPE;
  98 
  99         default:
 100                 BUG();
 101         }
 102 
 103         return SIGFPE;
 104 }
 105 
 106 #define clear_fpu_owner()       clear_thread_flag(TIF_USEDFPU)
 107 
 108 static inline int __is_fpu_owner(void)
 109 {
 110         return test_thread_flag(TIF_USEDFPU);
 111 }
 112 
 113 static inline int is_fpu_owner(void)
 114 {
 115         return cpu_has_fpu && __is_fpu_owner();
 116 }
 117 
 118 static inline int __own_fpu(void)
 119 {
 120         enum fpu_mode mode;
 121         int ret;
 122 
 123         if (test_thread_flag(TIF_HYBRID_FPREGS))
 124                 mode = FPU_HYBRID;
 125         else
 126                 mode = !test_thread_flag(TIF_32BIT_FPREGS);
 127 
 128         ret = __enable_fpu(mode);
 129         if (ret)
 130                 return ret;
 131 
 132         KSTK_STATUS(current) |= ST0_CU1;
 133         if (mode == FPU_64BIT || mode == FPU_HYBRID)
 134                 KSTK_STATUS(current) |= ST0_FR;
 135         else /* mode == FPU_32BIT */
 136                 KSTK_STATUS(current) &= ~ST0_FR;
 137 
 138         set_thread_flag(TIF_USEDFPU);
 139         return 0;
 140 }
 141 
 142 static inline int own_fpu_inatomic(int restore)
 143 {
 144         int ret = 0;
 145 
 146         if (cpu_has_fpu && !__is_fpu_owner()) {
 147                 ret = __own_fpu();
 148                 if (restore && !ret)
 149                         _restore_fp(current);
 150         }
 151         return ret;
 152 }
 153 
 154 static inline int own_fpu(int restore)
 155 {
 156         int ret;
 157 
 158         preempt_disable();
 159         ret = own_fpu_inatomic(restore);
 160         preempt_enable();
 161         return ret;
 162 }
 163 
 164 static inline void lose_fpu_inatomic(int save, struct task_struct *tsk)
 165 {
 166         if (is_msa_enabled()) {
 167                 if (save) {
 168                         save_msa(tsk);
 169                         tsk->thread.fpu.fcr31 =
 170                                         read_32bit_cp1_register(CP1_STATUS);
 171                 }
 172                 disable_msa();
 173                 clear_tsk_thread_flag(tsk, TIF_USEDMSA);
 174                 __disable_fpu();
 175         } else if (is_fpu_owner()) {
 176                 if (save)
 177                         _save_fp(tsk);
 178                 __disable_fpu();
 179         } else {
 180                 /* FPU should not have been left enabled with no owner */
 181                 WARN(read_c0_status() & ST0_CU1,
 182                      "Orphaned FPU left enabled");
 183         }
 184         KSTK_STATUS(tsk) &= ~ST0_CU1;
 185         clear_tsk_thread_flag(tsk, TIF_USEDFPU);
 186 }
 187 
 188 static inline void lose_fpu(int save)
 189 {
 190         preempt_disable();
 191         lose_fpu_inatomic(save, current);
 192         preempt_enable();
 193 }
 194 
 195 /**
 196  * init_fp_ctx() - Initialize task FP context
 197  * @target: The task whose FP context should be initialized.
 198  *
 199  * Initializes the FP context of the target task to sane default values if that
 200  * target task does not already have valid FP context. Once the context has
 201  * been initialized, the task will be marked as having used FP & thus having
 202  * valid FP context.
 203  *
 204  * Returns: true if context is initialized, else false.
 205  */
 206 static inline bool init_fp_ctx(struct task_struct *target)
 207 {
 208         /* If FP has been used then the target already has context */
 209         if (tsk_used_math(target))
 210                 return false;
 211 
 212         /* Begin with data registers set to all 1s... */
 213         memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr));
 214 
 215         /* FCSR has been preset by `mips_set_personality_nan'.  */
 216 
 217         /*
 218          * Record that the target has "used" math, such that the context
 219          * just initialised, and any modifications made by the caller,
 220          * aren't discarded.
 221          */
 222         set_stopped_child_used_math(target);
 223 
 224         return true;
 225 }
 226 
 227 static inline void save_fp(struct task_struct *tsk)
 228 {
 229         if (cpu_has_fpu)
 230                 _save_fp(tsk);
 231 }
 232 
 233 static inline void restore_fp(struct task_struct *tsk)
 234 {
 235         if (cpu_has_fpu)
 236                 _restore_fp(tsk);
 237 }
 238 
 239 static inline union fpureg *get_fpu_regs(struct task_struct *tsk)
 240 {
 241         if (tsk == current) {
 242                 preempt_disable();
 243                 if (is_fpu_owner())
 244                         _save_fp(current);
 245                 preempt_enable();
 246         }
 247 
 248         return tsk->thread.fpu.fpr;
 249 }
 250 
 251 #else /* !CONFIG_MIPS_FP_SUPPORT */
 252 
 253 /*
 254  * When FP support is disabled we provide only a minimal set of stub functions
 255  * to avoid callers needing to care too much about CONFIG_MIPS_FP_SUPPORT.
 256  */
 257 
 258 static inline int __enable_fpu(enum fpu_mode mode)
 259 {
 260         return SIGILL;
 261 }
 262 
 263 static inline void __disable_fpu(void)
 264 {
 265         /* no-op */
 266 }
 267 
 268 
 269 static inline int is_fpu_owner(void)
 270 {
 271         return 0;
 272 }
 273 
 274 static inline void clear_fpu_owner(void)
 275 {
 276         /* no-op */
 277 }
 278 
 279 static inline int own_fpu_inatomic(int restore)
 280 {
 281         return SIGILL;
 282 }
 283 
 284 static inline int own_fpu(int restore)
 285 {
 286         return SIGILL;
 287 }
 288 
 289 static inline void lose_fpu_inatomic(int save, struct task_struct *tsk)
 290 {
 291         /* no-op */
 292 }
 293 
 294 static inline void lose_fpu(int save)
 295 {
 296         /* no-op */
 297 }
 298 
 299 static inline bool init_fp_ctx(struct task_struct *target)
 300 {
 301         return false;
 302 }
 303 
 304 /*
 305  * The following functions should only be called in paths where we know that FP
 306  * support is enabled, typically a path where own_fpu() or __enable_fpu() have
 307  * returned successfully. When CONFIG_MIPS_FP_SUPPORT=n it is known at compile
 308  * time that this should never happen, so calls to these functions should be
 309  * optimized away & never actually be emitted.
 310  */
 311 
 312 extern void save_fp(struct task_struct *tsk)
 313         __compiletime_error("save_fp() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
 314 
 315 extern void _save_fp(struct task_struct *)
 316         __compiletime_error("_save_fp() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
 317 
 318 extern void restore_fp(struct task_struct *tsk)
 319         __compiletime_error("restore_fp() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
 320 
 321 extern void _restore_fp(struct task_struct *)
 322         __compiletime_error("_restore_fp() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
 323 
 324 extern union fpureg *get_fpu_regs(struct task_struct *tsk)
 325         __compiletime_error("get_fpu_regs() should not be called when CONFIG_MIPS_FP_SUPPORT=n");
 326 
 327 #endif /* !CONFIG_MIPS_FP_SUPPORT */
 328 #endif /* _ASM_FPU_H */

/* [<][>][^][v][top][bottom][index][help] */