Merge tag 'nfs-for-4.11-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
[linux-2.6-block.git] / arch / sh / kernel / cpu / fpu.c
1 #include <linux/sched/signal.h>
2 #include <linux/sched/task.h>
3 #include <linux/sched/task_stack.h>
4 #include <linux/slab.h>
5 #include <asm/processor.h>
6 #include <asm/fpu.h>
7 #include <asm/traps.h>
8 #include <asm/ptrace.h>
9
10 int init_fpu(struct task_struct *tsk)
11 {
12         if (tsk_used_math(tsk)) {
13                 if ((boot_cpu_data.flags & CPU_HAS_FPU) && tsk == current)
14                         unlazy_fpu(tsk, task_pt_regs(tsk));
15                 return 0;
16         }
17
18         /*
19          * Memory allocation at the first usage of the FPU and other state.
20          */
21         if (!tsk->thread.xstate) {
22                 tsk->thread.xstate = kmem_cache_alloc(task_xstate_cachep,
23                                                       GFP_KERNEL);
24                 if (!tsk->thread.xstate)
25                         return -ENOMEM;
26         }
27
28         if (boot_cpu_data.flags & CPU_HAS_FPU) {
29                 struct sh_fpu_hard_struct *fp = &tsk->thread.xstate->hardfpu;
30                 memset(fp, 0, xstate_size);
31                 fp->fpscr = FPSCR_INIT;
32         } else {
33                 struct sh_fpu_soft_struct *fp = &tsk->thread.xstate->softfpu;
34                 memset(fp, 0, xstate_size);
35                 fp->fpscr = FPSCR_INIT;
36         }
37
38         set_stopped_child_used_math(tsk);
39         return 0;
40 }
41
42 #ifdef CONFIG_SH_FPU
43 void __fpu_state_restore(void)
44 {
45         struct task_struct *tsk = current;
46
47         restore_fpu(tsk);
48
49         task_thread_info(tsk)->status |= TS_USEDFPU;
50         tsk->thread.fpu_counter++;
51 }
52
53 void fpu_state_restore(struct pt_regs *regs)
54 {
55         struct task_struct *tsk = current;
56
57         if (unlikely(!user_mode(regs))) {
58                 printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
59                 BUG();
60                 return;
61         }
62
63         if (!tsk_used_math(tsk)) {
64                 local_irq_enable();
65                 /*
66                  * does a slab alloc which can sleep
67                  */
68                 if (init_fpu(tsk)) {
69                         /*
70                          * ran out of memory!
71                          */
72                         do_group_exit(SIGKILL);
73                         return;
74                 }
75                 local_irq_disable();
76         }
77
78         grab_fpu(regs);
79
80         __fpu_state_restore();
81 }
82
83 BUILD_TRAP_HANDLER(fpu_state_restore)
84 {
85         TRAP_HANDLER_DECL;
86
87         fpu_state_restore(regs);
88 }
89 #endif /* CONFIG_SH_FPU */