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