diff options
Diffstat (limited to 'arch/powerpc/kernel/process.c')
-rw-r--r-- | arch/powerpc/kernel/process.c | 113 |
1 files changed, 61 insertions, 52 deletions
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 7de41c3948ec..219f3634115e 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 |
54 | struct task_struct *last_task_used_math = NULL; | 54 | struct task_struct *last_task_used_math = NULL; |
55 | struct task_struct *last_task_used_altivec = NULL; | 55 | struct task_struct *last_task_used_altivec = NULL; |
56 | struct task_struct *last_task_used_vsx = NULL; | ||
56 | struct task_struct *last_task_used_spe = NULL; | 57 | struct task_struct *last_task_used_spe = NULL; |
57 | #endif | 58 | #endif |
58 | 59 | ||
@@ -104,17 +105,6 @@ void enable_kernel_fp(void) | |||
104 | } | 105 | } |
105 | EXPORT_SYMBOL(enable_kernel_fp); | 106 | EXPORT_SYMBOL(enable_kernel_fp); |
106 | 107 | ||
107 | int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) | ||
108 | { | ||
109 | if (!tsk->thread.regs) | ||
110 | return 0; | ||
111 | flush_fp_to_thread(current); | ||
112 | |||
113 | memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); | ||
114 | |||
115 | return 1; | ||
116 | } | ||
117 | |||
118 | #ifdef CONFIG_ALTIVEC | 108 | #ifdef CONFIG_ALTIVEC |
119 | void enable_kernel_altivec(void) | 109 | void enable_kernel_altivec(void) |
120 | { | 110 | { |
@@ -148,36 +138,48 @@ void flush_altivec_to_thread(struct task_struct *tsk) | |||
148 | preempt_enable(); | 138 | preempt_enable(); |
149 | } | 139 | } |
150 | } | 140 | } |
141 | #endif /* CONFIG_ALTIVEC */ | ||
151 | 142 | ||
152 | int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs) | 143 | #ifdef CONFIG_VSX |
144 | #if 0 | ||
145 | /* not currently used, but some crazy RAID module might want to later */ | ||
146 | void enable_kernel_vsx(void) | ||
153 | { | 147 | { |
154 | /* ELF_NVRREG includes the VSCR and VRSAVE which we need to save | 148 | WARN_ON(preemptible()); |
155 | * separately, see below */ | ||
156 | const int nregs = ELF_NVRREG - 2; | ||
157 | elf_vrreg_t *reg; | ||
158 | u32 *dest; | ||
159 | |||
160 | if (tsk == current) | ||
161 | flush_altivec_to_thread(tsk); | ||
162 | |||
163 | reg = (elf_vrreg_t *)vrregs; | ||
164 | |||
165 | /* copy the 32 vr registers */ | ||
166 | memcpy(reg, &tsk->thread.vr[0], nregs * sizeof(*reg)); | ||
167 | reg += nregs; | ||
168 | 149 | ||
169 | /* copy the vscr */ | 150 | #ifdef CONFIG_SMP |
170 | memcpy(reg, &tsk->thread.vscr, sizeof(*reg)); | 151 | if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) |
171 | reg++; | 152 | giveup_vsx(current); |
153 | else | ||
154 | giveup_vsx(NULL); /* just enable vsx for kernel - force */ | ||
155 | #else | ||
156 | giveup_vsx(last_task_used_vsx); | ||
157 | #endif /* CONFIG_SMP */ | ||
158 | } | ||
159 | EXPORT_SYMBOL(enable_kernel_vsx); | ||
160 | #endif | ||
172 | 161 | ||
173 | /* vrsave is stored in the high 32bit slot of the final 128bits */ | 162 | void giveup_vsx(struct task_struct *tsk) |
174 | memset(reg, 0, sizeof(*reg)); | 163 | { |
175 | dest = (u32 *)reg; | 164 | giveup_fpu(tsk); |
176 | *dest = tsk->thread.vrsave; | 165 | giveup_altivec(tsk); |
166 | __giveup_vsx(tsk); | ||
167 | } | ||
177 | 168 | ||
178 | return 1; | 169 | void flush_vsx_to_thread(struct task_struct *tsk) |
170 | { | ||
171 | if (tsk->thread.regs) { | ||
172 | preempt_disable(); | ||
173 | if (tsk->thread.regs->msr & MSR_VSX) { | ||
174 | #ifdef CONFIG_SMP | ||
175 | BUG_ON(tsk != current); | ||
176 | #endif | ||
177 | giveup_vsx(tsk); | ||
178 | } | ||
179 | preempt_enable(); | ||
180 | } | ||
179 | } | 181 | } |
180 | #endif /* CONFIG_ALTIVEC */ | 182 | #endif /* CONFIG_VSX */ |
181 | 183 | ||
182 | #ifdef CONFIG_SPE | 184 | #ifdef CONFIG_SPE |
183 | 185 | ||
@@ -209,14 +211,6 @@ void flush_spe_to_thread(struct task_struct *tsk) | |||
209 | preempt_enable(); | 211 | preempt_enable(); |
210 | } | 212 | } |
211 | } | 213 | } |
212 | |||
213 | int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs) | ||
214 | { | ||
215 | flush_spe_to_thread(current); | ||
216 | /* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */ | ||
217 | memcpy(evrregs, ¤t->thread.evr[0], sizeof(u32) * 35); | ||
218 | return 1; | ||
219 | } | ||
220 | #endif /* CONFIG_SPE */ | 214 | #endif /* CONFIG_SPE */ |
221 | 215 | ||
222 | #ifndef CONFIG_SMP | 216 | #ifndef CONFIG_SMP |
@@ -233,6 +227,10 @@ void discard_lazy_cpu_state(void) | |||
233 | if (last_task_used_altivec == current) | 227 | if (last_task_used_altivec == current) |
234 | last_task_used_altivec = NULL; | 228 | last_task_used_altivec = NULL; |
235 | #endif /* CONFIG_ALTIVEC */ | 229 | #endif /* CONFIG_ALTIVEC */ |
230 | #ifdef CONFIG_VSX | ||
231 | if (last_task_used_vsx == current) | ||
232 | last_task_used_vsx = NULL; | ||
233 | #endif /* CONFIG_VSX */ | ||
236 | #ifdef CONFIG_SPE | 234 | #ifdef CONFIG_SPE |
237 | if (last_task_used_spe == current) | 235 | if (last_task_used_spe == current) |
238 | last_task_used_spe = NULL; | 236 | last_task_used_spe = NULL; |
@@ -297,6 +295,11 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
297 | if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) | 295 | if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) |
298 | giveup_altivec(prev); | 296 | giveup_altivec(prev); |
299 | #endif /* CONFIG_ALTIVEC */ | 297 | #endif /* CONFIG_ALTIVEC */ |
298 | #ifdef CONFIG_VSX | ||
299 | if (prev->thread.regs && (prev->thread.regs->msr & MSR_VSX)) | ||
300 | /* VMX and FPU registers are already save here */ | ||
301 | __giveup_vsx(prev); | ||
302 | #endif /* CONFIG_VSX */ | ||
300 | #ifdef CONFIG_SPE | 303 | #ifdef CONFIG_SPE |
301 | /* | 304 | /* |
302 | * If the previous thread used spe in the last quantum | 305 | * If the previous thread used spe in the last quantum |
@@ -317,6 +320,10 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
317 | if (new->thread.regs && last_task_used_altivec == new) | 320 | if (new->thread.regs && last_task_used_altivec == new) |
318 | new->thread.regs->msr |= MSR_VEC; | 321 | new->thread.regs->msr |= MSR_VEC; |
319 | #endif /* CONFIG_ALTIVEC */ | 322 | #endif /* CONFIG_ALTIVEC */ |
323 | #ifdef CONFIG_VSX | ||
324 | if (new->thread.regs && last_task_used_vsx == new) | ||
325 | new->thread.regs->msr |= MSR_VSX; | ||
326 | #endif /* CONFIG_VSX */ | ||
320 | #ifdef CONFIG_SPE | 327 | #ifdef CONFIG_SPE |
321 | /* Avoid the trap. On smp this this never happens since | 328 | /* Avoid the trap. On smp this this never happens since |
322 | * we don't set last_task_used_spe | 329 | * we don't set last_task_used_spe |
@@ -417,6 +424,8 @@ static struct regbit { | |||
417 | {MSR_EE, "EE"}, | 424 | {MSR_EE, "EE"}, |
418 | {MSR_PR, "PR"}, | 425 | {MSR_PR, "PR"}, |
419 | {MSR_FP, "FP"}, | 426 | {MSR_FP, "FP"}, |
427 | {MSR_VEC, "VEC"}, | ||
428 | {MSR_VSX, "VSX"}, | ||
420 | {MSR_ME, "ME"}, | 429 | {MSR_ME, "ME"}, |
421 | {MSR_IR, "IR"}, | 430 | {MSR_IR, "IR"}, |
422 | {MSR_DR, "DR"}, | 431 | {MSR_DR, "DR"}, |
@@ -484,10 +493,8 @@ void show_regs(struct pt_regs * regs) | |||
484 | * Lookup NIP late so we have the best change of getting the | 493 | * Lookup NIP late so we have the best change of getting the |
485 | * above info out without failing | 494 | * above info out without failing |
486 | */ | 495 | */ |
487 | printk("NIP ["REG"] ", regs->nip); | 496 | printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip); |
488 | print_symbol("%s\n", regs->nip); | 497 | printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link); |
489 | printk("LR ["REG"] ", regs->link); | ||
490 | print_symbol("%s\n", regs->link); | ||
491 | #endif | 498 | #endif |
492 | show_stack(current, (unsigned long *) regs->gpr[1]); | 499 | show_stack(current, (unsigned long *) regs->gpr[1]); |
493 | if (!user_mode(regs)) | 500 | if (!user_mode(regs)) |
@@ -534,6 +541,7 @@ void prepare_to_copy(struct task_struct *tsk) | |||
534 | { | 541 | { |
535 | flush_fp_to_thread(current); | 542 | flush_fp_to_thread(current); |
536 | flush_altivec_to_thread(current); | 543 | flush_altivec_to_thread(current); |
544 | flush_vsx_to_thread(current); | ||
537 | flush_spe_to_thread(current); | 545 | flush_spe_to_thread(current); |
538 | } | 546 | } |
539 | 547 | ||
@@ -689,6 +697,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) | |||
689 | #endif | 697 | #endif |
690 | 698 | ||
691 | discard_lazy_cpu_state(); | 699 | discard_lazy_cpu_state(); |
700 | #ifdef CONFIG_VSX | ||
701 | current->thread.used_vsr = 0; | ||
702 | #endif | ||
692 | memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); | 703 | memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); |
693 | current->thread.fpscr.val = 0; | 704 | current->thread.fpscr.val = 0; |
694 | #ifdef CONFIG_ALTIVEC | 705 | #ifdef CONFIG_ALTIVEC |
@@ -971,8 +982,7 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) | |||
971 | newsp = stack[0]; | 982 | newsp = stack[0]; |
972 | ip = stack[STACK_FRAME_LR_SAVE]; | 983 | ip = stack[STACK_FRAME_LR_SAVE]; |
973 | if (!firstframe || ip != lr) { | 984 | if (!firstframe || ip != lr) { |
974 | printk("["REG"] ["REG"] ", sp, ip); | 985 | printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip); |
975 | print_symbol("%s", ip); | ||
976 | if (firstframe) | 986 | if (firstframe) |
977 | printk(" (unreliable)"); | 987 | printk(" (unreliable)"); |
978 | printk("\n"); | 988 | printk("\n"); |
@@ -987,10 +997,9 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) | |||
987 | && stack[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) { | 997 | && stack[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) { |
988 | struct pt_regs *regs = (struct pt_regs *) | 998 | struct pt_regs *regs = (struct pt_regs *) |
989 | (sp + STACK_FRAME_OVERHEAD); | 999 | (sp + STACK_FRAME_OVERHEAD); |
990 | printk("--- Exception: %lx", regs->trap); | ||
991 | print_symbol(" at %s\n", regs->nip); | ||
992 | lr = regs->link; | 1000 | lr = regs->link; |
993 | print_symbol(" LR = %s\n", lr); | 1001 | printk("--- Exception: %lx at %pS\n LR = %pS\n", |
1002 | regs->trap, (void *)regs->nip, (void *)lr); | ||
994 | firstframe = 1; | 1003 | firstframe = 1; |
995 | } | 1004 | } |
996 | 1005 | ||