aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/vector.S
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-06-02 17:17:37 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-06-09 02:46:25 -0400
commite821ea70f3b4873b50056a1e0f74befed1014c09 (patch)
tree5c7808e9ab65af2577a05a79726fb211f673feb8 /arch/powerpc/kernel/vector.S
parentd3f6204a7d65030ba92bf43a278b3f3054353e0b (diff)
powerpc: Move VMX and VSX asm code to vector.S
Currently, load_up_altivec and give_up_altivec are duplicated in 32-bit and 64-bit. This creates a common implementation that is moved away from head_32.S, head_64.S and misc_64.S and into vector.S, using the same macros we already use for our common implementation of load_up_fpu. I also moved the VSX code over to vector.S though in that case I didn't make it build on 32-bit (yet). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/vector.S')
-rw-r--r--arch/powerpc/kernel/vector.S210
1 files changed, 210 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index 49ac3d6e1399..ef36cbbc5882 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -1,5 +1,215 @@
1#include <asm/processor.h>
1#include <asm/ppc_asm.h> 2#include <asm/ppc_asm.h>
2#include <asm/reg.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
9/*
10 * load_up_altivec(unused, unused, tsk)
11 * Disable VMX for the task which had it previously,
12 * and save its vector registers in its thread_struct.
13 * Enables the VMX for use in the kernel on return.
14 * On SMP we know the VMX is free, since we give it up every
15 * switch (ie, no lazy save of the vector registers).
16 */
17_GLOBAL(load_up_altivec)
18 mfmsr r5 /* grab the current MSR */
19 oris r5,r5,MSR_VEC@h
20 MTMSRD(r5) /* enable use of AltiVec now */
21 isync
22
23/*
24 * For SMP, we don't do lazy VMX switching because it just gets too
25 * horrendously complex, especially when a task switches from one CPU
26 * to another. Instead we call giveup_altvec in switch_to.
27 * VRSAVE isn't dealt with here, that is done in the normal context
28 * switch code. Note that we could rely on vrsave value to eventually
29 * avoid saving all of the VREGs here...
30 */
31#ifndef CONFIG_SMP
32 LOAD_REG_ADDRBASE(r3, last_task_used_altivec)
33 toreal(r3)
34 PPC_LL r4,ADDROFF(last_task_used_altivec)(r3)
35 PPC_LCMPI 0,r4,0
36 beq 1f
37
38 /* Save VMX state to last_task_used_altivec's THREAD struct */
39 toreal(r4)
40 addi r4,r4,THREAD
41 SAVE_32VRS(0,r5,r4)
42 mfvscr vr0
43 li r10,THREAD_VSCR
44 stvx vr0,r10,r4
45 /* Disable VMX for last_task_used_altivec */
46 PPC_LL r5,PT_REGS(r4)
47 toreal(r5)
48 PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
49 lis r10,MSR_VEC@h
50 andc r4,r4,r10
51 PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
521:
53#endif /* CONFIG_SMP */
54
55 /* Hack: if we get an altivec unavailable trap with VRSAVE
56 * set to all zeros, we assume this is a broken application
57 * that fails to set it properly, and thus we switch it to
58 * all 1's
59 */
60 mfspr r4,SPRN_VRSAVE
61 cmpdi 0,r4,0
62 bne+ 1f
63 li r4,-1
64 mtspr SPRN_VRSAVE,r4
651:
66 /* enable use of VMX after return */
67#ifdef CONFIG_PPC32
68 mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */
69 oris r9,r9,MSR_VEC@h
70#else
71 ld r4,PACACURRENT(r13)
72 addi r5,r4,THREAD /* Get THREAD */
73 oris r12,r12,MSR_VEC@h
74 std r12,_MSR(r1)
75#endif
76 li r4,1
77 li r10,THREAD_VSCR
78 stw r4,THREAD_USED_VR(r5)
79 lvx vr0,r10,r5
80 mtvscr vr0
81 REST_32VRS(0,r4,r5)
82#ifndef CONFIG_SMP
83 /* Update last_task_used_math to 'current' */
84 subi r4,r5,THREAD /* Back to 'current' */
85 fromreal(r4)
86 PPC_STL r4,ADDROFF(last_task_used_math)(r3)
87#endif /* CONFIG_SMP */
88 /* restore registers and return */
89 blr
90
91/*
92 * giveup_altivec(tsk)
93 * Disable VMX for the task given as the argument,
94 * and save the vector registers in its thread_struct.
95 * Enables the VMX for use in the kernel on return.
96 */
97_GLOBAL(giveup_altivec)
98 mfmsr r5
99 oris r5,r5,MSR_VEC@h
100 SYNC
101 MTMSRD(r5) /* enable use of VMX now */
102 isync
103 PPC_LCMPI 0,r3,0
104 beqlr- /* if no previous owner, done */
105 addi r3,r3,THREAD /* want THREAD of task */
106 PPC_LL r5,PT_REGS(r3)
107 PPC_LCMPI 0,r5,0
108 SAVE_32VRS(0,r4,r3)
109 mfvscr vr0
110 li r4,THREAD_VSCR
111 stvx vr0,r4,r3
112 beq 1f
113 PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
114#ifdef CONFIG_VSX
115BEGIN_FTR_SECTION
116 lis r3,(MSR_VEC|MSR_VSX)@h
117FTR_SECTION_ELSE
118 lis r3,MSR_VEC@h
119ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX)
120#else
121 lis r3,MSR_VEC@h
122#endif
123 andc r4,r4,r3 /* disable FP for previous task */
124 PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
1251:
126#ifndef CONFIG_SMP
127 li r5,0
128 LOAD_REG_ADDRBASE(r4,last_task_used_altivec)
129 PPC_STL r5,ADDROFF(last_task_used_altivec)(r4)
130#endif /* CONFIG_SMP */
131 blr
132
133#ifdef CONFIG_VSX
134
135#ifdef CONFIG_PPC32
136#error This asm code isn't ready for 32-bit kernels
137#endif
138
139/*
140 * load_up_vsx(unused, unused, tsk)
141 * Disable VSX for the task which had it previously,
142 * and save its vector registers in its thread_struct.
143 * Reuse the fp and vsx saves, but first check to see if they have
144 * been saved already.
145 */
146_GLOBAL(load_up_vsx)
147/* Load FP and VSX registers if they haven't been done yet */
148 andi. r5,r12,MSR_FP
149 beql+ load_up_fpu /* skip if already loaded */
150 andis. r5,r12,MSR_VEC@h
151 beql+ load_up_altivec /* skip if already loaded */
152
153#ifndef CONFIG_SMP
154 ld r3,last_task_used_vsx@got(r2)
155 ld r4,0(r3)
156 cmpdi 0,r4,0
157 beq 1f
158 /* Disable VSX for last_task_used_vsx */
159 addi r4,r4,THREAD
160 ld r5,PT_REGS(r4)
161 ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
162 lis r6,MSR_VSX@h
163 andc r6,r4,r6
164 std r6,_MSR-STACK_FRAME_OVERHEAD(r5)
1651:
166#endif /* CONFIG_SMP */
167 ld r4,PACACURRENT(r13)
168 addi r4,r4,THREAD /* Get THREAD */
169 li r6,1
170 stw r6,THREAD_USED_VSR(r4) /* ... also set thread used vsr */
171 /* enable use of VSX after return */
172 oris r12,r12,MSR_VSX@h
173 std r12,_MSR(r1)
174#ifndef CONFIG_SMP
175 /* Update last_task_used_math to 'current' */
176 ld r4,PACACURRENT(r13)
177 std r4,0(r3)
178#endif /* CONFIG_SMP */
179 b fast_exception_return
180
181/*
182 * __giveup_vsx(tsk)
183 * Disable VSX for the task given as the argument.
184 * Does NOT save vsx registers.
185 * Enables the VSX for use in the kernel on return.
186 */
187_GLOBAL(__giveup_vsx)
188 mfmsr r5
189 oris r5,r5,MSR_VSX@h
190 mtmsrd r5 /* enable use of VSX now */
191 isync
192
193 cmpdi 0,r3,0
194 beqlr- /* if no previous owner, done */
195 addi r3,r3,THREAD /* want THREAD of task */
196 ld r5,PT_REGS(r3)
197 cmpdi 0,r5,0
198 beq 1f
199 ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
200 lis r3,MSR_VSX@h
201 andc r4,r4,r3 /* disable VSX for previous task */
202 std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
2031:
204#ifndef CONFIG_SMP
205 li r5,0
206 ld r4,last_task_used_vsx@got(r2)
207 std r5,0(r4)
208#endif /* CONFIG_SMP */
209 blr
210
211#endif /* CONFIG_VSX */
212
3 213
4/* 214/*
5 * The routines below are in assembler so we can closely control the 215 * The routines below are in assembler so we can closely control the