Skip to content

Commit cc97ab2

Browse files
committed
MIPS: Simplify FP context initialization
MIPS has up until now had 3 different ways for a task's floating point context to be initialized: - If the task's first use of FP involves it gaining ownership of an FPU then _init_fpu() is used to initialize the FPU's registers such that they all contain ~0, and the FPU registers will be stored to struct thread_info later (eg. when context switching). - If the task first uses FP on a CPU without an associated FPU then fpu_emulator_init_fpu() initializes the task's floating point register state in struct thread_info such that all floating point register contain the bit pattern 0x7ff800007ff80000, different to the _init_fpu() behaviour. - If a task's floating point context is first accessed via ptrace then init_fp_ctx() initializes the floating point register state in struct thread_info to ~0, giving equivalent state to _init_fpu(). The _init_fpu() path has 2 separate implementations - one for r2k/r3k style systems & one for r4k style systems. The _init_fpu() path also requires that we be careful to clear & restore the value of the Config5.FRE bit on modern systems in order to avoid inadvertently triggering floating point exceptions. None of this code is in a performance critical hot path - it runs only the first time a task uses floating point. As such it doesn't seem to warrant the complications of maintaining the _init_fpu() path. Remove _init_fpu() & fpu_emulator_init_fpu(), instead using init_fp_ctx() consistently to initialize floating point register state in struct thread_info. Upon a task's first use of floating point this will typically mean that we initialize state in memory & then load it into FPU registers using _restore_fp() just as we would on a context switch. For other paths such as __compute_return_epc_for_insn() or mipsr2_decoder() this results in a significant simplification of the work to be done. Signed-off-by: Paul Burton <[email protected]> Patchwork: https://patchwork.linux-mips.org/patch/21002/ Cc: [email protected]
1 parent b1013f1 commit cc97ab2

File tree

9 files changed

+38
-292
lines changed

9 files changed

+38
-292
lines changed

arch/mips/include/asm/fpu.h

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
struct sigcontext;
3434
struct sigcontext32;
3535

36-
extern void _init_fpu(unsigned int);
3736
extern void _save_fp(struct task_struct *);
3837
extern void _restore_fp(struct task_struct *);
3938

@@ -198,42 +197,36 @@ static inline void lose_fpu(int save)
198197
preempt_enable();
199198
}
200199

201-
static inline int init_fpu(void)
200+
/**
201+
* init_fp_ctx() - Initialize task FP context
202+
* @target: The task whose FP context should be initialized.
203+
*
204+
* Initializes the FP context of the target task to sane default values if that
205+
* target task does not already have valid FP context. Once the context has
206+
* been initialized, the task will be marked as having used FP & thus having
207+
* valid FP context.
208+
*
209+
* Returns: true if context is initialized, else false.
210+
*/
211+
static inline bool init_fp_ctx(struct task_struct *target)
202212
{
203-
unsigned int fcr31 = current->thread.fpu.fcr31;
204-
int ret = 0;
205-
206-
if (cpu_has_fpu) {
207-
unsigned int config5;
208-
209-
ret = __own_fpu();
210-
if (ret)
211-
return ret;
213+
/* If FP has been used then the target already has context */
214+
if (tsk_used_math(target))
215+
return false;
212216

213-
if (!cpu_has_fre) {
214-
_init_fpu(fcr31);
217+
/* Begin with data registers set to all 1s... */
218+
memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr));
215219

216-
return 0;
217-
}
218-
219-
/*
220-
* Ensure FRE is clear whilst running _init_fpu, since
221-
* single precision FP instructions are used. If FRE
222-
* was set then we'll just end up initialising all 32
223-
* 64b registers.
224-
*/
225-
config5 = clear_c0_config5(MIPS_CONF5_FRE);
226-
enable_fpu_hazard();
220+
/* FCSR has been preset by `mips_set_personality_nan'. */
227221

228-
_init_fpu(fcr31);
222+
/*
223+
* Record that the target has "used" math, such that the context
224+
* just initialised, and any modifications made by the caller,
225+
* aren't discarded.
226+
*/
227+
set_stopped_child_used_math(target);
229228

