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