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