230-
/* Restore FRE */
231-
write_c0_config5(config5);
232-
enable_fpu_hazard();
233-
} else
234-
fpu_emulator_init_fpu();
235-
236-
return ret;
229+
return true;
237230
}
238231

239232
static inline void save_fp(struct task_struct *tsk)

arch/mips/include/asm/fpu_emulator.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -188,17 +188,6 @@ int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
188188
int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
189189
unsigned long *contpc);
190190

191-
#define SIGNALLING_NAN 0x7ff800007ff80000LL
192-
193-
static inline void fpu_emulator_init_fpu(void)
194-
{
195-
struct task_struct *t = current;
196-
int i;
197-
198-
for (i = 0; i < 32; i++)
199-
set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
200-
}
201-
202191
/*
203192
* Mask the FCSR Cause bits according to the Enable bits, observing
204193
* that Unimplemented is always enabled.

arch/mips/kernel/branch.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -674,16 +674,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
674674
if (cpu_has_mips_r6 &&
675675
((insn.i_format.rs == bc1eqz_op) ||
676676
(insn.i_format.rs == bc1nez_op))) {
677-
if (!used_math()) { /* First time FPU user */
678-
ret = init_fpu();
679-
if (ret && NO_R6EMU) {
680-
ret = -ret;
681-
break;
682-
}
683-
ret = 0;
684-
set_used_math();
685-
}
686-
lose_fpu(1); /* Save FPU state for the emulator. */
677+
if (!init_fp_ctx(current))
678+
lose_fpu(1);
687679
reg = insn.i_format.rt;
688680
bit = get_fpr32(&current->thread.fpu.fpr[reg], 0) & 0x1;
689681
if (insn.i_format.rs == bc1eqz_op)

arch/mips/kernel/mips-r2-to-r6-emul.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,13 +1174,9 @@ int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
11741174
fpu_emul:
11751175
regs->regs[31] = r31;
11761176
regs->cp0_epc = epc;
1177-
if (!used_math()) { /* First time FPU user. */
1178-
preempt_disable();
1179-
err = init_fpu();
1180-
preempt_enable();
1181-
set_used_math();
1182-
}
1183-
lose_fpu(1); /* Save FPU state for the emulator. */
1177+
1178+
if (!init_fp_ctx(current))
1179+
lose_fpu(1);
11841180

11851181
err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
11861182
&fault_addr);

arch/mips/kernel/ptrace.c

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,25 +50,6 @@
5050
#define CREATE_TRACE_POINTS
5151
#include <trace/events/syscalls.h>
5252

53-
static void init_fp_ctx(struct task_struct *target)
54-
{
55-
/* If FP has been used then the target already has context */
56-
if (tsk_used_math(target))
57-
return;
58-
59-
/* Begin with data registers set to all 1s... */
60-
memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr));
61-
62-
/* FCSR has been preset by `mips_set_personality_nan'. */
63-
64-
/*
65-
* Record that the target has "used" math, such that the context
66-
* just initialised, and any modifications made by the caller,
67-
* aren't discarded.
68-
*/
69-
set_stopped_child_used_math(target);
70-
}
71-
7253
/*
7354
* Called by kernel/ptrace.c when detaching..
7455
*

arch/mips/kernel/r2300_fpu.S

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -52,64 +52,6 @@ LEAF(_restore_fp)
5252
jr ra
5353
END(_restore_fp)
5454

55-
/*
56-
* Load the FPU with signalling NANS. This bit pattern we're using has
57-
* the property that no matter whether considered as single or as double
58-
* precision represents signaling NANS.
59-
*
60-
* The value to initialize fcr31 to comes in $a0.
61-
*/
62-
63-
.set push
64-
SET_HARDFLOAT
65-
66-
LEAF(_init_fpu)
67-
mfc0 t0, CP0_STATUS
68-
li t1, ST0_CU1
69-
or t0, t1
70-
mtc0 t0, CP0_STATUS
71-
72-
ctc1 a0, fcr31
73-
74-
li t0, -1
75-
76-
mtc1 t0, $f0
77-
mtc1 t0, $f1
78-
mtc1 t0, $f2
79-
mtc1 t0, $f3
80-
mtc1 t0, $f4
81-
mtc1 t0, $f5
82-
mtc1 t0, $f6
83-
mtc1 t0, $f7
84-
mtc1 t0, $f8
85-
mtc1 t0, $f9
86-
mtc1 t0, $f10
87-
mtc1 t0, $f11
88-
mtc1 t0, $f12
89-
mtc1 t0, $f13
90-
mtc1 t0, $f14
91-
mtc1 t0, $f15
92-
mtc1 t0, $f16
93-
mtc1 t0, $f17
94-
mtc1 t0, $f18
95-
mtc1 t0, $f19
96-
mtc1 t0, $f20
97-
mtc1 t0, $f21
98-
mtc1 t0, $f22
99-
mtc1 t0, $f23
100-
mtc1 t0, $f24
101-
mtc1 t0, $f25
102-
mtc1 t0, $f26
103-
mtc1 t0, $f27
104-
mtc1 t0, $f28
105-
mtc1 t0, $f29
106-
mtc1 t0, $f30
107-
mtc1 t0, $f31
108-
jr ra
109-
END(_init_fpu)
110-
111-
.set pop
112-
11355
.set noreorder
11456

