Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / arch / powerpc / kvm / fpu.S
1 /*
2  *  FPU helper code to use FPU operations from inside the kernel
3  *
4  *    Copyright (C) 2010 Alexander Graf (agraf@suse.de)
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation; either version
9  *  2 of the License, or (at your option) any later version.
10  *
11  */
12
13 #include <asm/reg.h>
14 #include <asm/page.h>
15 #include <asm/mmu.h>
16 #include <asm/pgtable.h>
17 #include <asm/cputable.h>
18 #include <asm/cache.h>
19 #include <asm/thread_info.h>
20 #include <asm/ppc_asm.h>
21 #include <asm/asm-offsets.h>
22
23 /* Instructions operating on single parameters */
24
25 /*
26  * Single operation with one input operand
27  *
28  * R3 = (double*)&fpscr
29  * R4 = (short*)&result
30  * R5 = (short*)&param1
31  */
32 #define FPS_ONE_IN(name)                                        \
33 _GLOBAL(fps_ ## name);                                                  \
34         lfd     0,0(r3);                /* load up fpscr value */       \
35         MTFSF_L(0);                                                     \
36         lfs     0,0(r5);                                                \
37                                                                         \
38         name    0,0;                                                    \
39                                                                         \
40         stfs    0,0(r4);                                                \
41         mffs    0;                                                      \
42         stfd    0,0(r3);        /* save new fpscr value */      \
43         blr
44
45 /*
46  * Single operation with two input operands
47  *
48  * R3 = (double*)&fpscr
49  * R4 = (short*)&result
50  * R5 = (short*)&param1
51  * R6 = (short*)&param2
52  */
53 #define FPS_TWO_IN(name)                                        \
54 _GLOBAL(fps_ ## name);                                                  \
55         lfd     0,0(r3);                /* load up fpscr value */       \
56         MTFSF_L(0);                                                     \
57         lfs     0,0(r5);                                                \
58         lfs     1,0(r6);                                                \
59                                                                         \
60         name    0,0,1;                                                  \
61                                                                         \
62         stfs    0,0(r4);                                                \
63         mffs    0;                                                      \
64         stfd    0,0(r3);                /* save new fpscr value */      \
65         blr
66
67 /*
68  * Single operation with three input operands
69  *
70  * R3 = (double*)&fpscr
71  * R4 = (short*)&result
72  * R5 = (short*)&param1
73  * R6 = (short*)&param2
74  * R7 = (short*)&param3
75  */
76 #define FPS_THREE_IN(name)                                      \
77 _GLOBAL(fps_ ## name);                                                  \
78         lfd     0,0(r3);                /* load up fpscr value */       \
79         MTFSF_L(0);                                                     \
80         lfs     0,0(r5);                                                \
81         lfs     1,0(r6);                                                \
82         lfs     2,0(r7);                                                \
83                                                                         \
84         name    0,0,1,2;                                                \
85                                                                         \
86         stfs    0,0(r4);                                                \
87         mffs    0;                                                      \
88         stfd    0,0(r3);                /* save new fpscr value */      \
89         blr
90
91 FPS_ONE_IN(fres)
92 FPS_ONE_IN(frsqrte)
93 FPS_ONE_IN(fsqrts)
94 FPS_TWO_IN(fadds)
95 FPS_TWO_IN(fdivs)
96 FPS_TWO_IN(fmuls)
97 FPS_TWO_IN(fsubs)
98 FPS_THREE_IN(fmadds)
99 FPS_THREE_IN(fmsubs)
100 FPS_THREE_IN(fnmadds)
101 FPS_THREE_IN(fnmsubs)
102 FPS_THREE_IN(fsel)
103
104
105 /* Instructions operating on double parameters */
106
107 /*
108  * Beginning of double instruction processing
109  *
110  * R3 = (double*)&fpscr
111  * R4 = (u32*)&cr
112  * R5 = (double*)&result
113  * R6 = (double*)&param1
114  * R7 = (double*)&param2 [load_two]
115  * R8 = (double*)&param3 [load_three]
116  * LR = instruction call function
117  */
118 fpd_load_three:
119         lfd     2,0(r8)                 /* load param3 */
120 fpd_load_two:
121         lfd     1,0(r7)                 /* load param2 */
122 fpd_load_one:
123         lfd     0,0(r6)                 /* load param1 */
124 fpd_load_none:
125         lfd     3,0(r3)                 /* load up fpscr value */
126         MTFSF_L(3)
127         lwz     r6, 0(r4)               /* load cr */
128         mtcr    r6
129         blr
130
131 /*
132  * End of double instruction processing
133  *
134  * R3 = (double*)&fpscr
135  * R4 = (u32*)&cr
136  * R5 = (double*)&result
137  * LR = caller of instruction call function
138  */
139 fpd_return:
140         mfcr    r6
141         stfd    0,0(r5)                 /* save result */
142         mffs    0
143         stfd    0,0(r3)                 /* save new fpscr value */
144         stw     r6,0(r4)                /* save new cr value */
145         blr
146
147 /*
148  * Double operation with no input operand
149  *
150  * R3 = (double*)&fpscr
151  * R4 = (u32*)&cr
152  * R5 = (double*)&result
153  */
154 #define FPD_NONE_IN(name)                                               \
155 _GLOBAL(fpd_ ## name);                                                  \
156         mflr    r12;                                                    \
157         bl      fpd_load_none;                                          \
158         mtlr    r12;                                                    \
159                                                                         \
160         name.   0;                      /* call instruction */          \
161         b       fpd_return
162
163 /*
164  * Double operation with one input operand
165  *
166  * R3 = (double*)&fpscr
167  * R4 = (u32*)&cr
168  * R5 = (double*)&result
169  * R6 = (double*)&param1
170  */
171 #define FPD_ONE_IN(name)                                                \
172 _GLOBAL(fpd_ ## name);                                                  \
173         mflr    r12;                                                    \
174         bl      fpd_load_one;                                           \
175         mtlr    r12;                                                    \
176                                                                         \
177         name.   0,0;                    /* call instruction */          \
178         b       fpd_return
179
180 /*
181  * Double operation with two input operands
182  *
183  * R3 = (double*)&fpscr
184  * R4 = (u32*)&cr
185  * R5 = (double*)&result
186  * R6 = (double*)&param1
187  * R7 = (double*)&param2
188  * R8 = (double*)&param3
189  */
190 #define FPD_TWO_IN(name)                                                \
191 _GLOBAL(fpd_ ## name);                                                  \
192         mflr    r12;                                                    \
193         bl      fpd_load_two;                                           \
194         mtlr    r12;                                                    \
195                                                                         \
196         name.   0,0,1;                  /* call instruction */          \
197         b       fpd_return
198
199 /*
200  * CR Double operation with two input operands
201  *
202  * R3 = (double*)&fpscr
203  * R4 = (u32*)&cr
204  * R5 = (double*)&param1
205  * R6 = (double*)&param2
206  * R7 = (double*)&param3
207  */
208 #define FPD_TWO_IN_CR(name)                                             \
209 _GLOBAL(fpd_ ## name);                                                  \
210         lfd     1,0(r6);                /* load param2 */               \
211         lfd     0,0(r5);                /* load param1 */               \
212         lfd     3,0(r3);                /* load up fpscr value */       \
213         MTFSF_L(3);                                                     \
214         lwz     r6, 0(r4);              /* load cr */                   \
215         mtcr    r6;                                                     \
216                                                                         \
217         name    0,0,1;                  /* call instruction */          \
218         mfcr    r6;                                                     \
219         mffs    0;                                                      \
220         stfd    0,0(r3);                /* save new fpscr value */      \
221         stw     r6,0(r4);               /* save new cr value */         \
222         blr
223
224 /*
225  * Double operation with three input operands
226  *
227  * R3 = (double*)&fpscr
228  * R4 = (u32*)&cr
229  * R5 = (double*)&result
230  * R6 = (double*)&param1
231  * R7 = (double*)&param2
232  * R8 = (double*)&param3
233  */
234 #define FPD_THREE_IN(name)                                              \
235 _GLOBAL(fpd_ ## name);                                                  \
236         mflr    r12;                                                    \
237         bl      fpd_load_three;                                         \
238         mtlr    r12;                                                    \
239                                                                         \
240         name.   0,0,1,2;                /* call instruction */          \
241         b       fpd_return
242
243 FPD_ONE_IN(fsqrts)
244 FPD_ONE_IN(frsqrtes)
245 FPD_ONE_IN(fres)
246 FPD_ONE_IN(frsp)
247 FPD_ONE_IN(fctiw)
248 FPD_ONE_IN(fctiwz)
249 FPD_ONE_IN(fsqrt)
250 FPD_ONE_IN(fre)
251 FPD_ONE_IN(frsqrte)
252 FPD_ONE_IN(fneg)
253 FPD_ONE_IN(fabs)
254 FPD_TWO_IN(fadds)
255 FPD_TWO_IN(fsubs)
256 FPD_TWO_IN(fdivs)
257 FPD_TWO_IN(fmuls)
258 FPD_TWO_IN_CR(fcmpu)
259 FPD_TWO_IN(fcpsgn)
260 FPD_TWO_IN(fdiv)
261 FPD_TWO_IN(fadd)
262 FPD_TWO_IN(fmul)
263 FPD_TWO_IN_CR(fcmpo)
264 FPD_TWO_IN(fsub)
265 FPD_THREE_IN(fmsubs)
266 FPD_THREE_IN(fmadds)
267 FPD_THREE_IN(fnmsubs)
268 FPD_THREE_IN(fnmadds)
269 FPD_THREE_IN(fsel)
270 FPD_THREE_IN(fmsub)
271 FPD_THREE_IN(fmadd)
272 FPD_THREE_IN(fnmsub)
273 FPD_THREE_IN(fnmadd)