aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2005-10-27 02:27:25 -0400
committerPaul Mackerras <paulus@samba.org>2005-10-27 06:48:50 -0400
commit25c8a78b1e00ac0cc640677eda78b462c2cd4c6e (patch)
treea0044f8b2b557799a8cb3346b590fcd3a8507ed7
parentfda262b8978d0089758ef9444508434c74113a61 (diff)
[PATCH] powerpc: Fix handling of fpscr on 64-bit
The recent merge of fpu.S broken the handling of fpscr for ARCH=powerpc and CONFIG_PPC64=y. FP registers could be corrupted, leading to strange random application crashes. The confusion arises, because the thread_struct has (and requires) a 64-bit area to save the fpscr, because we use load/store double instructions to get it in to/out of the FPU. However, only the low 32-bits are actually used, so we want to treat it as a 32-bit quantity when manipulating its bits to avoid extra load/stores on 32-bit. This patch replaces the current definition with a structure of two 32-bit quantities (pad and val), to clarify things as much as is possible. The 'val' field is used when manipulating bits, the structure itself is used when obtaining the address for loading/unloading the value from the FPU. While we're at it, consolidate the 4 (!) almost identical versions of cvt_fd() and cvt_df() (arch/ppc/kernel/misc.S, arch/ppc64/kernel/misc.S, arch/powerpc/kernel/misc_32.S, arch/powerpc/kernel/misc_64.S) into a single version in fpu.S. The new version takes a pointer to thread_struct and applies the correct offset itself, rather than a pointer to the fpscr field itself, again to avoid confusion as to which is the correct field to use. Finally, this patch makes ARCH=ppc64 also use the consolidated fpu.S code, which it previously did not. Built for G5 (ARCH=ppc64 and ARCH=powerpc), 32-bit powermac (ARCH=ppc and ARCH=powerpc) and Walnut (ARCH=ppc, CONFIG_MATH_EMULATION=y). Booted on G5 (ARCH=powerpc) and things which previously fell over no longer do. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/Makefile5
-rw-r--r--arch/powerpc/kernel/fpu.S31
-rw-r--r--arch/powerpc/kernel/misc_32.S27
-rw-r--r--arch/powerpc/kernel/misc_64.S19
-rw-r--r--arch/powerpc/kernel/process.c2
-rw-r--r--arch/powerpc/kernel/signal_32.c2
-rw-r--r--arch/powerpc/kernel/traps.c2
-rw-r--r--arch/ppc/kernel/align.c4
-rw-r--r--arch/ppc/kernel/misc.S27
-rw-r--r--arch/ppc/kernel/process.c2
-rw-r--r--arch/ppc/kernel/traps.c2
-rw-r--r--arch/ppc/math-emu/sfp-machine.h2
-rw-r--r--arch/ppc64/Kconfig3
-rw-r--r--arch/ppc64/Makefile1
-rw-r--r--arch/ppc64/kernel/align.c4
-rw-r--r--arch/ppc64/kernel/head.S59
-rw-r--r--arch/ppc64/kernel/misc.S51
-rw-r--r--arch/ppc64/kernel/signal.c2
-rw-r--r--include/asm-powerpc/processor.h11
-rw-r--r--include/asm-powerpc/system.h4
-rw-r--r--include/asm-ppc/system.h4
-rw-r--r--include/asm-ppc64/system.h4
22 files changed, 59 insertions, 209 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index a733347964a0..94cf917b7854 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -29,7 +29,6 @@ extra-$(CONFIG_44x) := head_44x.o
29extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o 29extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o
30extra-$(CONFIG_8xx) := head_8xx.o 30extra-$(CONFIG_8xx) := head_8xx.o
31extra-$(CONFIG_PPC64) += entry_64.o 31extra-$(CONFIG_PPC64) += entry_64.o
32extra-$(CONFIG_PPC_FPU) += fpu.o
33extra-y += vmlinux.lds 32extra-y += vmlinux.lds
34 33
35obj-y += process.o init_task.o time.o \ 34obj-y += process.o init_task.o time.o \
@@ -49,7 +48,7 @@ else
49# stuff used from here for ARCH=ppc or ARCH=ppc64 48# stuff used from here for ARCH=ppc or ARCH=ppc64
50obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o 49obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o
51 50
52fpux-$(CONFIG_PPC32) += fpu.o
53extra-$(CONFIG_PPC_FPU) += $(fpux-y)
54 51
55endif 52endif
53
54extra-$(CONFIG_PPC_FPU) += fpu.o
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 563d445ff584..51fd78da25b7 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -48,7 +48,7 @@ _GLOBAL(load_up_fpu)
48 addi r4,r4,THREAD /* want last_task_used_math->thread */ 48 addi r4,r4,THREAD /* want last_task_used_math->thread */
49 SAVE_32FPRS(0, r4) 49 SAVE_32FPRS(0, r4)
50 mffs fr0 50 mffs fr0
51 stfd fr0,THREAD_FPSCR-4(r4) 51 stfd fr0,THREAD_FPSCR(r4)
52 LDL r5,PT_REGS(r4) 52 LDL r5,PT_REGS(r4)
53 tophys(r5,r5) 53 tophys(r5,r5)
54 LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) 54 LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
@@ -71,7 +71,7 @@ _GLOBAL(load_up_fpu)
71 or r12,r12,r4 71 or r12,r12,r4
72 std r12,_MSR(r1) 72 std r12,_MSR(r1)
73#endif 73#endif
74 lfd fr0,THREAD_FPSCR-4(r5) 74 lfd fr0,THREAD_FPSCR(r5)
75 mtfsf 0xff,fr0 75 mtfsf 0xff,fr0
76 REST_32FPRS(0, r5) 76 REST_32FPRS(0, r5)
77#ifndef CONFIG_SMP 77#ifndef CONFIG_SMP
@@ -104,7 +104,7 @@ _GLOBAL(giveup_fpu)
104 CMPI 0,r5,0 104 CMPI 0,r5,0
105 SAVE_32FPRS(0, r3) 105 SAVE_32FPRS(0, r3)
106 mffs fr0 106 mffs fr0
107 stfd fr0,THREAD_FPSCR-4(r3) 107 stfd fr0,THREAD_FPSCR(r3)
108 beq 1f 108 beq 1f
109 LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) 109 LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
110 li r3,MSR_FP|MSR_FE0|MSR_FE1 110 li r3,MSR_FP|MSR_FE0|MSR_FE1
@@ -117,3 +117,28 @@ _GLOBAL(giveup_fpu)
117 STL r5,OFF(last_task_used_math)(r4) 117 STL r5,OFF(last_task_used_math)(r4)
118#endif /* CONFIG_SMP */ 118#endif /* CONFIG_SMP */
119 blr 119 blr
120
121/*
122 * These are used in the alignment trap handler when emulating
123 * single-precision loads and stores.
124 * We restore and save the fpscr so the task gets the same result
125 * and exceptions as if the cpu had performed the load or store.
126 */
127
128_GLOBAL(cvt_fd)
129 lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */
130 mtfsf 0xff,0
131 lfs 0,0(r3)
132 stfd 0,0(r4)
133 mffs 0
134 stfd 0,THREAD_FPSCR(r5) /* save new fpscr value */
135 blr
136
137_GLOBAL(cvt_df)
138 lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */
139 mtfsf 0xff,0
140 lfd 0,0(r3)
141 stfs 0,0(r4)
142 mffs 0
143 stfd 0,THREAD_FPSCR(r5) /* save new fpscr value */
144 blr
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 303229b090b8..3bedb532aed9 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -993,33 +993,6 @@ _GLOBAL(_get_SP)
993 blr 993 blr
994 994
995/* 995/*
996 * These are used in the alignment trap handler when emulating
997 * single-precision loads and stores.
998 * We restore and save the fpscr so the task gets the same result
999 * and exceptions as if the cpu had performed the load or store.
1000 */
1001
1002#ifdef CONFIG_PPC_FPU
1003_GLOBAL(cvt_fd)
1004 lfd 0,-4(r5) /* load up fpscr value */
1005 mtfsf 0xff,0
1006 lfs 0,0(r3)
1007 stfd 0,0(r4)
1008 mffs 0 /* save new fpscr value */
1009 stfd 0,-4(r5)
1010 blr
1011
1012_GLOBAL(cvt_df)
1013 lfd 0,-4(r5) /* load up fpscr value */
1014 mtfsf 0xff,0
1015 lfd 0,0(r3)
1016 stfs 0,0(r4)
1017 mffs 0 /* save new fpscr value */
1018 stfd 0,-4(r5)
1019 blr
1020#endif
1021
1022/*
1023 * Create a kernel thread 996 * Create a kernel thread
1024 * kernel_thread(fn, arg, flags) 997 * kernel_thread(fn, arg, flags)
1025 */ 998 */
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 4775bed42cac..b3e95ff0dba0 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -462,25 +462,6 @@ _GLOBAL(_outsl_ns)
462 sync 462 sync
463 blr 463 blr
464 464
465
466_GLOBAL(cvt_fd)
467 lfd 0,0(r5) /* load up fpscr value */
468 mtfsf 0xff,0
469 lfs 0,0(r3)
470 stfd 0,0(r4)
471 mffs 0 /* save new fpscr value */
472 stfd 0,0(r5)
473 blr
474
475_GLOBAL(cvt_df)
476 lfd 0,0(r5) /* load up fpscr value */
477 mtfsf 0xff,0
478 lfd 0,0(r3)
479 stfs 0,0(r4)
480 mffs 0 /* save new fpscr value */
481 stfd 0,0(r5)
482 blr
483
484/* 465/*
485 * identify_cpu and calls setup_cpu 466 * identify_cpu and calls setup_cpu
486 * In: r3 = base of the cpu_specs array 467 * In: r3 = base of the cpu_specs array
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 047da1ae21fe..8f85dabe4df3 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -665,7 +665,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
665#endif 665#endif
666#endif /* CONFIG_SMP */ 666#endif /* CONFIG_SMP */
667 memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); 667 memset(current->thread.fpr, 0, sizeof(current->thread.fpr));
668 current->thread.fpscr = 0; 668 current->thread.fpscr.val = 0;
669#ifdef CONFIG_ALTIVEC 669#ifdef CONFIG_ALTIVEC
670 memset(current->thread.vr, 0, sizeof(current->thread.vr)); 670 memset(current->thread.vr, 0, sizeof(current->thread.vr));
671 memset(&current->thread.vscr, 0, sizeof(current->thread.vscr)); 671 memset(&current->thread.vscr, 0, sizeof(current->thread.vscr));
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 92452b2db26a..444c3e81884c 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -403,7 +403,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
403 ELF_NFPREG * sizeof(double))) 403 ELF_NFPREG * sizeof(double)))
404 return 1; 404 return 1;
405 405
406 current->thread.fpscr = 0; /* turn off all fp exceptions */ 406 current->thread.fpscr.val = 0; /* turn off all fp exceptions */
407 407
408#ifdef CONFIG_ALTIVEC 408#ifdef CONFIG_ALTIVEC
409 /* save altivec registers */ 409 /* save altivec registers */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index f87580382da4..5d638ecddbd0 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -549,7 +549,7 @@ static void parse_fpe(struct pt_regs *regs)
549 549
550 flush_fp_to_thread(current); 550 flush_fp_to_thread(current);
551 551
552 fpscr = current->thread.fpscr; 552 fpscr = current->thread.fpscr.val;
553 553
554 /* Invalid operation */ 554 /* Invalid operation */
555 if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) 555 if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
index ff81da9598d8..ab398c4b70b6 100644
--- a/arch/ppc/kernel/align.c
+++ b/arch/ppc/kernel/align.c
@@ -375,7 +375,7 @@ fix_alignment(struct pt_regs *regs)
375#ifdef CONFIG_PPC_FPU 375#ifdef CONFIG_PPC_FPU
376 preempt_disable(); 376 preempt_disable();
377 enable_kernel_fp(); 377 enable_kernel_fp();
378 cvt_fd(&data.f, &data.d, &current->thread.fpscr); 378 cvt_fd(&data.f, &data.d, &current->thread);
379 preempt_enable(); 379 preempt_enable();
380#else 380#else
381 return 0; 381 return 0;
@@ -385,7 +385,7 @@ fix_alignment(struct pt_regs *regs)
385#ifdef CONFIG_PPC_FPU 385#ifdef CONFIG_PPC_FPU
386 preempt_disable(); 386 preempt_disable();
387 enable_kernel_fp(); 387 enable_kernel_fp();
388 cvt_df(&data.d, &data.f, &current->thread.fpscr); 388 cvt_df(&data.d, &data.f, &current->thread);
389 preempt_enable(); 389 preempt_enable();
390#else 390#else
391 return 0; 391 return 0;
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 2350f3e09f95..3056ede2424d 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -968,33 +968,6 @@ _GLOBAL(_get_SP)
968 blr 968 blr
969 969
970/* 970/*
971 * These are used in the alignment trap handler when emulating
972 * single-precision loads and stores.
973 * We restore and save the fpscr so the task gets the same result
974 * and exceptions as if the cpu had performed the load or store.
975 */
976
977#ifdef CONFIG_PPC_FPU
978_GLOBAL(cvt_fd)
979 lfd 0,-4(r5) /* load up fpscr value */
980 mtfsf 0xff,0
981 lfs 0,0(r3)
982 stfd 0,0(r4)
983 mffs 0 /* save new fpscr value */
984 stfd 0,-4(r5)
985 blr
986
987_GLOBAL(cvt_df)
988 lfd 0,-4(r5) /* load up fpscr value */
989 mtfsf 0xff,0
990 lfd 0,0(r3)
991 stfs 0,0(r4)
992 mffs 0 /* save new fpscr value */
993 stfd 0,-4(r5)
994 blr
995#endif
996
997/*
998 * Create a kernel thread 971 * Create a kernel thread
999 * kernel_thread(fn, arg, flags) 972 * kernel_thread(fn, arg, flags)
1000 */ 973 */
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 6d60c40598e7..78ea10197a0b 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -542,7 +542,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
542 last_task_used_spe = NULL; 542 last_task_used_spe = NULL;
543#endif 543#endif
544 memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); 544 memset(current->thread.fpr, 0, sizeof(current->thread.fpr));
545 current->thread.fpscr = 0; 545 current->thread.fpscr.val = 0;
546#ifdef CONFIG_ALTIVEC 546#ifdef CONFIG_ALTIVEC
547 memset(current->thread.vr, 0, sizeof(current->thread.vr)); 547 memset(current->thread.vr, 0, sizeof(current->thread.vr));
548 memset(&current->thread.vscr, 0, sizeof(current->thread.vscr)); 548 memset(&current->thread.vscr, 0, sizeof(current->thread.vscr));
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 5e4bf88a1ef5..f265b81e7008 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -659,7 +659,7 @@ void program_check_exception(struct pt_regs *regs)
659 giveup_fpu(current); 659 giveup_fpu(current);
660 preempt_enable(); 660 preempt_enable();
661 661
662 fpscr = current->thread.fpscr; 662 fpscr = current->thread.fpscr.val;
663 fpscr &= fpscr << 22; /* mask summary bits with enables */ 663 fpscr &= fpscr << 22; /* mask summary bits with enables */
664 if (fpscr & FPSCR_VX) 664 if (fpscr & FPSCR_VX)
665 code = FPE_FLTINV; 665 code = FPE_FLTINV;
diff --git a/arch/ppc/math-emu/sfp-machine.h b/arch/ppc/math-emu/sfp-machine.h
index 686e06d29186..4b17d83cfcdd 100644
--- a/arch/ppc/math-emu/sfp-machine.h
+++ b/arch/ppc/math-emu/sfp-machine.h
@@ -166,7 +166,7 @@ extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);
166#include <linux/kernel.h> 166#include <linux/kernel.h>
167#include <linux/sched.h> 167#include <linux/sched.h>
168 168
169#define __FPU_FPSCR (current->thread.fpscr) 169#define __FPU_FPSCR (current->thread.fpscr.val)
170 170
171/* We only actually write to the destination register 171/* We only actually write to the destination register
172 * if exceptions signalled (if any) will not trap. 172 * if exceptions signalled (if any) will not trap.
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
index 8cc73cc1b4c4..b889277ab7de 100644
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -197,6 +197,9 @@ config BOOTX_TEXT
197config POWER4 197config POWER4
198 def_bool y 198 def_bool y
199 199
200config PPC_FPU
201 def_bool y
202
200config POWER4_ONLY 203config POWER4_ONLY
201 bool "Optimize for POWER4" 204 bool "Optimize for POWER4"
202 default n 205 default n
diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile
index 4d18bdb680f0..ba59225fd373 100644
--- a/arch/ppc64/Makefile
+++ b/arch/ppc64/Makefile
@@ -80,6 +80,7 @@ endif
80CFLAGS += $(call cc-option,-funit-at-a-time) 80CFLAGS += $(call cc-option,-funit-at-a-time)
81 81
82head-y := arch/ppc64/kernel/head.o 82head-y := arch/ppc64/kernel/head.o
83head-y += arch/powerpc/kernel/fpu.o
83 84
84libs-y += arch/ppc64/lib/ 85libs-y += arch/ppc64/lib/
85core-y += arch/ppc64/kernel/ arch/powerpc/kernel/ 86core-y += arch/ppc64/kernel/ arch/powerpc/kernel/
diff --git a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c
index 330e7ef81427..256d5b592aa1 100644
--- a/arch/ppc64/kernel/align.c
+++ b/arch/ppc64/kernel/align.c
@@ -313,7 +313,7 @@ fix_alignment(struct pt_regs *regs)
313 /* Doing stfs, have to convert to single */ 313 /* Doing stfs, have to convert to single */
314 preempt_disable(); 314 preempt_disable();
315 enable_kernel_fp(); 315 enable_kernel_fp();
316 cvt_df(&current->thread.fpr[reg], (float *)&data.v[4], &current->thread.fpscr); 316 cvt_df(&current->thread.fpr[reg], (float *)&data.v[4], &current->thread);
317 disable_kernel_fp(); 317 disable_kernel_fp();
318 preempt_enable(); 318 preempt_enable();
319 } 319 }
@@ -349,7 +349,7 @@ fix_alignment(struct pt_regs *regs)
349 /* Doing lfs, have to convert to double */ 349 /* Doing lfs, have to convert to double */
350 preempt_disable(); 350 preempt_disable();
351 enable_kernel_fp(); 351 enable_kernel_fp();
352 cvt_fd((float *)&data.v[4], &current->thread.fpr[reg], &current->thread.fpscr); 352 cvt_fd((float *)&data.v[4], &current->thread.fpr[reg], &current->thread);
353 disable_kernel_fp(); 353 disable_kernel_fp();
354 preempt_enable(); 354 preempt_enable();
355 } 355 }
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index f58af9c246cb..929f9f42cf7a 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -81,7 +81,7 @@ _stext:
81_GLOBAL(__start) 81_GLOBAL(__start)
82 /* NOP this out unconditionally */ 82 /* NOP this out unconditionally */
83BEGIN_FTR_SECTION 83BEGIN_FTR_SECTION
84 b .__start_initialization_multiplatform 84 b .__start_initialization_multiplatform
85END_FTR_SECTION(0, 1) 85END_FTR_SECTION(0, 1)
86#endif /* CONFIG_PPC_MULTIPLATFORM */ 86#endif /* CONFIG_PPC_MULTIPLATFORM */
87 87
@@ -747,6 +747,7 @@ bad_stack:
747 * any task or sent any task a signal, you should use 747 * any task or sent any task a signal, you should use
748 * ret_from_except or ret_from_except_lite instead of this. 748 * ret_from_except or ret_from_except_lite instead of this.
749 */ 749 */
750 .globl fast_exception_return
750fast_exception_return: 751fast_exception_return:
751 ld r12,_MSR(r1) 752 ld r12,_MSR(r1)
752 ld r11,_NIP(r1) 753 ld r11,_NIP(r1)
@@ -858,62 +859,6 @@ fp_unavailable_common:
858 bl .kernel_fp_unavailable_exception 859 bl .kernel_fp_unavailable_exception
859 BUG_OPCODE 860 BUG_OPCODE
860 861
861/*
862 * load_up_fpu(unused, unused, tsk)
863 * Disable FP for the task which had the FPU previously,
864 * and save its floating-point registers in its thread_struct.
865 * Enables the FPU for use in the kernel on return.
866 * On SMP we know the fpu is free, since we give it up every
867 * switch (ie, no lazy save of the FP registers).
868 * On entry: r13 == 'current' && last_task_used_math != 'current'
869 */
870_STATIC(load_up_fpu)
871 mfmsr r5 /* grab the current MSR */
872 ori r5,r5,MSR_FP
873 mtmsrd r5 /* enable use of fpu now */
874 isync
875/*
876 * For SMP, we don't do lazy FPU switching because it just gets too
877 * horrendously complex, especially when a task switches from one CPU
878 * to another. Instead we call giveup_fpu in switch_to.
879 *
880 */
881#ifndef CONFIG_SMP
882 ld r3,last_task_used_math@got(r2)
883 ld r4,0(r3)
884 cmpdi 0,r4,0
885 beq 1f
886 /* Save FP state to last_task_used_math's THREAD struct */
887 addi r4,r4,THREAD
888 SAVE_32FPRS(0, r4)
889 mffs fr0
890 stfd fr0,THREAD_FPSCR(r4)
891 /* Disable FP for last_task_used_math */
892 ld r5,PT_REGS(r4)
893 ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
894 li r6,MSR_FP|MSR_FE0|MSR_FE1
895 andc r4,r4,r6
896 std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
8971:
898#endif /* CONFIG_SMP */
899 /* enable use of FP after return */
900 ld r4,PACACURRENT(r13)
901 addi r5,r4,THREAD /* Get THREAD */
902 ld r4,THREAD_FPEXC_MODE(r5)
903 ori r12,r12,MSR_FP
904 or r12,r12,r4
905 std r12,_MSR(r1)
906 lfd fr0,THREAD_FPSCR(r5)
907 mtfsf 0xff,fr0
908 REST_32FPRS(0, r5)
909#ifndef CONFIG_SMP
910 /* Update last_task_used_math to 'current' */
911 subi r4,r5,THREAD /* Back to 'current' */
912 std r4,0(r3)
913#endif /* CONFIG_SMP */
914 /* restore registers and return */
915 b fast_exception_return
916
917 .align 7 862 .align 7
918 .globl altivec_unavailable_common 863 .globl altivec_unavailable_common
919altivec_unavailable_common: 864altivec_unavailable_common:
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index a33448c2bd91..9cae3d5c40e6 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -451,25 +451,6 @@ _GLOBAL(_outsl_ns)
451 sync 451 sync
452 blr 452 blr
453 453
454
455_GLOBAL(cvt_fd)
456 lfd 0,0(r5) /* load up fpscr value */
457 mtfsf 0xff,0
458 lfs 0,0(r3)
459 stfd 0,0(r4)
460 mffs 0 /* save new fpscr value */
461 stfd 0,0(r5)
462 blr
463
464_GLOBAL(cvt_df)
465 lfd 0,0(r5) /* load up fpscr value */
466 mtfsf 0xff,0
467 lfd 0,0(r3)
468 stfs 0,0(r4)
469 mffs 0 /* save new fpscr value */
470 stfd 0,0(r5)
471 blr
472
473/* 454/*
474 * identify_cpu and calls setup_cpu 455 * identify_cpu and calls setup_cpu
475 * In: r3 = base of the cpu_specs array 456 * In: r3 = base of the cpu_specs array
@@ -655,38 +636,6 @@ _GLOBAL(disable_kernel_fp)
655 isync 636 isync
656 blr 637 blr
657 638
658/*
659 * giveup_fpu(tsk)
660 * Disable FP for the task given as the argument,
661 * and save the floating-point registers in its thread_struct.
662 * Enables the FPU for use in the kernel on return.
663 */
664_GLOBAL(giveup_fpu)
665 mfmsr r5
666 ori r5,r5,MSR_FP
667 mtmsrd r5 /* enable use of fpu now */
668 isync
669 cmpdi 0,r3,0
670 beqlr- /* if no previous owner, done */
671 addi r3,r3,THREAD /* want THREAD of task */
672 ld r5,PT_REGS(r3)
673 cmpdi 0,r5,0
674 SAVE_32FPRS(0, r3)
675 mffs fr0
676 stfd fr0,THREAD_FPSCR(r3)
677 beq 1f
678 ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
679 li r3,MSR_FP|MSR_FE0|MSR_FE1
680 andc r4,r4,r3 /* disable FP for previous task */
681 std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
6821:
683#ifndef CONFIG_SMP
684 li r5,0
685 ld r4,last_task_used_math@got(r2)
686 std r5,0(r4)
687#endif /* CONFIG_SMP */
688 blr
689
690#ifdef CONFIG_ALTIVEC 639#ifdef CONFIG_ALTIVEC
691 640
692#if 0 /* this has no callers for now */ 641#if 0 /* this has no callers for now */
diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
index 347112cca3c0..ec9d0984b6a0 100644
--- a/arch/ppc64/kernel/signal.c
+++ b/arch/ppc64/kernel/signal.c
@@ -133,7 +133,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
133 flush_fp_to_thread(current); 133 flush_fp_to_thread(current);
134 134
135 /* Make sure signal doesn't get spurrious FP exceptions */ 135 /* Make sure signal doesn't get spurrious FP exceptions */
136 current->thread.fpscr = 0; 136 current->thread.fpscr.val = 0;
137 137
138#ifdef CONFIG_ALTIVEC 138#ifdef CONFIG_ALTIVEC
139 err |= __put_user(v_regs, &sc->v_regs); 139 err |= __put_user(v_regs, &sc->v_regs);
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index 9592f533e058..eee954a001fd 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -162,10 +162,11 @@ struct thread_struct {
162 unsigned long dbcr1; 162 unsigned long dbcr1;
163#endif 163#endif
164 double fpr[32]; /* Complete floating point set */ 164 double fpr[32]; /* Complete floating point set */
165#ifdef CONFIG_PPC32 165 struct { /* fpr ... fpscr must be contiguous */
166 unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */ 166
167#endif 167 unsigned int pad;
168 unsigned long fpscr; /* Floating point status */ 168 unsigned int val; /* Floating point status */
169 } fpscr;
169 int fpexc_mode; /* floating-point exception mode */ 170 int fpexc_mode; /* floating-point exception mode */
170#ifdef CONFIG_PPC64 171#ifdef CONFIG_PPC64
171 unsigned long start_tb; /* Start purr when proc switched in */ 172 unsigned long start_tb; /* Start purr when proc switched in */
@@ -207,7 +208,7 @@ struct thread_struct {
207 .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \ 208 .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
208 .fs = KERNEL_DS, \ 209 .fs = KERNEL_DS, \
209 .fpr = {0}, \ 210 .fpr = {0}, \
210 .fpscr = 0, \ 211 .fpscr = { .val = 0, }, \
211 .fpexc_mode = MSR_FE0|MSR_FE1, \ 212 .fpexc_mode = MSR_FE0|MSR_FE1, \
212} 213}
213#endif 214#endif
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index d60c8c928922..e926e43c4ae6 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -132,8 +132,8 @@ extern int emulate_altivec(struct pt_regs *);
132extern void giveup_spe(struct task_struct *); 132extern void giveup_spe(struct task_struct *);
133extern void load_up_spe(struct task_struct *); 133extern void load_up_spe(struct task_struct *);
134extern int fix_alignment(struct pt_regs *); 134extern int fix_alignment(struct pt_regs *);
135extern void cvt_fd(float *from, double *to, unsigned long *fpscr); 135extern void cvt_fd(float *from, double *to, struct thread_struct *thread);
136extern void cvt_df(double *from, float *to, unsigned long *fpscr); 136extern void cvt_df(double *from, float *to, struct thread_struct *thread);
137 137
138#ifdef CONFIG_ALTIVEC 138#ifdef CONFIG_ALTIVEC
139extern void flush_altivec_to_thread(struct task_struct *); 139extern void flush_altivec_to_thread(struct task_struct *);
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index 1f310783757e..eb30c09516ae 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -82,8 +82,8 @@ extern int emulate_altivec(struct pt_regs *);
82extern void giveup_spe(struct task_struct *); 82extern void giveup_spe(struct task_struct *);
83extern void load_up_spe(struct task_struct *); 83extern void load_up_spe(struct task_struct *);
84extern int fix_alignment(struct pt_regs *); 84extern int fix_alignment(struct pt_regs *);
85extern void cvt_fd(float *from, double *to, unsigned long *fpscr); 85extern void cvt_fd(float *from, double *to, struct thread_struct *thread);
86extern void cvt_df(double *from, float *to, unsigned long *fpscr); 86extern void cvt_df(double *from, float *to, struct thread_struct *thread);
87 87
88#ifdef CONFIG_ALTIVEC 88#ifdef CONFIG_ALTIVEC
89extern void flush_altivec_to_thread(struct task_struct *); 89extern void flush_altivec_to_thread(struct task_struct *);
diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h
index 2e17ef7dbeb4..fd7c1f890c45 100644
--- a/include/asm-ppc64/system.h
+++ b/include/asm-ppc64/system.h
@@ -120,8 +120,8 @@ extern void giveup_altivec(struct task_struct *);
120extern void disable_kernel_altivec(void); 120extern void disable_kernel_altivec(void);
121extern void enable_kernel_altivec(void); 121extern void enable_kernel_altivec(void);
122extern int emulate_altivec(struct pt_regs *); 122extern int emulate_altivec(struct pt_regs *);
123extern void cvt_fd(float *from, double *to, unsigned long *fpscr); 123extern void cvt_fd(float *from, double *to, struct thread_struct *thread);
124extern void cvt_df(double *from, float *to, unsigned long *fpscr); 124extern void cvt_df(double *from, float *to, struct thread_struct *thread);
125 125
126#ifdef CONFIG_ALTIVEC 126#ifdef CONFIG_ALTIVEC
127extern void flush_altivec_to_thread(struct task_struct *); 127extern void flush_altivec_to_thread(struct task_struct *);