11557
/**

arch/mips/kernel/r4k_fpu.S

Lines changed: 0 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -86,150 +86,6 @@ LEAF(_init_msa_upper)
8686

8787
#endif
8888

89-
/*
90-
* Load the FPU with signalling NANS. This bit pattern we're using has
91-
* the property that no matter whether considered as single or as double
92-
* precision represents signaling NANS.
93-
*
94-
* The value to initialize fcr31 to comes in $a0.
95-
*/
96-
97-
.set push
98-
SET_HARDFLOAT
99-
100-
LEAF(_init_fpu)
101-
mfc0 t0, CP0_STATUS
102-
li t1, ST0_CU1
103-
or t0, t1
104-
mtc0 t0, CP0_STATUS
105-
enable_fpu_hazard
106-
107-
ctc1 a0, fcr31
108-
109-
li t1, -1 # SNaN
110-
111-
#ifdef CONFIG_64BIT
112-
sll t0, t0, 5
113-
bgez t0, 1f # 16 / 32 register mode?
114-
115-
dmtc1 t1, $f1
116-
dmtc1 t1, $f3
117-
dmtc1 t1, $f5
118-
dmtc1 t1, $f7
119-
dmtc1 t1, $f9
120-
dmtc1 t1, $f11
121-
dmtc1 t1, $f13
122-
dmtc1 t1, $f15
123-
dmtc1 t1, $f17
124-
dmtc1 t1, $f19
125-
dmtc1 t1, $f21
126-
dmtc1 t1, $f23
127-
dmtc1 t1, $f25
128-
dmtc1 t1, $f27
129-
dmtc1 t1, $f29
130-
dmtc1 t1, $f31
131-
1:
132-
#endif
133-
134-
#ifdef CONFIG_CPU_MIPS32
135-
mtc1 t1, $f0
136-
mtc1 t1, $f1
137-
mtc1 t1, $f2
138-
mtc1 t1, $f3
139-
mtc1 t1, $f4
140-
mtc1 t1, $f5
141-
mtc1 t1, $f6
142-
mtc1 t1, $f7
143-
mtc1 t1, $f8
144-
mtc1 t1, $f9
145-
mtc1 t1, $f10
146-
mtc1 t1, $f11
147-
mtc1 t1, $f12
148-
mtc1 t1, $f13
149-
mtc1 t1, $f14
150-
mtc1 t1, $f15
151-
mtc1 t1, $f16
152-
mtc1 t1, $f17
153-
mtc1 t1, $f18
154-
mtc1 t1, $f19
155-
mtc1 t1, $f20
156-
mtc1 t1, $f21
157-
mtc1 t1, $f22
158-
mtc1 t1, $f23
159-
mtc1 t1, $f24
160-
mtc1 t1, $f25
161-
mtc1 t1, $f26
162-
mtc1 t1, $f27
163-
mtc1 t1, $f28
164-
mtc1 t1, $f29
165-
mtc1 t1, $f30
166-
mtc1 t1, $f31
167-
168-
#if defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS32_R6)
169-
.set push
170-
.set MIPS_ISA_LEVEL_RAW
171-
.set fp=64
172-
sll t0, t0, 5 # is Status.FR set?
173-
bgez t0, 1f # no: skip setting upper 32b
174-
175-
mthc1 t1, $f0
176-
mthc1 t1, $f1
177-
mthc1 t1, $f2
178-
mthc1 t1, $f3
179-
mthc1 t1, $f4
180-
mthc1 t1, $f5
181-
mthc1 t1, $f6
182-
mthc1 t1, $f7
183-
mthc1 t1, $f8
184-
mthc1 t1, $f9
185-
mthc1 t1, $f10
186-
mthc1 t1, $f11
187-
mthc1 t1, $f12
188-
mthc1 t1, $f13
189-
mthc1 t1, $f14
190-
mthc1 t1, $f15
191-
mthc1 t1, $f16
192-
mthc1 t1, $f17
193-
mthc1 t1, $f18
194-
mthc1 t1, $f19
195-
mthc1 t1, $f20
196-
mthc1 t1, $f21
197-
mthc1 t1, $f22
198-
mthc1 t1, $f23
199-
mthc1 t1, $f24
200-
mthc1 t1, $f25
201-
mthc1 t1, $f26
202-
mthc1 t1, $f27
203-
mthc1 t1, $f28
204-
mthc1 t1, $f29
205-
mthc1 t1, $f30
206-
mthc1 t1, $f31
207-
1: .set pop
208-
#endif /* CONFIG_CPU_MIPS32_R2 || CONFIG_CPU_MIPS32_R6 */
209-
#else
210-
.set MIPS_ISA_ARCH_LEVEL_RAW
211-
dmtc1 t1, $f0
212-
dmtc1 t1, $f2
213-
dmtc1 t1, $f4
214-
dmtc1 t1, $f6
215-
dmtc1 t1, $f8
216-
dmtc1 t1, $f10
217-
dmtc1 t1, $f12
218-
dmtc1 t1, $f14
219-
dmtc1 t1, $f16
220-
dmtc1 t1, $f18
221-
dmtc1 t1, $f20
222-
dmtc1 t1, $f22
223-
dmtc1 t1, $f24
224-
dmtc1 t1, $f26
225-
dmtc1 t1, $f28
226-
dmtc1 t1, $f30
227-
#endif
228-
jr ra
229-
END(_init_fpu)
230-
231-
.set pop /* SET_HARDFLOAT */
232-
23389
.set noreorder
23490

23591
/**

arch/mips/kernel/traps.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,20 +1218,20 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
12181218
static int enable_restore_fp_context(int msa)
12191219
{
12201220
int err, was_fpu_owner, prior_msa;
1221+
bool first_fp;
12211222

1222-
if (!used_math()) {
1223-
/* First time FP context user. */
1223+
/* Initialize context if it hasn't been used already */
1224+
first_fp = init_fp_ctx(current);
1225+
1226+
if (first_fp) {
12241227
preempt_disable();
1225-
err = init_fpu();
1228+
err = own_fpu_inatomic(1);
12261229
if (msa && !err) {
12271230
enable_msa();
1228-
init_msa_upper();
12291231
set_thread_flag(TIF_USEDMSA);
12301232
set_thread_flag(TIF_MSA_CTX_LIVE);
12311233
}
12321234
preempt_enable();
1233-
if (!err)
1234-
set_used_math();
12351235
return err;
12361236
}
12371237

0 commit comments

Comments
 (0)