blob: a48df870b6960ebcc6d7b94389edec89da868335 [file] [log] [blame]
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +00001#include <asm/processor.h>
Paul Mackerras14cf11a2005-09-26 16:04:21 +10002#include <asm/ppc_asm.h>
Paul Mackerrasb3b8dc62005-10-10 22:20:10 +10003#include <asm/reg.h>
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +00004#include <asm/asm-offsets.h>
5#include <asm/cputable.h>
6#include <asm/thread_info.h>
7#include <asm/page.h>
Stephen Rothwell46f52212010-11-18 15:06:17 +00008#include <asm/ptrace.h>
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +00009
Michael Neulinga2dcbb32013-02-13 16:21:36 +000010#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
Michael Neulinga2dcbb32013-02-13 16:21:36 +000011/* 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
Paul Mackerrasde79f7b2013-09-10 20:20:42 +100026 li r10,THREAD_TRANSACT_VRSTATE+VRSTATE_VSCR
Michael Neulinga2dcbb32013-02-13 16:21:36 +000027 lvx vr0,r10,r3
28 mtvscr vr0
Paul Mackerrasde79f7b2013-09-10 20:20:42 +100029 addi r10,r3,THREAD_TRANSACT_VRSTATE
30 REST_32VRS(0,r4,r10)
Michael Neulinga2dcbb32013-02-13 16:21:36 +000031
32 /* Disable VEC again. */
33 MTMSRD(r6)
34 isync
35
36 blr
37#endif
38
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +000039/*
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +000040 * 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
Paul Mackerrasde79f7b2013-09-10 20:20:42 +100070 addi r7,r4,THREAD_VRSTATE
71 SAVE_32VRS(0,r5,r7)
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +000072 mfvscr vr0
Paul Mackerrasde79f7b2013-09-10 20:20:42 +100073 li r10,VRSTATE_VSCR
74 stvx vr0,r10,r7
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +000075 /* 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)
821:
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
Benjamin Herrenschmidte090aa82009-12-08 18:45:45 +000091 cmpwi 0,r4,0
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +000092 bne+ 1f
93 li r4,-1
94 mtspr SPRN_VRSAVE,r4
951:
96 /* enable use of VMX after return */
97#ifdef CONFIG_PPC32
Benjamin Herrenschmidtee43eb72009-07-14 20:52:54 +000098 mfspr r5,SPRN_SPRG_THREAD /* current task's THREAD (phys) */
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +000099 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
Paul Mackerrasde79f7b2013-09-10 20:20:42 +1000106 addi r7,r5,THREAD_VRSTATE
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000107 li r4,1
Paul Mackerrasde79f7b2013-09-10 20:20:42 +1000108 li r10,VRSTATE_VSCR
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000109 stw r4,THREAD_USED_VR(r5)
Paul Mackerrasde79f7b2013-09-10 20:20:42 +1000110 lvx vr0,r10,r7
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000111 mtvscr vr0
Paul Mackerrasde79f7b2013-09-10 20:20:42 +1000112 REST_32VRS(0,r4,r7)
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000113#ifndef CONFIG_SMP
Andreas Schwab0115cb52009-07-10 11:17:36 +0000114 /* Update last_task_used_altivec to 'current' */
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000115 subi r4,r5,THREAD /* Back to 'current' */
116 fromreal(r4)
Andreas Schwab0115cb52009-07-10 11:17:36 +0000117 PPC_STL r4,ADDROFF(last_task_used_altivec)(r3)
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000118#endif /* CONFIG_SMP */
119 /* restore registers and return */
120 blr
121
Anton Blanchard35000872012-04-15 20:56:45 +0000122_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
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000132/*
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
Anton Blanchardba00ce12011-05-08 21:20:19 +0000145 beqlr /* if no previous owner, done */
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000146 addi r3,r3,THREAD /* want THREAD of task */
Paul Mackerrasde79f7b2013-09-10 20:20:42 +1000147 addi r7,r3,THREAD_VRSTATE
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000148 PPC_LL r5,PT_REGS(r3)
149 PPC_LCMPI 0,r5,0
Paul Mackerrasde79f7b2013-09-10 20:20:42 +1000150 SAVE_32VRS(0,r4,r7)
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000151 mfvscr vr0
Paul Mackerrasde79f7b2013-09-10 20:20:42 +1000152 li r4,VRSTATE_VSCR
153 stvx vr0,r4,r7
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000154 beq 1f
155 PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
156#ifdef CONFIG_VSX
157BEGIN_FTR_SECTION
158 lis r3,(MSR_VEC|MSR_VSX)@h
159FTR_SECTION_ELSE
160 lis r3,MSR_VEC@h
161ALT_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)
1671:
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)
2071:
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
Andreas Schwab0115cb52009-07-10 11:17:36 +0000217 /* Update last_task_used_vsx to 'current' */
Benjamin Herrenschmidte821ea72009-06-02 21:17:37 +0000218 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)
2451:
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
Paul Mackerras14cf11a2005-09-26 16:04:21 +1000255
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
263fpzero:
264 .long 0
265fpone:
266 .long 0x3f800000 /* 1.0 in single-precision FP */
267fphalf:
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"
276fpzero:
277 .tc FD_0_0[TC],0
278fpone:
279 .tc FD_3ff00000_0[TC],0x3ff0000000000000 /* 1.0 */
280fphalf:
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 */
292fpenable:
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
Anton Blanchard3a2c48c2006-06-10 20:18:39 +1000307 MTFSF_L(fr1)
Paul Mackerras14cf11a2005-09-26 16:04:21 +1000308 blr
309
310fpdisable:
311 mtlr r12
Anton Blanchard3a2c48c2006-06-10 20:18:39 +1000312 MTFSF_L(fr31)
Paul Mackerras14cf11a2005-09-26 16:04:21 +1000313 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
3301: 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
3471: 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
3651: 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
3851: 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
4061: 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
4311: 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