sh: Fix occasional FPU register corruption under preempt.

Presently with preempt enabled there's the possibility to be preempted
after the TIF_USEDFPU test and the register save, leading to bogus
state post-__switch_to(). Use an explicit preempt_disable()/enable()
pair around unlazy_fpu()/clear_fpu() to avoid this. Follows the x86
change.

Reported-by: Takuo Koguchi <takuo.koguchi.sw@hitachi.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

+25 -14
+1
arch/sh/kernel/cpu/sh2a/fpu.c
··· 13 #include <linux/signal.h> 14 #include <asm/processor.h> 15 #include <asm/io.h> 16 17 /* The PR (precision) bit in the FP Status Register must be clear when 18 * an frchg instruction is executed, otherwise the instruction is undefined.
··· 13 #include <linux/signal.h> 14 #include <asm/processor.h> 15 #include <asm/io.h> 16 + #include <asm/fpu.h> 17 18 /* The PR (precision) bit in the FP Status Register must be clear when 19 * an frchg instruction is executed, otherwise the instruction is undefined.
+1
arch/sh/kernel/cpu/sh4/fpu.c
··· 16 #include <asm/cpu/fpu.h> 17 #include <asm/processor.h> 18 #include <asm/system.h> 19 20 /* The PR (precision) bit in the FP Status Register must be clear when 21 * an frchg instruction is executed, otherwise the instruction is undefined.
··· 16 #include <asm/cpu/fpu.h> 17 #include <asm/processor.h> 18 #include <asm/system.h> 19 + #include <asm/fpu.h> 20 21 /* The PR (precision) bit in the FP Status Register must be clear when 22 * an frchg instruction is executed, otherwise the instruction is undefined.
+1
arch/sh/kernel/cpu/sh5/fpu.c
··· 17 #include <asm/processor.h> 18 #include <asm/user.h> 19 #include <asm/io.h> 20 21 /* 22 * Initially load the FPU with signalling NANS. This bit pattern
··· 17 #include <asm/processor.h> 18 #include <asm/user.h> 19 #include <asm/io.h> 20 + #include <asm/fpu.h> 21 22 /* 23 * Initially load the FPU with signalling NANS. This bit pattern
+1
arch/sh/kernel/dump_task.c
··· 1 #include <linux/elfcore.h> 2 #include <linux/sched.h> 3 4 /* 5 * Capture the user space registers if the task is not running (in user space)
··· 1 #include <linux/elfcore.h> 2 #include <linux/sched.h> 3 + #include <asm/fpu.h> 4 5 /* 6 * Capture the user space registers if the task is not running (in user space)
+1
arch/sh/kernel/process_32.c
··· 25 #include <asm/pgalloc.h> 26 #include <asm/system.h> 27 #include <asm/ubc.h> 28 29 static int hlt_counter; 30 int ubc_usercnt = 0;
··· 25 #include <asm/pgalloc.h> 26 #include <asm/system.h> 27 #include <asm/ubc.h> 28 + #include <asm/fpu.h> 29 30 static int hlt_counter; 31 int ubc_usercnt = 0;
+1
arch/sh/kernel/signal_32.c
··· 29 #include <asm/uaccess.h> 30 #include <asm/pgtable.h> 31 #include <asm/cacheflush.h> 32 33 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 34
··· 29 #include <asm/uaccess.h> 30 #include <asm/pgtable.h> 31 #include <asm/cacheflush.h> 32 + #include <asm/fpu.h> 33 34 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 35
+17 -13
include/asm-sh/fpu.h
··· 1 #ifndef __ASM_SH_FPU_H 2 #define __ASM_SH_FPU_H 3 4 - #define SR_FD 0x00008000 5 - 6 #ifndef __ASSEMBLY__ 7 #include <asm/ptrace.h> 8 9 #ifdef CONFIG_SH_FPU ··· 27 28 extern int do_fpu_inst(unsigned short, struct pt_regs *); 29 30 - #define unlazy_fpu(tsk, regs) do { \ 31 - if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { \ 32 - save_fpu(tsk, regs); \ 33 - } \ 34 - } while (0) 35 36 - #define clear_fpu(tsk, regs) do { \ 37 - if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { \ 38 - clear_tsk_thread_flag(tsk, TIF_USEDFPU); \ 39 - release_fpu(regs); \ 40 - } \ 41 - } while (0) 42 43 #endif /* __ASSEMBLY__ */ 44
··· 1 #ifndef __ASM_SH_FPU_H 2 #define __ASM_SH_FPU_H 3 4 #ifndef __ASSEMBLY__ 5 + #include <linux/preempt.h> 6 #include <asm/ptrace.h> 7 8 #ifdef CONFIG_SH_FPU ··· 28 29 extern int do_fpu_inst(unsigned short, struct pt_regs *); 30 31 + static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) 32 + { 33 + preempt_disable(); 34 + if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) 35 + save_fpu(tsk, regs); 36 + preempt_enable(); 37 + } 38 39 + static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs) 40 + { 41 + preempt_disable(); 42 + if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { 43 + clear_tsk_thread_flag(tsk, TIF_USEDFPU); 44 + release_fpu(regs); 45 + } 46 + preempt_enable(); 47 + } 48 49 #endif /* __ASSEMBLY__ */ 50
-1
include/asm-sh/processor.h
··· 2 #define __ASM_SH_PROCESSOR_H 3 4 #include <asm/cpu-features.h> 5 - #include <asm/fpu.h> 6 7 #ifndef __ASSEMBLY__ 8 /*
··· 2 #define __ASM_SH_PROCESSOR_H 3 4 #include <asm/cpu-features.h> 5 6 #ifndef __ASSEMBLY__ 7 /*
+1
include/asm-sh/processor_32.h
··· 70 */ 71 #define SR_DSP 0x00001000 72 #define SR_IMASK 0x000000f0 73 74 /* 75 * FPU structure and data
··· 70 */ 71 #define SR_DSP 0x00001000 72 #define SR_IMASK 0x000000f0 73 + #define SR_FD 0x00008000 74 75 /* 76 * FPU structure and data
+1
include/asm-sh/processor_64.h
··· 112 #endif 113 114 #define SR_IMASK 0x000000f0 115 #define SR_SSTEP 0x08000000 116 117 #ifndef __ASSEMBLY__
··· 112 #endif 113 114 #define SR_IMASK 0x000000f0 115 + #define SR_FD 0x00008000 116 #define SR_SSTEP 0x08000000 117 118 #ifndef __ASSEMBLY__