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