i387: move AMD K7/K8 fpu fxsave/fxrstor workaround from save to restore
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / x86 / include / asm / i387.h
index 1e12c2d..01b115d 100644 (file)
@@ -30,7 +30,6 @@ extern void fpu_init(void);
 extern void mxcsr_feature_mask_init(void);
 extern int init_fpu(struct task_struct *child);
 extern void math_state_restore(void);
-extern void __math_state_restore(void);
 extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
 
 extern user_regset_active_fn fpregs_active, xfpregs_active;
@@ -212,15 +211,6 @@ static inline void fpu_fxsave(struct fpu *fpu)
 
 #endif /* CONFIG_X86_64 */
 
-/* We need a safe address that is cheap to find and that is already
-   in L1 during context switch. The best choices are unfortunately
-   different for UP and SMP */
-#ifdef CONFIG_SMP
-#define safe_address (__per_cpu_offset[0])
-#else
-#define safe_address (__get_cpu_var(kernel_cpustat).cpustat[CPUTIME_USER])
-#endif
-
 /*
  * These must be called with preempt disabled
  */
@@ -244,16 +234,6 @@ static inline void fpu_save_init(struct fpu *fpu)
 
        if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES))
                asm volatile("fnclex");
-
-       /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
-          is pending.  Clear the x87 state here by setting it to fixed
-          values. safe_address is a random variable that should be in L1 */
-       alternative_input(
-               ASM_NOP8 ASM_NOP2,
-               "emms\n\t"              /* clear stack tags */
-               "fildl %P[addr]",       /* set F?P to defined value */
-               X86_FEATURE_FXSAVE_LEAK,
-               [addr] "m" (safe_address));
 }
 
 static inline void __save_init_fpu(struct task_struct *tsk)
@@ -280,6 +260,47 @@ static inline int restore_fpu_checking(struct task_struct *tsk)
 }
 
 /*
+ * Software FPU state helpers. Careful: these need to
+ * be preemption protection *and* they need to be
+ * properly paired with the CR0.TS changes!
+ */
+static inline int __thread_has_fpu(struct thread_info *ti)
+{
+       return ti->status & TS_USEDFPU;
+}
+
+/* Must be paired with an 'stts' after! */
+static inline void __thread_clear_has_fpu(struct thread_info *ti)
+{
+       ti->status &= ~TS_USEDFPU;
+}
+
+/* Must be paired with a 'clts' before! */
+static inline void __thread_set_has_fpu(struct thread_info *ti)
+{
+       ti->status |= TS_USEDFPU;
+}
+
+/*
+ * Encapsulate the CR0.TS handling together with the
+ * software flag.
+ *
+ * These generally need preemption protection to work,
+ * do try to avoid using these on their own.
+ */
+static inline void __thread_fpu_end(struct thread_info *ti)
+{
+       __thread_clear_has_fpu(ti);
+       stts();
+}
+
+static inline void __thread_fpu_begin(struct thread_info *ti)
+{
+       clts();
+       __thread_set_has_fpu(ti);
+}
+
+/*
  * Signal frame handlers...
  */
 extern int save_i387_xstate(void __user *buf);
@@ -287,23 +308,21 @@ extern int restore_i387_xstate(void __user *buf);
 
 static inline void __unlazy_fpu(struct task_struct *tsk)
 {
-       if (task_thread_info(tsk)->status & TS_USEDFPU) {
+       if (__thread_has_fpu(task_thread_info(tsk))) {
                __save_init_fpu(tsk);
-               task_thread_info(tsk)->status &= ~TS_USEDFPU;
-               stts();
+               __thread_fpu_end(task_thread_info(tsk));
        } else
                tsk->fpu_counter = 0;
 }
 
 static inline void __clear_fpu(struct task_struct *tsk)
 {
-       if (task_thread_info(tsk)->status & TS_USEDFPU) {
+       if (__thread_has_fpu(task_thread_info(tsk))) {
                /* Ignore delayed exceptions from user space */
                asm volatile("1: fwait\n"
                             "2:\n"
                             _ASM_EXTABLE(1b, 2b));
-               task_thread_info(tsk)->status &= ~TS_USEDFPU;
-               stts();
+               __thread_fpu_end(task_thread_info(tsk));
        }
 }
 
@@ -311,14 +330,14 @@ static inline void __clear_fpu(struct task_struct *tsk)
  * Were we in an interrupt that interrupted kernel mode?
  *
  * We can do a kernel_fpu_begin/end() pair *ONLY* if that
- * pair does nothing at all: TS_USEDFPU must be clear (so
+ * pair does nothing at all: the thread must not have fpu (so
  * that we don't try to save the FPU state), and TS must
  * be set (so that the clts/stts pair does nothing that is
  * visible in the interrupted kernel thread).
  */
 static inline bool interrupted_kernel_fpu_idle(void)
 {
-       return !(current_thread_info()->status & TS_USEDFPU) &&
+       return !__thread_has_fpu(current_thread_info()) &&
                (read_cr0() & X86_CR0_TS);
 }
 
@@ -356,9 +375,9 @@ static inline void kernel_fpu_begin(void)
 
        WARN_ON_ONCE(!irq_fpu_usable());
        preempt_disable();
-       if (me->status & TS_USEDFPU) {
+       if (__thread_has_fpu(me)) {
                __save_init_fpu(me->task);
-               me->status &= ~TS_USEDFPU;
+               __thread_clear_has_fpu(me);
                /* We do 'stts()' in kernel_fpu_end() */
        } else
                clts();
@@ -422,24 +441,21 @@ static inline void irq_ts_restore(int TS_state)
  */
 static inline int user_has_fpu(void)
 {
-       return current_thread_info()->status & TS_USEDFPU;
+       return __thread_has_fpu(current_thread_info());
 }
 
 static inline void user_fpu_end(void)
 {
        preempt_disable();
-       current_thread_info()->status &= ~TS_USEDFPU;
-       stts();
+       __thread_fpu_end(current_thread_info());
        preempt_enable();
 }
 
 static inline void user_fpu_begin(void)
 {
        preempt_disable();
-       if (!user_has_fpu()) {
-               clts();
-               current_thread_info()->status |= TS_USEDFPU;
-       }
+       if (!user_has_fpu())
+               __thread_fpu_begin(current_thread_info());
        preempt_enable();
 }
 
@@ -448,11 +464,10 @@ static inline void user_fpu_begin(void)
  */
 static inline void save_init_fpu(struct task_struct *tsk)
 {
-       WARN_ON_ONCE(!(task_thread_info(tsk)->status & TS_USEDFPU));
+       WARN_ON_ONCE(!__thread_has_fpu(task_thread_info(tsk)));
        preempt_disable();
        __save_init_fpu(tsk);
-       task_thread_info(tsk)->status &= ~TS_USEDFPU;
-       stts();
+       __thread_fpu_end(task_thread_info(tsk));
        preempt_enable();
 }