aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2015-04-03 18:27:48 -0400
committerRalf Baechle <ralf@linux-mips.org>2015-04-07 19:10:37 -0400
commit9b26616c8d9dae53fbac7f7cb2c6dd1308102976 (patch)
treed4249bd953d4fa955cecd1283cc0f518df83f8a2 /arch/mips
parent232b6ec5df874236166fb0167cd473601a631715 (diff)
MIPS: Respect the ISA level in FCSR handling
Define the central place the default FCSR value is set from, initialised in `cpu_probe'. Determine the FCSR mask applied to values written to the register with CTC1 in the full emulation mode and via ptrace(2), according to the ISA level of processor hardware or the writability of bits 31:18 if actual FPU hardware is used. Software may rely on FCSR bits whose functions our emulator does not implement, so it should not allow them to be set or software may get confused. For ptrace(2) it's just sanity. [ralf@linux-mips.org: Fixed double inclusion of <asm/current.h>.] Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9711/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/include/asm/cpu-info.h2
-rw-r--r--arch/mips/include/asm/elf.h7
-rw-r--r--arch/mips/include/asm/fpu.h7
-rw-r--r--arch/mips/include/asm/fpu_emulator.h2
-rw-r--r--arch/mips/kernel/cpu-probe.c53
-rw-r--r--arch/mips/kernel/ptrace.c10
-rw-r--r--arch/mips/kernel/r2300_switch.S7
-rw-r--r--arch/mips/kernel/r4k_switch.S7
-rw-r--r--arch/mips/loongson/loongson-3/cop2-ex.c2
-rw-r--r--arch/mips/math-emu/cp1emu.c7
10 files changed, 83 insertions, 21 deletions
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h
index c3f4f2d2e108..e7dc785a91ca 100644
--- a/arch/mips/include/asm/cpu-info.h
+++ b/arch/mips/include/asm/cpu-info.h
@@ -49,6 +49,8 @@ struct cpuinfo_mips {
49 unsigned int udelay_val; 49 unsigned int udelay_val;
50 unsigned int processor_id; 50 unsigned int processor_id;
51 unsigned int fpu_id; 51 unsigned int fpu_id;
52 unsigned int fpu_csr31;
53 unsigned int fpu_msk31;
52 unsigned int msa_id; 54 unsigned int msa_id;
53 unsigned int cputype; 55 unsigned int cputype;
54 int isa_level; 56 int isa_level;
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index 535f196ffe02..612cf519bd88 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -11,6 +11,9 @@
11#include <linux/fs.h> 11#include <linux/fs.h>
12#include <uapi/linux/elf.h> 12#include <uapi/linux/elf.h>
13 13
14#include <asm/cpu-info.h>
15#include <asm/current.h>
16
14/* ELF header e_flags defines. */ 17/* ELF header e_flags defines. */
15/* MIPS architecture level. */ 18/* MIPS architecture level. */
16#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ 19#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
@@ -297,6 +300,8 @@ do { \
297 mips_set_personality_fp(state); \ 300 mips_set_personality_fp(state); \
298 \ 301 \
299 current->thread.abi = &mips_abi; \ 302 current->thread.abi = &mips_abi; \
303 \
304 current->thread.fpu.fcr31 = current_cpu_data.fpu_csr31; \
300} while (0) 305} while (0)
301 306
302#endif /* CONFIG_32BIT */ 307#endif /* CONFIG_32BIT */
@@ -356,6 +361,8 @@ do { \
356 else \ 361 else \
357 current->thread.abi = &mips_abi; \ 362 current->thread.abi = &mips_abi; \
358 \ 363 \
364 current->thread.fpu.fcr31 = current_cpu_data.fpu_csr31; \
365 \
359 p = personality(current->personality); \ 366 p = personality(current->personality); \
360 if (p != PER_LINUX32 && p != PER_LINUX) \ 367 if (p != PER_LINUX32 && p != PER_LINUX) \
361 set_personality(PER_LINUX); \ 368 set_personality(PER_LINUX); \
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h
index dd083e999b08..83d50d563a0f 100644
--- a/arch/mips/include/asm/fpu.h
+++ b/arch/mips/include/asm/fpu.h
@@ -30,7 +30,7 @@
30struct sigcontext; 30struct sigcontext;
31struct sigcontext32; 31struct sigcontext32;
32 32
33extern void _init_fpu(void); 33extern void _init_fpu(unsigned int);
34extern void _save_fp(struct task_struct *); 34extern void _save_fp(struct task_struct *);
35extern void _restore_fp(struct task_struct *); 35extern void _restore_fp(struct task_struct *);
36 36
@@ -182,6 +182,7 @@ static inline void lose_fpu(int save)
182 182
183static inline int init_fpu(void) 183static inline int init_fpu(void)
184{ 184{
185 unsigned int fcr31 = current->thread.fpu.fcr31;
185 int ret = 0; 186 int ret = 0;
186 187
187 if (cpu_has_fpu) { 188 if (cpu_has_fpu) {
@@ -192,7 +193,7 @@ static inline int init_fpu(void)
192 return ret; 193 return ret;
193 194
194 if (!cpu_has_fre) { 195 if (!cpu_has_fre) {
195 _init_fpu(); 196 _init_fpu(fcr31);
196 197
197 return 0; 198 return 0;
198 } 199 }
@@ -206,7 +207,7 @@ static inline int init_fpu(void)
206 config5 = clear_c0_config5(MIPS_CONF5_FRE); 207 config5 = clear_c0_config5(MIPS_CONF5_FRE);
207 enable_fpu_hazard(); 208 enable_fpu_hazard();
208 209
209 _init_fpu(); 210 _init_fpu(fcr31);
210 211
211 /* Restore FRE */ 212 /* Restore FRE */
212 write_c0_config5(config5); 213 write_c0_config5(config5);
diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h
index bfcc5c64b7b0..2f021cdfba4f 100644
--- a/arch/mips/include/asm/fpu_emulator.h
+++ b/arch/mips/include/asm/fpu_emulator.h
@@ -88,8 +88,6 @@ static inline void fpu_emulator_init_fpu(void)
88 struct task_struct *t = current; 88 struct task_struct *t = current;
89 int i; 89 int i;
90 90
91 t->thread.fpu.fcr31 = 0;
92
93 for (i = 0; i < 32; i++) 91 for (i = 0; i < 32; i++)
94 set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN); 92 set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
95} 93}
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index ca9b9c62c6ea..2911ad5977d7 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -33,6 +33,35 @@
33#include <asm/uaccess.h> 33#include <asm/uaccess.h>
34 34
35/* 35/*
36 * Determine the FCSR mask for FPU hardware.
37 */
38static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c)
39{
40 unsigned long sr, mask, fcsr, fcsr0, fcsr1;
41
42 mask = FPU_CSR_ALL_X | FPU_CSR_ALL_E | FPU_CSR_ALL_S | FPU_CSR_RM;
43
44 sr = read_c0_status();
45 __enable_fpu(FPU_AS_IS);
46
47 fcsr = read_32bit_cp1_register(CP1_STATUS);
48
49 fcsr0 = fcsr & mask;
50 write_32bit_cp1_register(CP1_STATUS, fcsr0);
51 fcsr0 = read_32bit_cp1_register(CP1_STATUS);
52
53 fcsr1 = fcsr | ~mask;
54 write_32bit_cp1_register(CP1_STATUS, fcsr1);
55 fcsr1 = read_32bit_cp1_register(CP1_STATUS);
56
57 write_32bit_cp1_register(CP1_STATUS, fcsr);
58
59 write_c0_status(sr);
60
61 c->fpu_msk31 = ~(fcsr0 ^ fcsr1) & ~mask;
62}
63
64/*
36 * Set the FIR feature flags for the FPU emulator. 65 * Set the FIR feature flags for the FPU emulator.
37 */ 66 */
38static void cpu_set_nofpu_id(struct cpuinfo_mips *c) 67static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
@@ -50,11 +79,15 @@ static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
50 c->fpu_id = value; 79 c->fpu_id = value;
51} 80}
52 81
82/* Determined FPU emulator mask to use for the boot CPU with "nofpu". */
83static unsigned int mips_nofpu_msk31;
84
53static int mips_fpu_disabled; 85static int mips_fpu_disabled;
54 86
55static int __init fpu_disable(char *s) 87static int __init fpu_disable(char *s)
56{ 88{
57 boot_cpu_data.options &= ~MIPS_CPU_FPU; 89 boot_cpu_data.options &= ~MIPS_CPU_FPU;
90 boot_cpu_data.fpu_msk31 = mips_nofpu_msk31;
58 cpu_set_nofpu_id(&boot_cpu_data); 91 cpu_set_nofpu_id(&boot_cpu_data);
59 mips_fpu_disabled = 1; 92 mips_fpu_disabled = 1;
60 93
@@ -597,6 +630,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
597 case PRID_IMP_R2000: 630 case PRID_IMP_R2000:
598 c->cputype = CPU_R2000; 631 c->cputype = CPU_R2000;
599 __cpu_name[cpu] = "R2000"; 632 __cpu_name[cpu] = "R2000";
633 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
600 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | 634 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
601 MIPS_CPU_NOFPUEX; 635 MIPS_CPU_NOFPUEX;
602 if (__cpu_has_fpu()) 636 if (__cpu_has_fpu())
@@ -616,6 +650,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
616 c->cputype = CPU_R3000; 650 c->cputype = CPU_R3000;
617 __cpu_name[cpu] = "R3000"; 651 __cpu_name[cpu] = "R3000";
618 } 652 }
653 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
619 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | 654 c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
620 MIPS_CPU_NOFPUEX; 655 MIPS_CPU_NOFPUEX;
621 if (__cpu_has_fpu()) 656 if (__cpu_has_fpu())
@@ -664,6 +699,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
664 } 699 }
665 700
666 set_isa(c, MIPS_CPU_ISA_III); 701 set_isa(c, MIPS_CPU_ISA_III);
702 c->fpu_msk31 |= FPU_CSR_CONDX;
667 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 703 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
668 MIPS_CPU_WATCH | MIPS_CPU_VCE | 704 MIPS_CPU_WATCH | MIPS_CPU_VCE |
669 MIPS_CPU_LLSC; 705 MIPS_CPU_LLSC;
@@ -671,6 +707,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
671 break; 707 break;
672 case PRID_IMP_VR41XX: 708 case PRID_IMP_VR41XX:
673 set_isa(c, MIPS_CPU_ISA_III); 709 set_isa(c, MIPS_CPU_ISA_III);
710 c->fpu_msk31 |= FPU_CSR_CONDX;
674 c->options = R4K_OPTS; 711 c->options = R4K_OPTS;
675 c->tlbsize = 32; 712 c->tlbsize = 32;
676 switch (c->processor_id & 0xf0) { 713 switch (c->processor_id & 0xf0) {
@@ -712,6 +749,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
712 c->cputype = CPU_R4300; 749 c->cputype = CPU_R4300;
713 __cpu_name[cpu] = "R4300"; 750 __cpu_name[cpu] = "R4300";
714 set_isa(c, MIPS_CPU_ISA_III); 751 set_isa(c, MIPS_CPU_ISA_III);
752 c->fpu_msk31 |= FPU_CSR_CONDX;
715 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 753 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
716 MIPS_CPU_LLSC; 754 MIPS_CPU_LLSC;
717 c->tlbsize = 32; 755 c->tlbsize = 32;
@@ -720,6 +758,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
720 c->cputype = CPU_R4600; 758 c->cputype = CPU_R4600;
721 __cpu_name[cpu] = "R4600"; 759 __cpu_name[cpu] = "R4600";
722 set_isa(c, MIPS_CPU_ISA_III); 760 set_isa(c, MIPS_CPU_ISA_III);
761 c->fpu_msk31 |= FPU_CSR_CONDX;
723 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 762 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
724 MIPS_CPU_LLSC; 763 MIPS_CPU_LLSC;
725 c->tlbsize = 48; 764 c->tlbsize = 48;
@@ -735,11 +774,13 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
735 c->cputype = CPU_R4650; 774 c->cputype = CPU_R4650;
736 __cpu_name[cpu] = "R4650"; 775 __cpu_name[cpu] = "R4650";
737 set_isa(c, MIPS_CPU_ISA_III); 776 set_isa(c, MIPS_CPU_ISA_III);
777 c->fpu_msk31 |= FPU_CSR_CONDX;
738 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC; 778 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
739 c->tlbsize = 48; 779 c->tlbsize = 48;
740 break; 780 break;
741 #endif 781 #endif
742 case PRID_IMP_TX39: 782 case PRID_IMP_TX39:
783 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
743 c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE; 784 c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE;
744 785
745 if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) { 786 if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
@@ -765,6 +806,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
765 c->cputype = CPU_R4700; 806 c->cputype = CPU_R4700;
766 __cpu_name[cpu] = "R4700"; 807 __cpu_name[cpu] = "R4700";
767 set_isa(c, MIPS_CPU_ISA_III); 808 set_isa(c, MIPS_CPU_ISA_III);
809 c->fpu_msk31 |= FPU_CSR_CONDX;
768 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | 810 c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
769 MIPS_CPU_LLSC; 811 MIPS_CPU_LLSC;
770 c->tlbsize = 48; 812 c->tlbsize = 48;
@@ -773,6 +815,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
773 c->cputype = CPU_TX49XX; 815 c->cputype = CPU_TX49XX;
774 __cpu_name[cpu] = "R49XX"; 816 __cpu_name[cpu] = "R49XX";
775 set_isa(c, MIPS_CPU_ISA_III); 817 set_isa(c, MIPS_CPU_ISA_III);
818 c->fpu_msk31 |= FPU_CSR_CONDX;
776 c->options = R4K_OPTS | MIPS_CPU_LLSC; 819 c->options = R4K_OPTS | MIPS_CPU_LLSC;
777 if (!(c->processor_id & 0x08)) 820 if (!(c->processor_id & 0x08))
778 c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR; 821 c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
@@ -814,6 +857,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
814 c->cputype = CPU_R6000; 857 c->cputype = CPU_R6000;
815 __cpu_name[cpu] = "R6000"; 858 __cpu_name[cpu] = "R6000";
816 set_isa(c, MIPS_CPU_ISA_II); 859 set_isa(c, MIPS_CPU_ISA_II);
860 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
817 c->options = MIPS_CPU_TLB | MIPS_CPU_FPU | 861 c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
818 MIPS_CPU_LLSC; 862 MIPS_CPU_LLSC;
819 c->tlbsize = 32; 863 c->tlbsize = 32;
@@ -822,6 +866,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
822 c->cputype = CPU_R6000A; 866 c->cputype = CPU_R6000A;
823 __cpu_name[cpu] = "R6000A"; 867 __cpu_name[cpu] = "R6000A";
824 set_isa(c, MIPS_CPU_ISA_II); 868 set_isa(c, MIPS_CPU_ISA_II);
869 c->fpu_msk31 |= FPU_CSR_CONDX | FPU_CSR_FS;
825 c->options = MIPS_CPU_TLB | MIPS_CPU_FPU | 870 c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
826 MIPS_CPU_LLSC; 871 MIPS_CPU_LLSC;
827 c->tlbsize = 32; 872 c->tlbsize = 32;
@@ -893,12 +938,14 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
893 __cpu_name[cpu] = "ICT Loongson-2"; 938 __cpu_name[cpu] = "ICT Loongson-2";
894 set_elf_platform(cpu, "loongson2e"); 939 set_elf_platform(cpu, "loongson2e");
895 set_isa(c, MIPS_CPU_ISA_III); 940 set_isa(c, MIPS_CPU_ISA_III);
941 c->fpu_msk31 |= FPU_CSR_CONDX;
896 break; 942 break;
897 case PRID_REV_LOONGSON2F: 943 case PRID_REV_LOONGSON2F:
898 c->cputype = CPU_LOONGSON2; 944 c->cputype = CPU_LOONGSON2;
899 __cpu_name[cpu] = "ICT Loongson-2"; 945 __cpu_name[cpu] = "ICT Loongson-2";
900 set_elf_platform(cpu, "loongson2f"); 946 set_elf_platform(cpu, "loongson2f");
901 set_isa(c, MIPS_CPU_ISA_III); 947 set_isa(c, MIPS_CPU_ISA_III);
948 c->fpu_msk31 |= FPU_CSR_CONDX;
902 break; 949 break;
903 case PRID_REV_LOONGSON3A: 950 case PRID_REV_LOONGSON3A:
904 c->cputype = CPU_LOONGSON3; 951 c->cputype = CPU_LOONGSON3;
@@ -1335,6 +1382,9 @@ void cpu_probe(void)
1335 c->cputype = CPU_UNKNOWN; 1382 c->cputype = CPU_UNKNOWN;
1336 c->writecombine = _CACHE_UNCACHED; 1383 c->writecombine = _CACHE_UNCACHED;
1337 1384
1385 c->fpu_csr31 = FPU_CSR_RN;
1386 c->fpu_msk31 = FPU_CSR_RSVD | FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
1387
1338 c->processor_id = read_c0_prid(); 1388 c->processor_id = read_c0_prid();
1339 switch (c->processor_id & PRID_COMP_MASK) { 1389 switch (c->processor_id & PRID_COMP_MASK) {
1340 case PRID_COMP_LEGACY: 1390 case PRID_COMP_LEGACY:
@@ -1393,6 +1443,7 @@ void cpu_probe(void)
1393 1443
1394 if (c->options & MIPS_CPU_FPU) { 1444 if (c->options & MIPS_CPU_FPU) {
1395 c->fpu_id = cpu_get_fpu_id(); 1445 c->fpu_id = cpu_get_fpu_id();
1446 mips_nofpu_msk31 = c->fpu_msk31;
1396 1447
1397 if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 | 1448 if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
1398 MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 | 1449 MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
@@ -1402,6 +1453,8 @@ void cpu_probe(void)
1402 if (c->fpu_id & MIPS_FPIR_FREP) 1453 if (c->fpu_id & MIPS_FPIR_FREP)
1403 c->options |= MIPS_CPU_FRE; 1454 c->options |= MIPS_CPU_FRE;
1404 } 1455 }
1456
1457 cpu_set_fpu_fcsr_mask(c);
1405 } else 1458 } else
1406 cpu_set_nofpu_id(c); 1459 cpu_set_nofpu_id(c);
1407 1460
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 510452812594..6d1e3f8005f7 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -32,6 +32,7 @@
32 32
33#include <asm/byteorder.h> 33#include <asm/byteorder.h>
34#include <asm/cpu.h> 34#include <asm/cpu.h>
35#include <asm/cpu-info.h>
35#include <asm/dsp.h> 36#include <asm/dsp.h>
36#include <asm/fpu.h> 37#include <asm/fpu.h>
37#include <asm/mipsregs.h> 38#include <asm/mipsregs.h>
@@ -137,6 +138,9 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
137{ 138{
138 union fpureg *fregs; 139 union fpureg *fregs;
139 u64 fpr_val; 140 u64 fpr_val;
141 u32 fcr31;
142 u32 value;
143 u32 mask;
140 int i; 144 int i;
141 145
142 if (!access_ok(VERIFY_READ, data, 33 * 8)) 146 if (!access_ok(VERIFY_READ, data, 33 * 8))
@@ -149,8 +153,10 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
149 set_fpr64(&fregs[i], 0, fpr_val); 153 set_fpr64(&fregs[i], 0, fpr_val);
150 } 154 }
151 155
152 __get_user(child->thread.fpu.fcr31, data + 64); 156 __get_user(value, data + 64);
153 child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; 157 fcr31 = child->thread.fpu.fcr31;
158 mask = current_cpu_data.fpu_msk31;
159 child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
154 160
155 /* FIR may not be written. */ 161 /* FIR may not be written. */
156 162
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 435ea652f5fa..5087a4b72e6b 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -115,11 +115,9 @@ LEAF(_restore_fp)
115 * the property that no matter whether considered as single or as double 115 * the property that no matter whether considered as single or as double
116 * precision represents signaling NANS. 116 * precision represents signaling NANS.
117 * 117 *
118 * We initialize fcr31 to rounding to nearest, no exceptions. 118 * The value to initialize fcr31 to comes in $a0.
119 */ 119 */
120 120
121#define FPU_DEFAULT 0x00000000
122
123 .set push 121 .set push
124 SET_HARDFLOAT 122 SET_HARDFLOAT
125 123
@@ -129,8 +127,7 @@ LEAF(_init_fpu)
129 or t0, t1 127 or t0, t1
130 mtc0 t0, CP0_STATUS 128 mtc0 t0, CP0_STATUS
131 129
132 li t1, FPU_DEFAULT 130 ctc1 a0, fcr31
133 ctc1 t1, fcr31
134 131
135 li t0, -1 132 li t0, -1
136 133
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 3b1a36f13a7d..04cbbde3521b 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -165,11 +165,9 @@ LEAF(_init_msa_upper)
165 * the property that no matter whether considered as single or as double 165 * the property that no matter whether considered as single or as double
166 * precision represents signaling NANS. 166 * precision represents signaling NANS.
167 * 167 *
168 * We initialize fcr31 to rounding to nearest, no exceptions. 168 * The value to initialize fcr31 to comes in $a0.
169 */ 169 */
170 170
171#define FPU_DEFAULT 0x00000000
172
173 .set push 171 .set push
174 SET_HARDFLOAT 172 SET_HARDFLOAT
175 173
@@ -180,8 +178,7 @@ LEAF(_init_fpu)
180 mtc0 t0, CP0_STATUS 178 mtc0 t0, CP0_STATUS
181 enable_fpu_hazard 179 enable_fpu_hazard
182 180
183 li t1, FPU_DEFAULT 181 ctc1 a0, fcr31
184 ctc1 t1, fcr31
185 182
186 li t1, -1 # SNaN 183 li t1, -1 # SNaN
187 184
diff --git a/arch/mips/loongson/loongson-3/cop2-ex.c b/arch/mips/loongson/loongson-3/cop2-ex.c
index b03e37d2071a..ea13764d0a03 100644
--- a/arch/mips/loongson/loongson-3/cop2-ex.c
+++ b/arch/mips/loongson/loongson-3/cop2-ex.c
@@ -43,7 +43,7 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
43 if (!fpu_owned) { 43 if (!fpu_owned) {
44 set_thread_flag(TIF_USEDFPU); 44 set_thread_flag(TIF_USEDFPU);
45 if (!used_math()) { 45 if (!used_math()) {
46 _init_fpu(); 46 _init_fpu(current->thread.fpu.fcr31);
47 set_used_math(); 47 set_used_math();
48 } else 48 } else
49 _restore_fp(current); 49 _restore_fp(current);
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 3a90170a6277..d31c537ace1d 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -908,6 +908,7 @@ static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
908{ 908{
909 u32 fcr31 = ctx->fcr31; 909 u32 fcr31 = ctx->fcr31;
910 u32 value; 910 u32 value;
911 u32 mask;
911 912
912 if (MIPSInst_RT(ir) == 0) 913 if (MIPSInst_RT(ir) == 0)
913 value = 0; 914 value = 0;
@@ -919,9 +920,9 @@ static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
919 pr_debug("%p gpr[%d]->csr=%08x\n", 920 pr_debug("%p gpr[%d]->csr=%08x\n",
920 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value); 921 (void *)xcp->cp0_epc, MIPSInst_RT(ir), value);
921 922
922 /* Don't write unsupported bits. */ 923 /* Preserve read-only bits. */
923 fcr31 = value & 924 mask = current_cpu_data.fpu_msk31;
924 ~(FPU_CSR_RSVD | FPU_CSR_ABS2008 | FPU_CSR_NAN2008); 925 fcr31 = (value & ~mask) | (fcr31 & mask);
925 break; 926 break;
926 927
927 case FPCREG_FENR: 928 case FPCREG_FENR: