aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/process.c
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2008-06-25 00:07:18 -0400
committerPaul Mackerras <paulus@samba.org>2008-06-30 21:28:50 -0400
commitce48b2100785e5ca629fb3aa8e3b50aca808f692 (patch)
tree63532ff7cc68b18ca4902bd10e03fcbaaf01cade /arch/powerpc/kernel/process.c
parent72ffff5b1792b0fa4d40a8e2f3276fff999820ec (diff)
powerpc: Add VSX context save/restore, ptrace and signal support
This patch extends the floating point save and restore code to use the VSX load/stores when VSX is available. This will make FP context save/restore marginally slower on FP only code, when VSX is available, as it has to load/store 128bits rather than just 64bits. Mixing FP, VMX and VSX code will get constant architected state. The signals interface is extended to enable access to VSR 0-31 doubleword 1 after discussions with tool chain maintainers. Backward compatibility is maintained. The ptrace interface is also extended to allow access to VSR 0-31 full registers. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/process.c')
-rw-r--r--arch/powerpc/kernel/process.c107
1 files changed, 106 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 582df70439cb..d52ded366f14 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -53,6 +53,7 @@ extern unsigned long _get_SP(void);
53#ifndef CONFIG_SMP 53#ifndef CONFIG_SMP
54struct task_struct *last_task_used_math = NULL; 54struct task_struct *last_task_used_math = NULL;
55struct task_struct *last_task_used_altivec = NULL; 55struct task_struct *last_task_used_altivec = NULL;
56struct task_struct *last_task_used_vsx = NULL;
56struct task_struct *last_task_used_spe = NULL; 57struct task_struct *last_task_used_spe = NULL;
57#endif 58#endif
58 59
@@ -106,11 +107,23 @@ EXPORT_SYMBOL(enable_kernel_fp);
106 107
107int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) 108int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
108{ 109{
110#ifdef CONFIG_VSX
111 int i;
112 elf_fpreg_t *reg;
113#endif
114
109 if (!tsk->thread.regs) 115 if (!tsk->thread.regs)
110 return 0; 116 return 0;
111 flush_fp_to_thread(current); 117 flush_fp_to_thread(current);
112 118
119#ifdef CONFIG_VSX
120 reg = (elf_fpreg_t *)fpregs;
121 for (i = 0; i < ELF_NFPREG - 1; i++, reg++)
122 *reg = tsk->thread.TS_FPR(i);
123 memcpy(reg, &tsk->thread.fpscr, sizeof(elf_fpreg_t));
124#else
113 memcpy(fpregs, &tsk->thread.TS_FPR(0), sizeof(*fpregs)); 125 memcpy(fpregs, &tsk->thread.TS_FPR(0), sizeof(*fpregs));
126#endif
114 127
115 return 1; 128 return 1;
116} 129}
@@ -149,7 +162,7 @@ void flush_altivec_to_thread(struct task_struct *tsk)
149 } 162 }
150} 163}
151 164
152int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs) 165int dump_task_altivec(struct task_struct *tsk, elf_vrreg_t *vrregs)
153{ 166{
154 /* ELF_NVRREG includes the VSCR and VRSAVE which we need to save 167 /* ELF_NVRREG includes the VSCR and VRSAVE which we need to save
155 * separately, see below */ 168 * separately, see below */
@@ -179,6 +192,80 @@ int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs)
179} 192}
180#endif /* CONFIG_ALTIVEC */ 193#endif /* CONFIG_ALTIVEC */
181 194
195#ifdef CONFIG_VSX
196#if 0
197/* not currently used, but some crazy RAID module might want to later */
198void enable_kernel_vsx(void)
199{
200 WARN_ON(preemptible());
201
202#ifdef CONFIG_SMP
203 if (current->thread.regs && (current->thread.regs->msr & MSR_VSX))
204 giveup_vsx(current);
205 else
206 giveup_vsx(NULL); /* just enable vsx for kernel - force */
207#else
208 giveup_vsx(last_task_used_vsx);
209#endif /* CONFIG_SMP */
210}
211EXPORT_SYMBOL(enable_kernel_vsx);
212#endif
213
214void flush_vsx_to_thread(struct task_struct *tsk)
215{
216 if (tsk->thread.regs) {
217 preempt_disable();
218 if (tsk->thread.regs->msr & MSR_VSX) {
219#ifdef CONFIG_SMP
220 BUG_ON(tsk != current);
221#endif
222 giveup_vsx(tsk);
223 }
224 preempt_enable();
225 }
226}
227
228/*
229 * This dumps the lower half 64bits of the first 32 VSX registers.
230 * This needs to be called with dump_task_fp and dump_task_altivec to
231 * get all the VSX state.
232 */
233int dump_task_vsx(struct task_struct *tsk, elf_vrreg_t *vrregs)
234{
235 elf_vrreg_t *reg;
236 double buf[32];
237 int i;
238
239 if (tsk == current)
240 flush_vsx_to_thread(tsk);
241
242 reg = (elf_vrreg_t *)vrregs;
243
244 for (i = 0; i < 32 ; i++)
245 buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET];
246 memcpy(reg, buf, sizeof(buf));
247
248 return 1;
249}
250#endif /* CONFIG_VSX */
251
252int dump_task_vector(struct task_struct *tsk, elf_vrregset_t *vrregs)
253{
254 int rc = 0;
255 elf_vrreg_t *regs = (elf_vrreg_t *)vrregs;
256#ifdef CONFIG_ALTIVEC
257 rc = dump_task_altivec(tsk, regs);
258 if (rc)
259 return rc;
260 regs += ELF_NVRREG;
261#endif
262
263#ifdef CONFIG_VSX
264 rc = dump_task_vsx(tsk, regs);
265#endif
266 return rc;
267}
268
182#ifdef CONFIG_SPE 269#ifdef CONFIG_SPE
183 270
184void enable_kernel_spe(void) 271void enable_kernel_spe(void)
@@ -233,6 +320,10 @@ void discard_lazy_cpu_state(void)
233 if (last_task_used_altivec == current) 320 if (last_task_used_altivec == current)
234 last_task_used_altivec = NULL; 321 last_task_used_altivec = NULL;
235#endif /* CONFIG_ALTIVEC */ 322#endif /* CONFIG_ALTIVEC */
323#ifdef CONFIG_VSX
324 if (last_task_used_vsx == current)
325 last_task_used_vsx = NULL;
326#endif /* CONFIG_VSX */
236#ifdef CONFIG_SPE 327#ifdef CONFIG_SPE
237 if (last_task_used_spe == current) 328 if (last_task_used_spe == current)
238 last_task_used_spe = NULL; 329 last_task_used_spe = NULL;
@@ -297,6 +388,10 @@ struct task_struct *__switch_to(struct task_struct *prev,
297 if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) 388 if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC))
298 giveup_altivec(prev); 389 giveup_altivec(prev);
299#endif /* CONFIG_ALTIVEC */ 390#endif /* CONFIG_ALTIVEC */
391#ifdef CONFIG_VSX
392 if (prev->thread.regs && (prev->thread.regs->msr & MSR_VSX))
393 giveup_vsx(prev);
394#endif /* CONFIG_VSX */
300#ifdef CONFIG_SPE 395#ifdef CONFIG_SPE
301 /* 396 /*
302 * If the previous thread used spe in the last quantum 397 * If the previous thread used spe in the last quantum
@@ -317,6 +412,10 @@ struct task_struct *__switch_to(struct task_struct *prev,
317 if (new->thread.regs && last_task_used_altivec == new) 412 if (new->thread.regs && last_task_used_altivec == new)
318 new->thread.regs->msr |= MSR_VEC; 413 new->thread.regs->msr |= MSR_VEC;
319#endif /* CONFIG_ALTIVEC */ 414#endif /* CONFIG_ALTIVEC */
415#ifdef CONFIG_VSX
416 if (new->thread.regs && last_task_used_vsx == new)
417 new->thread.regs->msr |= MSR_VSX;
418#endif /* CONFIG_VSX */
320#ifdef CONFIG_SPE 419#ifdef CONFIG_SPE
321 /* Avoid the trap. On smp this this never happens since 420 /* Avoid the trap. On smp this this never happens since
322 * we don't set last_task_used_spe 421 * we don't set last_task_used_spe
@@ -417,6 +516,8 @@ static struct regbit {
417 {MSR_EE, "EE"}, 516 {MSR_EE, "EE"},
418 {MSR_PR, "PR"}, 517 {MSR_PR, "PR"},
419 {MSR_FP, "FP"}, 518 {MSR_FP, "FP"},
519 {MSR_VEC, "VEC"},
520 {MSR_VSX, "VSX"},
420 {MSR_ME, "ME"}, 521 {MSR_ME, "ME"},
421 {MSR_IR, "IR"}, 522 {MSR_IR, "IR"},
422 {MSR_DR, "DR"}, 523 {MSR_DR, "DR"},
@@ -534,6 +635,7 @@ void prepare_to_copy(struct task_struct *tsk)
534{ 635{
535 flush_fp_to_thread(current); 636 flush_fp_to_thread(current);
536 flush_altivec_to_thread(current); 637 flush_altivec_to_thread(current);
638 flush_vsx_to_thread(current);
537 flush_spe_to_thread(current); 639 flush_spe_to_thread(current);
538} 640}
539 641
@@ -689,6 +791,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
689#endif 791#endif
690 792
691 discard_lazy_cpu_state(); 793 discard_lazy_cpu_state();
794#ifdef CONFIG_VSX
795 current->thread.used_vsr = 0;
796#endif
692 memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); 797 memset(current->thread.fpr, 0, sizeof(current->thread.fpr));
693 current->thread.fpscr.val = 0; 798 current->thread.fpscr.val = 0;
694#ifdef CONFIG_ALTIVEC 799#ifdef CONFIG_ALTIVEC