xref: /openbmc/linux/arch/sh/kernel/cpu/fpu.c (revision a09d2831)
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 		/*
60 		 * does a slab alloc which can sleep
61 		 */
62 		if (init_fpu(tsk)) {
63 			/*
64 			 * ran out of memory!
65 			 */
66 			do_group_exit(SIGKILL);
67 			return;
68 		}
69 	}
70 
71 	grab_fpu(regs);
72 
73 	__fpu_state_restore();
74 }
75 
76 BUILD_TRAP_HANDLER(fpu_state_restore)
77 {
78 	TRAP_HANDLER_DECL;
79 
80 	fpu_state_restore(regs);
81 }
82 #endif /* CONFIG_SH_FPU */
83