powerpc: Remove UP only lazy floating point and vector optimisations
[cascardo/linux.git] / arch / powerpc / kernel / vector.S
1 #include <asm/processor.h>
2 #include <asm/ppc_asm.h>
3 #include <asm/reg.h>
4 #include <asm/asm-offsets.h>
5 #include <asm/cputable.h>
6 #include <asm/thread_info.h>
7 #include <asm/page.h>
8 #include <asm/ptrace.h>
9
10 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
11 /* void do_load_up_transact_altivec(struct thread_struct *thread)
12  *
13  * This is similar to load_up_altivec but for the transactional version of the
14  * vector regs.  It doesn't mess with the task MSR or valid flags.
15  * Furthermore, VEC laziness is not supported with TM currently.
16  */
17 _GLOBAL(do_load_up_transact_altivec)
18         mfmsr   r6
19         oris    r5,r6,MSR_VEC@h
20         MTMSRD(r5)
21         isync
22
23         li      r4,1
24         stw     r4,THREAD_USED_VR(r3)
25
26         li      r10,THREAD_TRANSACT_VRSTATE+VRSTATE_VSCR
27         lvx     v0,r10,r3
28         mtvscr  v0
29         addi    r10,r3,THREAD_TRANSACT_VRSTATE
30         REST_32VRS(0,r4,r10)
31
32         blr
33 #endif
34
35 /*
36  * Enable use of VMX/Altivec for the caller.
37  */
38 _GLOBAL(vec_enable)
39         mfmsr   r3
40         oris    r3,r3,MSR_VEC@h
41         MTMSRD(r3)
42         isync
43         blr
44
45 /*
46  * Load state from memory into VMX registers including VSCR.
47  * Assumes the caller has enabled VMX in the MSR.
48  */
49 _GLOBAL(load_vr_state)
50         li      r4,VRSTATE_VSCR
51         lvx     v0,r4,r3
52         mtvscr  v0
53         REST_32VRS(0,r4,r3)
54         blr
55
56 /*
57  * Store VMX state into memory, including VSCR.
58  * Assumes the caller has enabled VMX in the MSR.
59  */
60 _GLOBAL(store_vr_state)
61         SAVE_32VRS(0, r4, r3)
62         mfvscr  v0
63         li      r4, VRSTATE_VSCR
64         stvx    v0, r4, r3
65         blr
66
67 /*
68  * Disable VMX for the task which had it previously,
69  * and save its vector registers in its thread_struct.
70  * Enables the VMX for use in the kernel on return.
71  * On SMP we know the VMX is free, since we give it up every
72  * switch (ie, no lazy save of the vector registers).
73  *
74  * Note that on 32-bit this can only use registers that will be
75  * restored by fast_exception_return, i.e. r3 - r6, r10 and r11.
76  */
77 _GLOBAL(load_up_altivec)
78         mfmsr   r5                      /* grab the current MSR */
79         oris    r5,r5,MSR_VEC@h
80         MTMSRD(r5)                      /* enable use of AltiVec now */
81         isync
82
83         /* Hack: if we get an altivec unavailable trap with VRSAVE
84          * set to all zeros, we assume this is a broken application
85          * that fails to set it properly, and thus we switch it to
86          * all 1's
87          */
88         mfspr   r4,SPRN_VRSAVE
89         cmpwi   0,r4,0
90         bne+    1f
91         li      r4,-1
92         mtspr   SPRN_VRSAVE,r4
93 1:
94         /* enable use of VMX after return */
95 #ifdef CONFIG_PPC32
96         mfspr   r5,SPRN_SPRG_THREAD             /* current task's THREAD (phys) */
97         oris    r9,r9,MSR_VEC@h
98 #else
99         ld      r4,PACACURRENT(r13)
100         addi    r5,r4,THREAD            /* Get THREAD */
101         oris    r12,r12,MSR_VEC@h
102         std     r12,_MSR(r1)
103 #endif
104         addi    r6,r5,THREAD_VRSTATE
105         li      r4,1
106         li      r10,VRSTATE_VSCR
107         stw     r4,THREAD_USED_VR(r5)
108         lvx     v0,r10,r6
109         mtvscr  v0
110         REST_32VRS(0,r4,r6)
111         /* restore registers and return */
112         blr
113
114 _GLOBAL(giveup_altivec_notask)
115         mfmsr   r3
116         andis.  r4,r3,MSR_VEC@h
117         bnelr                           /* Already enabled? */
118         oris    r3,r3,MSR_VEC@h
119         SYNC
120         MTMSRD(r3)                      /* enable use of VMX now */
121         isync
122         blr
123
124 /*
125  * giveup_altivec(tsk)
126  * Disable VMX for the task given as the argument,
127  * and save the vector registers in its thread_struct.
128  * Enables the VMX for use in the kernel on return.
129  */
130 _GLOBAL(giveup_altivec)
131         mfmsr   r5
132         oris    r5,r5,MSR_VEC@h
133         SYNC
134         MTMSRD(r5)                      /* enable use of VMX now */
135         isync
136         PPC_LCMPI       0,r3,0
137         beqlr                           /* if no previous owner, done */
138         addi    r3,r3,THREAD            /* want THREAD of task */
139         PPC_LL  r7,THREAD_VRSAVEAREA(r3)
140         PPC_LL  r5,PT_REGS(r3)
141         PPC_LCMPI       0,r7,0
142         bne     2f
143         addi    r7,r3,THREAD_VRSTATE
144 2:      PPC_LCMPI       0,r5,0
145         SAVE_32VRS(0,r4,r7)
146         mfvscr  v0
147         li      r4,VRSTATE_VSCR
148         stvx    v0,r4,r7
149         beq     1f
150         PPC_LL  r4,_MSR-STACK_FRAME_OVERHEAD(r5)
151 #ifdef CONFIG_VSX
152 BEGIN_FTR_SECTION
153         lis     r3,(MSR_VEC|MSR_VSX)@h
154 FTR_SECTION_ELSE
155         lis     r3,MSR_VEC@h
156 ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX)
157 #else
158         lis     r3,MSR_VEC@h
159 #endif
160         andc    r4,r4,r3                /* disable FP for previous task */
161         PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
162 1:
163         blr
164
165 #ifdef CONFIG_VSX
166
167 #ifdef CONFIG_PPC32
168 #error This asm code isn't ready for 32-bit kernels
169 #endif
170
171 /*
172  * load_up_vsx(unused, unused, tsk)
173  * Disable VSX for the task which had it previously,
174  * and save its vector registers in its thread_struct.
175  * Reuse the fp and vsx saves, but first check to see if they have
176  * been saved already.
177  */
178 _GLOBAL(load_up_vsx)
179 /* Load FP and VSX registers if they haven't been done yet */
180         andi.   r5,r12,MSR_FP
181         beql+   load_up_fpu             /* skip if already loaded */
182         andis.  r5,r12,MSR_VEC@h
183         beql+   load_up_altivec         /* skip if already loaded */
184
185         ld      r4,PACACURRENT(r13)
186         addi    r4,r4,THREAD            /* Get THREAD */
187         li      r6,1
188         stw     r6,THREAD_USED_VSR(r4) /* ... also set thread used vsr */
189         /* enable use of VSX after return */
190         oris    r12,r12,MSR_VSX@h
191         std     r12,_MSR(r1)
192         b       fast_exception_return
193
194 /*
195  * __giveup_vsx(tsk)
196  * Disable VSX for the task given as the argument.
197  * Does NOT save vsx registers.
198  * Enables the VSX for use in the kernel on return.
199  */
200 _GLOBAL(__giveup_vsx)
201         mfmsr   r5
202         oris    r5,r5,MSR_VSX@h
203         mtmsrd  r5                      /* enable use of VSX now */
204         isync
205
206         cmpdi   0,r3,0
207         beqlr-                          /* if no previous owner, done */
208         addi    r3,r3,THREAD            /* want THREAD of task */
209         ld      r5,PT_REGS(r3)
210         cmpdi   0,r5,0
211         beq     1f
212         ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
213         lis     r3,MSR_VSX@h
214         andc    r4,r4,r3                /* disable VSX for previous task */
215         std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
216 1:
217         blr
218
219 #endif /* CONFIG_VSX */
220
221
222 /*
223  * The routines below are in assembler so we can closely control the
224  * usage of floating-point registers.  These routines must be called
225  * with preempt disabled.
226  */
227 #ifdef CONFIG_PPC32
228         .data
229 fpzero:
230         .long   0
231 fpone:
232         .long   0x3f800000      /* 1.0 in single-precision FP */
233 fphalf:
234         .long   0x3f000000      /* 0.5 in single-precision FP */
235
236 #define LDCONST(fr, name)       \
237         lis     r11,name@ha;    \
238         lfs     fr,name@l(r11)
239 #else
240
241         .section ".toc","aw"
242 fpzero:
243         .tc     FD_0_0[TC],0
244 fpone:
245         .tc     FD_3ff00000_0[TC],0x3ff0000000000000    /* 1.0 */
246 fphalf:
247         .tc     FD_3fe00000_0[TC],0x3fe0000000000000    /* 0.5 */
248
249 #define LDCONST(fr, name)       \
250         lfd     fr,name@toc(r2)
251 #endif
252
253         .text
254 /*
255  * Internal routine to enable floating point and set FPSCR to 0.
256  * Don't call it from C; it doesn't use the normal calling convention.
257  */
258 fpenable:
259 #ifdef CONFIG_PPC32
260         stwu    r1,-64(r1)
261 #else
262         stdu    r1,-64(r1)
263 #endif
264         mfmsr   r10
265         ori     r11,r10,MSR_FP
266         mtmsr   r11
267         isync
268         stfd    fr0,24(r1)
269         stfd    fr1,16(r1)
270         stfd    fr31,8(r1)
271         LDCONST(fr1, fpzero)
272         mffs    fr31
273         MTFSF_L(fr1)
274         blr
275
276 fpdisable:
277         mtlr    r12
278         MTFSF_L(fr31)
279         lfd     fr31,8(r1)
280         lfd     fr1,16(r1)
281         lfd     fr0,24(r1)
282         mtmsr   r10
283         isync
284         addi    r1,r1,64
285         blr
286
287 /*
288  * Vector add, floating point.
289  */
290 _GLOBAL(vaddfp)
291         mflr    r12
292         bl      fpenable
293         li      r0,4
294         mtctr   r0
295         li      r6,0
296 1:      lfsx    fr0,r4,r6
297         lfsx    fr1,r5,r6
298         fadds   fr0,fr0,fr1
299         stfsx   fr0,r3,r6
300         addi    r6,r6,4
301         bdnz    1b
302         b       fpdisable
303
304 /*
305  * Vector subtract, floating point.
306  */
307 _GLOBAL(vsubfp)
308         mflr    r12
309         bl      fpenable
310         li      r0,4
311         mtctr   r0
312         li      r6,0
313 1:      lfsx    fr0,r4,r6
314         lfsx    fr1,r5,r6
315         fsubs   fr0,fr0,fr1
316         stfsx   fr0,r3,r6
317         addi    r6,r6,4
318         bdnz    1b
319         b       fpdisable
320
321 /*
322  * Vector multiply and add, floating point.
323  */
324 _GLOBAL(vmaddfp)
325         mflr    r12
326         bl      fpenable
327         stfd    fr2,32(r1)
328         li      r0,4
329         mtctr   r0
330         li      r7,0
331 1:      lfsx    fr0,r4,r7
332         lfsx    fr1,r5,r7
333         lfsx    fr2,r6,r7
334         fmadds  fr0,fr0,fr2,fr1
335         stfsx   fr0,r3,r7
336         addi    r7,r7,4
337         bdnz    1b
338         lfd     fr2,32(r1)
339         b       fpdisable
340
341 /*
342  * Vector negative multiply and subtract, floating point.
343  */
344 _GLOBAL(vnmsubfp)
345         mflr    r12
346         bl      fpenable
347         stfd    fr2,32(r1)
348         li      r0,4
349         mtctr   r0
350         li      r7,0
351 1:      lfsx    fr0,r4,r7
352         lfsx    fr1,r5,r7
353         lfsx    fr2,r6,r7
354         fnmsubs fr0,fr0,fr2,fr1
355         stfsx   fr0,r3,r7
356         addi    r7,r7,4
357         bdnz    1b
358         lfd     fr2,32(r1)
359         b       fpdisable
360
361 /*
362  * Vector reciprocal estimate.  We just compute 1.0/x.
363  * r3 -> destination, r4 -> source.
364  */
365 _GLOBAL(vrefp)
366         mflr    r12
367         bl      fpenable
368         li      r0,4
369         LDCONST(fr1, fpone)
370         mtctr   r0
371         li      r6,0
372 1:      lfsx    fr0,r4,r6
373         fdivs   fr0,fr1,fr0
374         stfsx   fr0,r3,r6
375         addi    r6,r6,4
376         bdnz    1b
377         b       fpdisable
378
379 /*
380  * Vector reciprocal square-root estimate, floating point.
381  * We use the frsqrte instruction for the initial estimate followed
382  * by 2 iterations of Newton-Raphson to get sufficient accuracy.
383  * r3 -> destination, r4 -> source.
384  */
385 _GLOBAL(vrsqrtefp)
386         mflr    r12
387         bl      fpenable
388         stfd    fr2,32(r1)
389         stfd    fr3,40(r1)
390         stfd    fr4,48(r1)
391         stfd    fr5,56(r1)
392         li      r0,4
393         LDCONST(fr4, fpone)
394         LDCONST(fr5, fphalf)
395         mtctr   r0
396         li      r6,0
397 1:      lfsx    fr0,r4,r6
398         frsqrte fr1,fr0         /* r = frsqrte(s) */
399         fmuls   fr3,fr1,fr0     /* r * s */
400         fmuls   fr2,fr1,fr5     /* r * 0.5 */
401         fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */
402         fmadds  fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */
403         fmuls   fr3,fr1,fr0     /* r * s */
404         fmuls   fr2,fr1,fr5     /* r * 0.5 */
405         fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */
406         fmadds  fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */
407         stfsx   fr1,r3,r6
408         addi    r6,r6,4
409         bdnz    1b
410         lfd     fr5,56(r1)
411         lfd     fr4,48(r1)
412         lfd     fr3,40(r1)
413         lfd     fr2,32(r1)
414         b       fpdisable