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