GNU Linux-libre 5.10.217-gnu1
[releases.git] / arch / powerpc / kernel / vector.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <asm/processor.h>
3 #include <asm/ppc_asm.h>
4 #include <asm/reg.h>
5 #include <asm/asm-offsets.h>
6 #include <asm/cputable.h>
7 #include <asm/thread_info.h>
8 #include <asm/page.h>
9 #include <asm/ptrace.h>
10 #include <asm/export.h>
11 #include <asm/asm-compat.h>
12
13 /*
14  * Load state from memory into VMX registers including VSCR.
15  * Assumes the caller has enabled VMX in the MSR.
16  */
17 _GLOBAL(load_vr_state)
18         li      r4,VRSTATE_VSCR
19         lvx     v0,r4,r3
20         mtvscr  v0
21         REST_32VRS(0,r4,r3)
22         blr
23 EXPORT_SYMBOL(load_vr_state)
24 _ASM_NOKPROBE_SYMBOL(load_vr_state); /* used by restore_math */
25
26 /*
27  * Store VMX state into memory, including VSCR.
28  * Assumes the caller has enabled VMX in the MSR.
29  */
30 _GLOBAL(store_vr_state)
31         SAVE_32VRS(0, r4, r3)
32         mfvscr  v0
33         li      r4, VRSTATE_VSCR
34         stvx    v0, r4, r3
35         lvx     v0, 0, r3
36         blr
37 EXPORT_SYMBOL(store_vr_state)
38
39 /*
40  * Disable VMX for the task which had it previously,
41  * and save its vector registers in its thread_struct.
42  * Enables the VMX for use in the kernel on return.
43  * On SMP we know the VMX is free, since we give it up every
44  * switch (ie, no lazy save of the vector registers).
45  *
46  * Note that on 32-bit this can only use registers that will be
47  * restored by fast_exception_return, i.e. r3 - r6, r10 and r11.
48  */
49 _GLOBAL(load_up_altivec)
50         mfmsr   r5                      /* grab the current MSR */
51         oris    r5,r5,MSR_VEC@h
52         MTMSRD(r5)                      /* enable use of AltiVec now */
53         isync
54
55         /*
56          * While userspace in general ignores VRSAVE, glibc uses it as a boolean
57          * to optimise userspace context save/restore. Whenever we take an
58          * altivec unavailable exception we must set VRSAVE to something non
59          * zero. Set it to all 1s. See also the programming note in the ISA.
60          */
61         mfspr   r4,SPRN_VRSAVE
62         cmpwi   0,r4,0
63         bne+    1f
64         li      r4,-1
65         mtspr   SPRN_VRSAVE,r4
66 1:
67         /* enable use of VMX after return */
68 #ifdef CONFIG_PPC32
69         mfspr   r5,SPRN_SPRG_THREAD             /* current task's THREAD (phys) */
70         oris    r9,r9,MSR_VEC@h
71 #ifdef CONFIG_VMAP_STACK
72         tovirt(r5, r5)
73 #endif
74 #else
75         ld      r4,PACACURRENT(r13)
76         addi    r5,r4,THREAD            /* Get THREAD */
77         oris    r12,r12,MSR_VEC@h
78         std     r12,_MSR(r1)
79 #endif
80         li      r4,1
81         stb     r4,THREAD_LOAD_VEC(r5)
82         addi    r6,r5,THREAD_VRSTATE
83         li      r4,1
84         li      r10,VRSTATE_VSCR
85         stw     r4,THREAD_USED_VR(r5)
86         lvx     v0,r10,r6
87         mtvscr  v0
88         REST_32VRS(0,r4,r6)
89         /* restore registers and return */
90         blr
91 _ASM_NOKPROBE_SYMBOL(load_up_altivec)
92
93 /*
94  * save_altivec(tsk)
95  * Save the vector registers to its thread_struct
96  */
97 _GLOBAL(save_altivec)
98         addi    r3,r3,THREAD            /* want THREAD of task */
99         PPC_LL  r7,THREAD_VRSAVEAREA(r3)
100         PPC_LL  r5,PT_REGS(r3)
101         PPC_LCMPI       0,r7,0
102         bne     2f
103         addi    r7,r3,THREAD_VRSTATE
104 2:      SAVE_32VRS(0,r4,r7)
105         mfvscr  v0
106         li      r4,VRSTATE_VSCR
107         stvx    v0,r4,r7
108         lvx     v0,0,r7
109         blr
110
111 #ifdef CONFIG_VSX
112
113 #ifdef CONFIG_PPC32
114 #error This asm code isn't ready for 32-bit kernels
115 #endif
116
117 /*
118  * load_up_vsx(unused, unused, tsk)
119  * Disable VSX for the task which had it previously,
120  * and save its vector registers in its thread_struct.
121  * Reuse the fp and vsx saves, but first check to see if they have
122  * been saved already.
123  */
124 _GLOBAL(load_up_vsx)
125 /* Load FP and VSX registers if they haven't been done yet */
126         andi.   r5,r12,MSR_FP
127         beql+   load_up_fpu             /* skip if already loaded */
128         andis.  r5,r12,MSR_VEC@h
129         beql+   load_up_altivec         /* skip if already loaded */
130
131         ld      r4,PACACURRENT(r13)
132         addi    r4,r4,THREAD            /* Get THREAD */
133         li      r6,1
134         stw     r6,THREAD_USED_VSR(r4) /* ... also set thread used vsr */
135         /* enable use of VSX after return */
136         oris    r12,r12,MSR_VSX@h
137         std     r12,_MSR(r1)
138         b       fast_interrupt_return
139
140 #endif /* CONFIG_VSX */
141
142
143 /*
144  * The routines below are in assembler so we can closely control the
145  * usage of floating-point registers.  These routines must be called
146  * with preempt disabled.
147  */
148 #ifdef CONFIG_PPC32
149         .data
150 fpzero:
151         .long   0
152 fpone:
153         .long   0x3f800000      /* 1.0 in single-precision FP */
154 fphalf:
155         .long   0x3f000000      /* 0.5 in single-precision FP */
156
157 #define LDCONST(fr, name)       \
158         lis     r11,name@ha;    \
159         lfs     fr,name@l(r11)
160 #else
161
162         .section ".toc","aw"
163 fpzero:
164         .tc     FD_0_0[TC],0
165 fpone:
166         .tc     FD_3ff00000_0[TC],0x3ff0000000000000    /* 1.0 */
167 fphalf:
168         .tc     FD_3fe00000_0[TC],0x3fe0000000000000    /* 0.5 */
169
170 #define LDCONST(fr, name)       \
171         lfd     fr,name@toc(r2)
172 #endif
173
174         .text
175 /*
176  * Internal routine to enable floating point and set FPSCR to 0.
177  * Don't call it from C; it doesn't use the normal calling convention.
178  */
179 fpenable:
180 #ifdef CONFIG_PPC32
181         stwu    r1,-64(r1)
182 #else
183         stdu    r1,-64(r1)
184 #endif
185         mfmsr   r10
186         ori     r11,r10,MSR_FP
187         mtmsr   r11
188         isync
189         stfd    fr0,24(r1)
190         stfd    fr1,16(r1)
191         stfd    fr31,8(r1)
192         LDCONST(fr1, fpzero)
193         mffs    fr31
194         MTFSF_L(fr1)
195         blr
196
197 fpdisable:
198         mtlr    r12
199         MTFSF_L(fr31)
200         lfd     fr31,8(r1)
201         lfd     fr1,16(r1)
202         lfd     fr0,24(r1)
203         mtmsr   r10
204         isync
205         addi    r1,r1,64
206         blr
207
208 /*
209  * Vector add, floating point.
210  */
211 _GLOBAL(vaddfp)
212         mflr    r12
213         bl      fpenable
214         li      r0,4
215         mtctr   r0
216         li      r6,0
217 1:      lfsx    fr0,r4,r6
218         lfsx    fr1,r5,r6
219         fadds   fr0,fr0,fr1
220         stfsx   fr0,r3,r6
221         addi    r6,r6,4
222         bdnz    1b
223         b       fpdisable
224
225 /*
226  * Vector subtract, floating point.
227  */
228 _GLOBAL(vsubfp)
229         mflr    r12
230         bl      fpenable
231         li      r0,4
232         mtctr   r0
233         li      r6,0
234 1:      lfsx    fr0,r4,r6
235         lfsx    fr1,r5,r6
236         fsubs   fr0,fr0,fr1
237         stfsx   fr0,r3,r6
238         addi    r6,r6,4
239         bdnz    1b
240         b       fpdisable
241
242 /*
243  * Vector multiply and add, floating point.
244  */
245 _GLOBAL(vmaddfp)
246         mflr    r12
247         bl      fpenable
248         stfd    fr2,32(r1)
249         li      r0,4
250         mtctr   r0
251         li      r7,0
252 1:      lfsx    fr0,r4,r7
253         lfsx    fr1,r5,r7
254         lfsx    fr2,r6,r7
255         fmadds  fr0,fr0,fr2,fr1
256         stfsx   fr0,r3,r7
257         addi    r7,r7,4
258         bdnz    1b
259         lfd     fr2,32(r1)
260         b       fpdisable
261
262 /*
263  * Vector negative multiply and subtract, floating point.
264  */
265 _GLOBAL(vnmsubfp)
266         mflr    r12
267         bl      fpenable
268         stfd    fr2,32(r1)
269         li      r0,4
270         mtctr   r0
271         li      r7,0
272 1:      lfsx    fr0,r4,r7
273         lfsx    fr1,r5,r7
274         lfsx    fr2,r6,r7
275         fnmsubs fr0,fr0,fr2,fr1
276         stfsx   fr0,r3,r7
277         addi    r7,r7,4
278         bdnz    1b
279         lfd     fr2,32(r1)
280         b       fpdisable
281
282 /*
283  * Vector reciprocal estimate.  We just compute 1.0/x.
284  * r3 -> destination, r4 -> source.
285  */
286 _GLOBAL(vrefp)
287         mflr    r12
288         bl      fpenable
289         li      r0,4
290         LDCONST(fr1, fpone)
291         mtctr   r0
292         li      r6,0
293 1:      lfsx    fr0,r4,r6
294         fdivs   fr0,fr1,fr0
295         stfsx   fr0,r3,r6
296         addi    r6,r6,4
297         bdnz    1b
298         b       fpdisable
299
300 /*
301  * Vector reciprocal square-root estimate, floating point.
302  * We use the frsqrte instruction for the initial estimate followed
303  * by 2 iterations of Newton-Raphson to get sufficient accuracy.
304  * r3 -> destination, r4 -> source.
305  */
306 _GLOBAL(vrsqrtefp)
307         mflr    r12
308         bl      fpenable
309         stfd    fr2,32(r1)
310         stfd    fr3,40(r1)
311         stfd    fr4,48(r1)
312         stfd    fr5,56(r1)
313         li      r0,4
314         LDCONST(fr4, fpone)
315         LDCONST(fr5, fphalf)
316         mtctr   r0
317         li      r6,0
318 1:      lfsx    fr0,r4,r6
319         frsqrte fr1,fr0         /* r = frsqrte(s) */
320         fmuls   fr3,fr1,fr0     /* r * s */
321         fmuls   fr2,fr1,fr5     /* r * 0.5 */
322         fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */
323         fmadds  fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */
324         fmuls   fr3,fr1,fr0     /* r * s */
325         fmuls   fr2,fr1,fr5     /* r * 0.5 */
326         fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */
327         fmadds  fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */
328         stfsx   fr1,r3,r6
329         addi    r6,r6,4
330         bdnz    1b
331         lfd     fr5,56(r1)
332         lfd     fr4,48(r1)
333         lfd     fr3,40(r1)
334         lfd     fr2,32(r1)
335         b       fpdisable