summaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2014-07-11 16:44:29 +0100
committerRalf Baechle <ralf@linux-mips.org>2014-08-02 00:06:43 +0200
commitb83406735a4ae0aff4b614664d6a64a0fd6b9917 (patch)
tree2fd9b98b88f6f19c421001666b4aaeb943d1e7e7 /arch/mips
parentf7a46fa7bb0047d3e226702a0c4b786862fe6843 (diff)
MIPS: preserve scalar FP CSR when switching vector context
Switching the vector context implicitly saves & restores the state of the aliased scalar FP data registers, however the scalar FP control & status register is distinct from the MSA control & status register. In order to allow scalar FP to function correctly in programs using MSA, the scalar CSR needs to be saved & restored along with the MSA vector context. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7301/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kernel/r4k_switch.S4
-rw-r--r--arch/mips/kernel/traps.c5
2 files changed, 8 insertions, 1 deletions
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 81ca3f70fe2..1a1aef04312 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -64,8 +64,10 @@
/* Check whether we're saving scalar or vector context. */
bgtz a3, 1f
- /* Save 128b MSA vector context. */
+ /* Save 128b MSA vector context + scalar FP control & status. */
+ cfc1 t1, fcr31
msa_save_all a0
+ sw t1, THREAD_FCR31(a0)
b 2f
1: /* Save 32b/64b scalar FP context. */
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 1a328b1e288..649c151fe1d 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1154,6 +1154,11 @@ static int enable_restore_fp_context(int msa)
/* We need to restore the vector context. */
restore_msa(current);
+
+ /* Restore the scalar FP control & status register */
+ if (!was_fpu_owner)
+ asm volatile("ctc1 %0, $31" : : "r"(current->thread.fpu.fcr31));
+
return 0;
}