diff options
Diffstat (limited to 'arch/mips/include/asm/fpu.h')
-rw-r--r-- | arch/mips/include/asm/fpu.h | 104 |
1 files changed, 76 insertions, 28 deletions
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index d088e5db4903..cfe092fc720d 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h | |||
@@ -33,11 +33,48 @@ extern void _init_fpu(void); | |||
33 | extern void _save_fp(struct task_struct *); | 33 | extern void _save_fp(struct task_struct *); |
34 | extern void _restore_fp(struct task_struct *); | 34 | extern void _restore_fp(struct task_struct *); |
35 | 35 | ||
36 | #define __enable_fpu() \ | 36 | /* |
37 | do { \ | 37 | * This enum specifies a mode in which we want the FPU to operate, for cores |
38 | set_c0_status(ST0_CU1); \ | 38 | * which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT |
39 | enable_fpu_hazard(); \ | 39 | * purposefully have the values 0 & 1 respectively, so that an integer value |
40 | } while (0) | 40 | * of Status.FR can be trivially casted to the corresponding enum fpu_mode. |
41 | */ | ||
42 | enum fpu_mode { | ||
43 | FPU_32BIT = 0, /* FR = 0 */ | ||
44 | FPU_64BIT, /* FR = 1 */ | ||
45 | FPU_AS_IS, | ||
46 | }; | ||
47 | |||
48 | static inline int __enable_fpu(enum fpu_mode mode) | ||
49 | { | ||
50 | int fr; | ||
51 | |||
52 | switch (mode) { | ||
53 | case FPU_AS_IS: | ||
54 | /* just enable the FPU in its current mode */ | ||
55 | set_c0_status(ST0_CU1); | ||
56 | enable_fpu_hazard(); | ||
57 | return 0; | ||
58 | |||
59 | case FPU_64BIT: | ||
60 | #if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64)) | ||
61 | /* we only have a 32-bit FPU */ | ||
62 | return SIGFPE; | ||
63 | #endif | ||
64 | /* fall through */ | ||
65 | case FPU_32BIT: | ||
66 | /* set CU1 & change FR appropriately */ | ||
67 | fr = (int)mode; | ||
68 | change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0)); | ||
69 | enable_fpu_hazard(); | ||
70 | |||
71 | /* check FR has the desired value */ | ||
72 | return (!!(read_c0_status() & ST0_FR) == !!fr) ? 0 : SIGFPE; | ||
73 | |||
74 | default: | ||
75 | BUG(); | ||
76 | } | ||
77 | } | ||
41 | 78 | ||
42 | #define __disable_fpu() \ | 79 | #define __disable_fpu() \ |
43 | do { \ | 80 | do { \ |
@@ -45,19 +82,6 @@ do { \ | |||
45 | disable_fpu_hazard(); \ | 82 | disable_fpu_hazard(); \ |
46 | } while (0) | 83 | } while (0) |
47 | 84 | ||
48 | #define enable_fpu() \ | ||
49 | do { \ | ||
50 | if (cpu_has_fpu) \ | ||
51 | __enable_fpu(); \ | ||
52 | } while (0) | ||
53 | |||
54 | #define disable_fpu() \ | ||
55 | do { \ | ||
56 | if (cpu_has_fpu) \ | ||
57 | __disable_fpu(); \ | ||
58 | } while (0) | ||
59 | |||
60 | |||
61 | #define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU) | 85 | #define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU) |
62 | 86 | ||
63 | static inline int __is_fpu_owner(void) | 87 | static inline int __is_fpu_owner(void) |
@@ -70,27 +94,46 @@ static inline int is_fpu_owner(void) | |||
70 | return cpu_has_fpu && __is_fpu_owner(); | 94 | return cpu_has_fpu && __is_fpu_owner(); |
71 | } | 95 | } |
72 | 96 | ||
73 | static inline void __own_fpu(void) | 97 | static inline int __own_fpu(void) |
74 | { | 98 | { |
75 | __enable_fpu(); | 99 | enum fpu_mode mode; |
100 | int ret; | ||
101 | |||
102 | mode = !test_thread_flag(TIF_32BIT_FPREGS); | ||
103 | ret = __enable_fpu(mode); | ||
104 | if (ret) | ||
105 | return ret; | ||
106 | |||
76 | KSTK_STATUS(current) |= ST0_CU1; | 107 | KSTK_STATUS(current) |= ST0_CU1; |
108 | if (mode == FPU_64BIT) | ||
109 | KSTK_STATUS(current) |= ST0_FR; | ||
110 | else /* mode == FPU_32BIT */ | ||
111 | KSTK_STATUS(current) &= ~ST0_FR; | ||
112 | |||
77 | set_thread_flag(TIF_USEDFPU); | 113 | set_thread_flag(TIF_USEDFPU); |
114 | return 0; | ||
78 | } | 115 | } |
79 | 116 | ||
80 | static inline void own_fpu_inatomic(int restore) | 117 | static inline int own_fpu_inatomic(int restore) |
81 | { | 118 | { |
119 | int ret = 0; | ||
120 | |||
82 | if (cpu_has_fpu && !__is_fpu_owner()) { | 121 | if (cpu_has_fpu && !__is_fpu_owner()) { |
83 | __own_fpu(); | 122 | ret = __own_fpu(); |
84 | if (restore) | 123 | if (restore && !ret) |
85 | _restore_fp(current); | 124 | _restore_fp(current); |
86 | } | 125 | } |
126 | return ret; | ||
87 | } | 127 | } |
88 | 128 | ||
89 | static inline void own_fpu(int restore) | 129 | static inline int own_fpu(int restore) |
90 | { | 130 | { |
131 | int ret; | ||
132 | |||
91 | preempt_disable(); | 133 | preempt_disable(); |
92 | own_fpu_inatomic(restore); | 134 | ret = own_fpu_inatomic(restore); |
93 | preempt_enable(); | 135 | preempt_enable(); |
136 | return ret; | ||
94 | } | 137 | } |
95 | 138 | ||
96 | static inline void lose_fpu(int save) | 139 | static inline void lose_fpu(int save) |
@@ -106,16 +149,21 @@ static inline void lose_fpu(int save) | |||
106 | preempt_enable(); | 149 | preempt_enable(); |
107 | } | 150 | } |
108 | 151 | ||
109 | static inline void init_fpu(void) | 152 | static inline int init_fpu(void) |
110 | { | 153 | { |
154 | int ret = 0; | ||
155 | |||
111 | preempt_disable(); | 156 | preempt_disable(); |
112 | if (cpu_has_fpu) { | 157 | if (cpu_has_fpu) { |
113 | __own_fpu(); | 158 | ret = __own_fpu(); |
114 | _init_fpu(); | 159 | if (!ret) |
160 | _init_fpu(); | ||
115 | } else { | 161 | } else { |
116 | fpu_emulator_init_fpu(); | 162 | fpu_emulator_init_fpu(); |
117 | } | 163 | } |
164 | |||
118 | preempt_enable(); | 165 | preempt_enable(); |
166 | return ret; | ||
119 | } | 167 | } |
120 | 168 | ||
121 | static inline void save_fp(struct task_struct *tsk) | 169 | static inline void save_fp(struct task_struct *tsk) |