1 /*
2  * Copyright (C) 2002 MontaVista Software Inc.
3  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
4  *
5  * This program is free software; you can redistribute  it and/or modify it
6  * under  the terms of  the GNU General  Public License as published by the
7  * Free Software Foundation;  either version 2 of the  License, or (at your
8  * option) any later version.
9  *
10  */
11 #ifndef _ASM_FPU_H
12 #define _ASM_FPU_H
13 
14 #include <linux/config.h>
15 #include <linux/sched.h>
16 
17 #include <asm/mipsregs.h>
18 #include <asm/cpu.h>
19 #include <asm/bitops.h>
20 #include <asm/processor.h>
21 #include <asm/current.h>
22 
23 struct sigcontext;
24 
25 extern asmlinkage int (*save_fp_context)(struct sigcontext *sc);
26 extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
27 
28 extern void fpu_emulator_init_fpu(void);
29 extern void _init_fpu(void);
30 extern void _save_fp(struct task_struct *);
31 extern void _restore_fp(struct task_struct *);
32 
33 #if defined(CONFIG_CPU_SB1)
34 #define __enable_fpu_hazard()						\
35 do {									\
36 	asm(".set push		\n\t"					\
37 	    ".set mips64	\n\t"					\
38 	    ".set noreorder	\n\t"					\
39 	    "ssnop		\n\t"					\
40 	    "bnezl $0, .+4	\n\t"					\
41 	    "ssnop		\n\t"					\
42 	    ".set pop");						\
43 } while (0)
44 #else
45 #define __enable_fpu_hazard()                                           \
46 do {                                                                    \
47         asm("nop;nop;nop;nop");         /* max. hazard */               \
48 } while (0)
49 #endif
50 
51 #define __enable_fpu()							\
52 do {									\
53         set_c0_status(ST0_CU1);						\
54         __enable_fpu_hazard();						\
55 } while (0)
56 
57 #define __disable_fpu()							\
58 do {									\
59 	clear_c0_status(ST0_CU1);					\
60 	/* We don't care about the c0 hazard here  */			\
61 } while (0)
62 
63 #define enable_fpu()							\
64 do {									\
65 	if (cpu_has_fpu)						\
66 		__enable_fpu();						\
67 } while (0)
68 
69 #define disable_fpu()							\
70 do {									\
71 	if (cpu_has_fpu)						\
72 		__disable_fpu();					\
73 } while (0)
74 
75 
76 #define clear_fpu_owner() do { current->flags &= ~PF_USEDFPU; } while(0)
77 
is_fpu_owner(void)78 static inline int is_fpu_owner(void)
79 {
80 	return cpu_has_fpu && ((current->flags & PF_USEDFPU) != 0);
81 }
82 
own_fpu(void)83 static inline void own_fpu(void)
84 {
85 	if (cpu_has_fpu) {
86 		__enable_fpu();
87 		KSTK_STATUS(current) |= ST0_CU1;
88 		current->flags |= PF_USEDFPU;
89 	}
90 }
91 
lose_fpu(void)92 static inline void lose_fpu(void)
93 {
94 	if (cpu_has_fpu) {
95 		KSTK_STATUS(current) &= ~ST0_CU1;
96 		current->flags &= ~PF_USEDFPU;
97 		__disable_fpu();
98 	}
99 }
100 
init_fpu(void)101 static inline void init_fpu(void)
102 {
103 	if (cpu_has_fpu) {
104 		_init_fpu();
105 	} else {
106 		fpu_emulator_init_fpu();
107 	}
108 }
109 
save_fp(struct task_struct * tsk)110 static inline void save_fp(struct task_struct *tsk)
111 {
112 	if (cpu_has_fpu)
113 		_save_fp(tsk);
114 }
115 
restore_fp(struct task_struct * tsk)116 static inline void restore_fp(struct task_struct *tsk)
117 {
118 	if (cpu_has_fpu)
119 		_restore_fp(tsk);
120 }
121 
get_fpu_regs(struct task_struct * tsk)122 static inline unsigned long long *get_fpu_regs(struct task_struct *tsk)
123 {
124 	if (cpu_has_fpu) {
125 		if ((tsk == current) && is_fpu_owner())
126 			_save_fp(current);
127 		return (unsigned long long *)&tsk->thread.fpu.hard.fp_regs[0];
128 	} else {
129 		return (unsigned long long *)tsk->thread.fpu.soft.regs;
130 	}
131 }
132 
133 #endif /* _ASM_FPU_H */
134