From 9c75a31c3525a127f70b919856e32be3d8b03755 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 26 Jun 2008 17:07:48 +1000 Subject: powerpc: Add macros to access floating point registers in thread_struct. We are going to change where the floating point registers are stored in the thread_struct, so in preparation add some macros to access the floating point registers. Update all code to use these new macros. Signed-off-by: Michael Neuling Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/kernel/process.c') diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 7de41c3948ec..582df70439cb 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -110,7 +110,7 @@ int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) return 0; flush_fp_to_thread(current); - memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); + memcpy(fpregs, &tsk->thread.TS_FPR(0), sizeof(*fpregs)); return 1; } -- cgit v1.2.3 From ce48b2100785e5ca629fb3aa8e3b50aca808f692 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 25 Jun 2008 14:07:18 +1000 Subject: 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 Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/process.c | 107 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/kernel/process.c') 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); #ifndef CONFIG_SMP struct task_struct *last_task_used_math = NULL; struct task_struct *last_task_used_altivec = NULL; +struct task_struct *last_task_used_vsx = NULL; struct task_struct *last_task_used_spe = NULL; #endif @@ -106,11 +107,23 @@ EXPORT_SYMBOL(enable_kernel_fp); int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) { +#ifdef CONFIG_VSX + int i; + elf_fpreg_t *reg; +#endif + if (!tsk->thread.regs) return 0; flush_fp_to_thread(current); +#ifdef CONFIG_VSX + reg = (elf_fpreg_t *)fpregs; + for (i = 0; i < ELF_NFPREG - 1; i++, reg++) + *reg = tsk->thread.TS_FPR(i); + memcpy(reg, &tsk->thread.fpscr, sizeof(elf_fpreg_t)); +#else memcpy(fpregs, &tsk->thread.TS_FPR(0), sizeof(*fpregs)); +#endif return 1; } @@ -149,7 +162,7 @@ void flush_altivec_to_thread(struct task_struct *tsk) } } -int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs) +int dump_task_altivec(struct task_struct *tsk, elf_vrreg_t *vrregs) { /* ELF_NVRREG includes the VSCR and VRSAVE which we need to save * separately, see below */ @@ -179,6 +192,80 @@ int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs) } #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_VSX +#if 0 +/* not currently used, but some crazy RAID module might want to later */ +void enable_kernel_vsx(void) +{ + WARN_ON(preemptible()); + +#ifdef CONFIG_SMP + if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) + giveup_vsx(current); + else + giveup_vsx(NULL); /* just enable vsx for kernel - force */ +#else + giveup_vsx(last_task_used_vsx); +#endif /* CONFIG_SMP */ +} +EXPORT_SYMBOL(enable_kernel_vsx); +#endif + +void flush_vsx_to_thread(struct task_struct *tsk) +{ + if (tsk->thread.regs) { + preempt_disable(); + if (tsk->thread.regs->msr & MSR_VSX) { +#ifdef CONFIG_SMP + BUG_ON(tsk != current); +#endif + giveup_vsx(tsk); + } + preempt_enable(); + } +} + +/* + * This dumps the lower half 64bits of the first 32 VSX registers. + * This needs to be called with dump_task_fp and dump_task_altivec to + * get all the VSX state. + */ +int dump_task_vsx(struct task_struct *tsk, elf_vrreg_t *vrregs) +{ + elf_vrreg_t *reg; + double buf[32]; + int i; + + if (tsk == current) + flush_vsx_to_thread(tsk); + + reg = (elf_vrreg_t *)vrregs; + + for (i = 0; i < 32 ; i++) + buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET]; + memcpy(reg, buf, sizeof(buf)); + + return 1; +} +#endif /* CONFIG_VSX */ + +int dump_task_vector(struct task_struct *tsk, elf_vrregset_t *vrregs) +{ + int rc = 0; + elf_vrreg_t *regs = (elf_vrreg_t *)vrregs; +#ifdef CONFIG_ALTIVEC + rc = dump_task_altivec(tsk, regs); + if (rc) + return rc; + regs += ELF_NVRREG; +#endif + +#ifdef CONFIG_VSX + rc = dump_task_vsx(tsk, regs); +#endif + return rc; +} + #ifdef CONFIG_SPE void enable_kernel_spe(void) @@ -233,6 +320,10 @@ void discard_lazy_cpu_state(void) if (last_task_used_altivec == current) last_task_used_altivec = NULL; #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_VSX + if (last_task_used_vsx == current) + last_task_used_vsx = NULL; +#endif /* CONFIG_VSX */ #ifdef CONFIG_SPE if (last_task_used_spe == current) last_task_used_spe = NULL; @@ -297,6 +388,10 @@ struct task_struct *__switch_to(struct task_struct *prev, if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) giveup_altivec(prev); #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_VSX + if (prev->thread.regs && (prev->thread.regs->msr & MSR_VSX)) + giveup_vsx(prev); +#endif /* CONFIG_VSX */ #ifdef CONFIG_SPE /* * If the previous thread used spe in the last quantum @@ -317,6 +412,10 @@ struct task_struct *__switch_to(struct task_struct *prev, if (new->thread.regs && last_task_used_altivec == new) new->thread.regs->msr |= MSR_VEC; #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_VSX + if (new->thread.regs && last_task_used_vsx == new) + new->thread.regs->msr |= MSR_VSX; +#endif /* CONFIG_VSX */ #ifdef CONFIG_SPE /* Avoid the trap. On smp this this never happens since * we don't set last_task_used_spe @@ -417,6 +516,8 @@ static struct regbit { {MSR_EE, "EE"}, {MSR_PR, "PR"}, {MSR_FP, "FP"}, + {MSR_VEC, "VEC"}, + {MSR_VSX, "VSX"}, {MSR_ME, "ME"}, {MSR_IR, "IR"}, {MSR_DR, "DR"}, @@ -534,6 +635,7 @@ void prepare_to_copy(struct task_struct *tsk) { flush_fp_to_thread(current); flush_altivec_to_thread(current); + flush_vsx_to_thread(current); flush_spe_to_thread(current); } @@ -689,6 +791,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) #endif discard_lazy_cpu_state(); +#ifdef CONFIG_VSX + current->thread.used_vsr = 0; +#endif memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); current->thread.fpscr.val = 0; #ifdef CONFIG_ALTIVEC -- cgit v1.2.3 From f3e909c2750eb20536bacacc867dc9047b70546a Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 1 Jul 2008 14:01:39 +1000 Subject: powerpc: Update for VSX core file and ptrace This correctly hooks the VSX dump into Roland McGrath core file infrastructure. It adds the VSX dump information as an additional elf note in the core file (after talking more to the tool chain/gdb guys). This also ensures the formats are consistent between signals, ptrace and core files. Signed-off-by: Michael Neuling Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/process.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'arch/powerpc/kernel/process.c') diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d52ded366f14..1924b57bd241 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -162,7 +162,7 @@ void flush_altivec_to_thread(struct task_struct *tsk) } } -int dump_task_altivec(struct task_struct *tsk, elf_vrreg_t *vrregs) +int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs) { /* ELF_NVRREG includes the VSCR and VRSAVE which we need to save * separately, see below */ @@ -249,23 +249,6 @@ int dump_task_vsx(struct task_struct *tsk, elf_vrreg_t *vrregs) } #endif /* CONFIG_VSX */ -int dump_task_vector(struct task_struct *tsk, elf_vrregset_t *vrregs) -{ - int rc = 0; - elf_vrreg_t *regs = (elf_vrreg_t *)vrregs; -#ifdef CONFIG_ALTIVEC - rc = dump_task_altivec(tsk, regs); - if (rc) - return rc; - regs += ELF_NVRREG; -#endif - -#ifdef CONFIG_VSX - rc = dump_task_vsx(tsk, regs); -#endif - return rc; -} - #ifdef CONFIG_SPE void enable_kernel_spe(void) -- cgit v1.2.3 From 138fc1ee06e58f12fc2b755e435ce15bb36a0471 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 2 Jul 2008 22:51:37 +1000 Subject: powerpc: Remove old dump_task_* functions Since Roland's ptrace cleanup starting with commit f65255e8d51ecbc6c9eef20d39e0377d19b658ca ("[POWERPC] Use user_regset accessors for FP regs"), the dump_task_* functions are no longer being used. Signed-off-by: Michael Neuling Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/process.c | 83 ------------------------------------------- 1 file changed, 83 deletions(-) (limited to 'arch/powerpc/kernel/process.c') diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 1924b57bd241..85e557300d86 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -105,29 +105,6 @@ void enable_kernel_fp(void) } EXPORT_SYMBOL(enable_kernel_fp); -int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) -{ -#ifdef CONFIG_VSX - int i; - elf_fpreg_t *reg; -#endif - - if (!tsk->thread.regs) - return 0; - flush_fp_to_thread(current); - -#ifdef CONFIG_VSX - reg = (elf_fpreg_t *)fpregs; - for (i = 0; i < ELF_NFPREG - 1; i++, reg++) - *reg = tsk->thread.TS_FPR(i); - memcpy(reg, &tsk->thread.fpscr, sizeof(elf_fpreg_t)); -#else - memcpy(fpregs, &tsk->thread.TS_FPR(0), sizeof(*fpregs)); -#endif - - return 1; -} - #ifdef CONFIG_ALTIVEC void enable_kernel_altivec(void) { @@ -161,35 +138,6 @@ void flush_altivec_to_thread(struct task_struct *tsk) preempt_enable(); } } - -int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs) -{ - /* ELF_NVRREG includes the VSCR and VRSAVE which we need to save - * separately, see below */ - const int nregs = ELF_NVRREG - 2; - elf_vrreg_t *reg; - u32 *dest; - - if (tsk == current) - flush_altivec_to_thread(tsk); - - reg = (elf_vrreg_t *)vrregs; - - /* copy the 32 vr registers */ - memcpy(reg, &tsk->thread.vr[0], nregs * sizeof(*reg)); - reg += nregs; - - /* copy the vscr */ - memcpy(reg, &tsk->thread.vscr, sizeof(*reg)); - reg++; - - /* vrsave is stored in the high 32bit slot of the final 128bits */ - memset(reg, 0, sizeof(*reg)); - dest = (u32 *)reg; - *dest = tsk->thread.vrsave; - - return 1; -} #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_VSX @@ -224,29 +172,6 @@ void flush_vsx_to_thread(struct task_struct *tsk) preempt_enable(); } } - -/* - * This dumps the lower half 64bits of the first 32 VSX registers. - * This needs to be called with dump_task_fp and dump_task_altivec to - * get all the VSX state. - */ -int dump_task_vsx(struct task_struct *tsk, elf_vrreg_t *vrregs) -{ - elf_vrreg_t *reg; - double buf[32]; - int i; - - if (tsk == current) - flush_vsx_to_thread(tsk); - - reg = (elf_vrreg_t *)vrregs; - - for (i = 0; i < 32 ; i++) - buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET]; - memcpy(reg, buf, sizeof(buf)); - - return 1; -} #endif /* CONFIG_VSX */ #ifdef CONFIG_SPE @@ -279,14 +204,6 @@ void flush_spe_to_thread(struct task_struct *tsk) preempt_enable(); } } - -int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs) -{ - flush_spe_to_thread(current); - /* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */ - memcpy(evrregs, ¤t->thread.evr[0], sizeof(u32) * 35); - return 1; -} #endif /* CONFIG_SPE */ #ifndef CONFIG_SMP -- cgit v1.2.3 From 058c78f4ba89df7b2de82ac271452f09e2b8fa05 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 7 Jul 2008 13:44:31 +1000 Subject: powerpc: Use new printk extension %pS to print symbols on oops This changes the oops and backtrace code to use the new %pS printk extension to print out symbols rather than manually calling print_symbol. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/process.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'arch/powerpc/kernel/process.c') diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 85e557300d86..0a4eb0811590 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -485,10 +485,8 @@ void show_regs(struct pt_regs * regs) * Lookup NIP late so we have the best change of getting the * above info out without failing */ - printk("NIP ["REG"] ", regs->nip); - print_symbol("%s\n", regs->nip); - printk("LR ["REG"] ", regs->link); - print_symbol("%s\n", regs->link); + printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip); + printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link); #endif show_stack(current, (unsigned long *) regs->gpr[1]); if (!user_mode(regs)) @@ -976,8 +974,7 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) newsp = stack[0]; ip = stack[STACK_FRAME_LR_SAVE]; if (!firstframe || ip != lr) { - printk("["REG"] ["REG"] ", sp, ip); - print_symbol("%s", ip); + printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip); if (firstframe) printk(" (unreliable)"); printk("\n"); @@ -992,10 +989,9 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) && stack[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) { struct pt_regs *regs = (struct pt_regs *) (sp + STACK_FRAME_OVERHEAD); - printk("--- Exception: %lx", regs->trap); - print_symbol(" at %s\n", regs->nip); lr = regs->link; - print_symbol(" LR = %s\n", lr); + printk("--- Exception: %lx at %pS\n LR = %pS\n", + regs->trap, (void *)regs->nip, (void *)lr); firstframe = 1; } -- cgit v1.2.3 From 7c29217096d83f657e6ee70479af09b46f4275f6 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 11 Jul 2008 16:29:12 +1000 Subject: powerpc: fix giveup_vsx to save registers correctly giveup_vsx didn't save the FPU and VMX regsiters. Change it to be like giveup_fpr/altivec which save these registers. Also update call sites where FPU and VMX are already saved to use the original giveup_vsx (renamed to __giveup_vsx). Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/process.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/kernel/process.c') diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 0a4eb0811590..219f3634115e 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -159,6 +159,13 @@ void enable_kernel_vsx(void) EXPORT_SYMBOL(enable_kernel_vsx); #endif +void giveup_vsx(struct task_struct *tsk) +{ + giveup_fpu(tsk); + giveup_altivec(tsk); + __giveup_vsx(tsk); +} + void flush_vsx_to_thread(struct task_struct *tsk) { if (tsk->thread.regs) { @@ -290,7 +297,8 @@ struct task_struct *__switch_to(struct task_struct *prev, #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_VSX if (prev->thread.regs && (prev->thread.regs->msr & MSR_VSX)) - giveup_vsx(prev); + /* VMX and FPU registers are already save here */ + __giveup_vsx(prev); #endif /* CONFIG_VSX */ #ifdef CONFIG_SPE /* -- cgit v1.2.3