diff options
| -rw-r--r-- | arch/powerpc/include/asm/processor.h | 2 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/thread_info.h | 5 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/tm.h | 1 | ||||
| -rw-r--r-- | arch/powerpc/kernel/entry_64.S | 12 | ||||
| -rw-r--r-- | arch/powerpc/kernel/fpu.S | 16 | ||||
| -rw-r--r-- | arch/powerpc/kernel/process.c | 146 | ||||
| -rw-r--r-- | arch/powerpc/kernel/signal.c | 3 | ||||
| -rw-r--r-- | arch/powerpc/kernel/signal_32.c | 21 | ||||
| -rw-r--r-- | arch/powerpc/kernel/signal_64.c | 14 | ||||
| -rw-r--r-- | arch/powerpc/kernel/traps.c | 12 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vector.S | 10 |
11 files changed, 195 insertions, 47 deletions
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index fc14a38c7ccf..232a2fa5b483 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h | |||
| @@ -373,6 +373,8 @@ extern int set_endian(struct task_struct *tsk, unsigned int val); | |||
| 373 | extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr); | 373 | extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr); |
| 374 | extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); | 374 | extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); |
| 375 | 375 | ||
| 376 | extern void fp_enable(void); | ||
| 377 | extern void vec_enable(void); | ||
| 376 | extern void load_fp_state(struct thread_fp_state *fp); | 378 | extern void load_fp_state(struct thread_fp_state *fp); |
| 377 | extern void store_fp_state(struct thread_fp_state *fp); | 379 | extern void store_fp_state(struct thread_fp_state *fp); |
| 378 | extern void load_vr_state(struct thread_vr_state *vr); | 380 | extern void load_vr_state(struct thread_vr_state *vr); |
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index fc2bf414c584..b034ecdb7c74 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h | |||
| @@ -91,6 +91,7 @@ static inline struct thread_info *current_thread_info(void) | |||
| 91 | #define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling | 91 | #define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling |
| 92 | TIF_NEED_RESCHED */ | 92 | TIF_NEED_RESCHED */ |
| 93 | #define TIF_32BIT 4 /* 32 bit binary */ | 93 | #define TIF_32BIT 4 /* 32 bit binary */ |
| 94 | #define TIF_RESTORE_TM 5 /* need to restore TM FP/VEC/VSX */ | ||
| 94 | #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ | 95 | #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ |
| 95 | #define TIF_SINGLESTEP 8 /* singlestepping active */ | 96 | #define TIF_SINGLESTEP 8 /* singlestepping active */ |
| 96 | #define TIF_NOHZ 9 /* in adaptive nohz mode */ | 97 | #define TIF_NOHZ 9 /* in adaptive nohz mode */ |
| @@ -113,6 +114,7 @@ static inline struct thread_info *current_thread_info(void) | |||
| 113 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 114 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
| 114 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 115 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
| 115 | #define _TIF_32BIT (1<<TIF_32BIT) | 116 | #define _TIF_32BIT (1<<TIF_32BIT) |
| 117 | #define _TIF_RESTORE_TM (1<<TIF_RESTORE_TM) | ||
| 116 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | 118 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) |
| 117 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) | 119 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) |
| 118 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | 120 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) |
| @@ -128,7 +130,8 @@ static inline struct thread_info *current_thread_info(void) | |||
| 128 | _TIF_NOHZ) | 130 | _TIF_NOHZ) |
| 129 | 131 | ||
| 130 | #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ | 132 | #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ |
| 131 | _TIF_NOTIFY_RESUME | _TIF_UPROBE) | 133 | _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ |
| 134 | _TIF_RESTORE_TM) | ||
| 132 | #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR) | 135 | #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR) |
| 133 | 136 | ||
| 134 | /* Bits in local_flags */ | 137 | /* Bits in local_flags */ |
diff --git a/arch/powerpc/include/asm/tm.h b/arch/powerpc/include/asm/tm.h index 9dfbc34bdbf5..0c9f8b74dd97 100644 --- a/arch/powerpc/include/asm/tm.h +++ b/arch/powerpc/include/asm/tm.h | |||
| @@ -15,6 +15,7 @@ extern void do_load_up_transact_altivec(struct thread_struct *thread); | |||
| 15 | extern void tm_enable(void); | 15 | extern void tm_enable(void); |
| 16 | extern void tm_reclaim(struct thread_struct *thread, | 16 | extern void tm_reclaim(struct thread_struct *thread, |
| 17 | unsigned long orig_msr, uint8_t cause); | 17 | unsigned long orig_msr, uint8_t cause); |
| 18 | extern void tm_reclaim_current(uint8_t cause); | ||
| 18 | extern void tm_recheckpoint(struct thread_struct *thread, | 19 | extern void tm_recheckpoint(struct thread_struct *thread, |
| 19 | unsigned long orig_msr); | 20 | unsigned long orig_msr); |
| 20 | extern void tm_abort(uint8_t cause); | 21 | extern void tm_abort(uint8_t cause); |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index bbfb0294b354..662c6dd98072 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
| @@ -664,8 +664,16 @@ _GLOBAL(ret_from_except_lite) | |||
| 664 | bl .restore_interrupts | 664 | bl .restore_interrupts |
| 665 | SCHEDULE_USER | 665 | SCHEDULE_USER |
| 666 | b .ret_from_except_lite | 666 | b .ret_from_except_lite |
| 667 | 667 | 2: | |
| 668 | 2: bl .save_nvgprs | 668 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
| 669 | andi. r0,r4,_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM | ||
| 670 | bne 3f /* only restore TM if nothing else to do */ | ||
| 671 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
| 672 | bl .restore_tm_state | ||
| 673 | b restore | ||
| 674 | 3: | ||
| 675 | #endif | ||
| 676 | bl .save_nvgprs | ||
| 669 | bl .restore_interrupts | 677 | bl .restore_interrupts |
| 670 | addi r3,r1,STACK_FRAME_OVERHEAD | 678 | addi r3,r1,STACK_FRAME_OVERHEAD |
| 671 | bl .do_notify_resume | 679 | bl .do_notify_resume |
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index f7f5b8bed68f..9ad236e5d2c9 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S | |||
| @@ -81,6 +81,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) | |||
| 81 | #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ | 81 | #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ |
| 82 | 82 | ||
| 83 | /* | 83 | /* |
| 84 | * Enable use of the FPU, and VSX if possible, for the caller. | ||
| 85 | */ | ||
| 86 | _GLOBAL(fp_enable) | ||
| 87 | mfmsr r3 | ||
| 88 | ori r3,r3,MSR_FP | ||
| 89 | #ifdef CONFIG_VSX | ||
| 90 | BEGIN_FTR_SECTION | ||
| 91 | oris r3,r3,MSR_VSX@h | ||
| 92 | END_FTR_SECTION_IFSET(CPU_FTR_VSX) | ||
| 93 | #endif | ||
| 94 | SYNC | ||
| 95 | MTMSRD(r3) | ||
| 96 | isync /* (not necessary for arch 2.02 and later) */ | ||
| 97 | blr | ||
| 98 | |||
| 99 | /* | ||
| 84 | * Load state from memory into FP registers including FPSCR. | 100 | * Load state from memory into FP registers including FPSCR. |
| 85 | * Assumes the caller has enabled FP in the MSR. | 101 | * Assumes the caller has enabled FP in the MSR. |
| 86 | */ | 102 | */ |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index bf8e136316e2..3573d186505f 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
| @@ -73,6 +73,48 @@ struct task_struct *last_task_used_vsx = NULL; | |||
| 73 | struct task_struct *last_task_used_spe = NULL; | 73 | struct task_struct *last_task_used_spe = NULL; |
| 74 | #endif | 74 | #endif |
| 75 | 75 | ||
| 76 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
| 77 | void giveup_fpu_maybe_transactional(struct task_struct *tsk) | ||
| 78 | { | ||
| 79 | /* | ||
| 80 | * If we are saving the current thread's registers, and the | ||
| 81 | * thread is in a transactional state, set the TIF_RESTORE_TM | ||
| 82 | * bit so that we know to restore the registers before | ||
| 83 | * returning to userspace. | ||
| 84 | */ | ||
| 85 | if (tsk == current && tsk->thread.regs && | ||
| 86 | MSR_TM_ACTIVE(tsk->thread.regs->msr) && | ||
| 87 | !test_thread_flag(TIF_RESTORE_TM)) { | ||
| 88 | tsk->thread.tm_orig_msr = tsk->thread.regs->msr; | ||
| 89 | set_thread_flag(TIF_RESTORE_TM); | ||
| 90 | } | ||
| 91 | |||
| 92 | giveup_fpu(tsk); | ||
| 93 | } | ||
| 94 | |||
| 95 | void giveup_altivec_maybe_transactional(struct task_struct *tsk) | ||
| 96 | { | ||
| 97 | /* | ||
| 98 | * If we are saving the current thread's registers, and the | ||
| 99 | * thread is in a transactional state, set the TIF_RESTORE_TM | ||
| 100 | * bit so that we know to restore the registers before | ||
| 101 | * returning to userspace. | ||
| 102 | */ | ||
| 103 | if (tsk == current && tsk->thread.regs && | ||
| 104 | MSR_TM_ACTIVE(tsk->thread.regs->msr) && | ||
| 105 | !test_thread_flag(TIF_RESTORE_TM)) { | ||
| 106 | tsk->thread.tm_orig_msr = tsk->thread.regs->msr; | ||
| 107 | set_thread_flag(TIF_RESTORE_TM); | ||
| 108 | } | ||
| 109 | |||
| 110 | giveup_altivec(tsk); | ||
| 111 | } | ||
| 112 | |||
| 113 | #else | ||
| 114 | #define giveup_fpu_maybe_transactional(tsk) giveup_fpu(tsk) | ||
| 115 | #define giveup_altivec_maybe_transactional(tsk) giveup_altivec(tsk) | ||
| 116 | #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ | ||
| 117 | |||
| 76 | #ifdef CONFIG_PPC_FPU | 118 | #ifdef CONFIG_PPC_FPU |
| 77 | /* | 119 | /* |
| 78 | * Make sure the floating-point register state in the | 120 | * Make sure the floating-point register state in the |
| @@ -101,13 +143,13 @@ void flush_fp_to_thread(struct task_struct *tsk) | |||
| 101 | */ | 143 | */ |
| 102 | BUG_ON(tsk != current); | 144 | BUG_ON(tsk != current); |
| 103 | #endif | 145 | #endif |
| 104 | giveup_fpu(tsk); | 146 | giveup_fpu_maybe_transactional(tsk); |
| 105 | } | 147 | } |
| 106 | preempt_enable(); | 148 | preempt_enable(); |
| 107 | } | 149 | } |
| 108 | } | 150 | } |
| 109 | EXPORT_SYMBOL_GPL(flush_fp_to_thread); | 151 | EXPORT_SYMBOL_GPL(flush_fp_to_thread); |
| 110 | #endif | 152 | #endif /* CONFIG_PPC_FPU */ |
| 111 | 153 | ||
| 112 | void enable_kernel_fp(void) | 154 | void enable_kernel_fp(void) |
| 113 | { | 155 | { |
| @@ -115,11 +157,11 @@ void enable_kernel_fp(void) | |||
| 115 | 157 | ||
| 116 | #ifdef CONFIG_SMP | 158 | #ifdef CONFIG_SMP |
| 117 | if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) | 159 | if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) |
| 118 | giveup_fpu(current); | 160 | giveup_fpu_maybe_transactional(current); |
| 119 | else | 161 | else |
| 120 | giveup_fpu(NULL); /* just enables FP for kernel */ | 162 | giveup_fpu(NULL); /* just enables FP for kernel */ |
| 121 | #else | 163 | #else |
| 122 | giveup_fpu(last_task_used_math); | 164 | giveup_fpu_maybe_transactional(last_task_used_math); |
| 123 | #endif /* CONFIG_SMP */ | 165 | #endif /* CONFIG_SMP */ |
| 124 | } | 166 | } |
| 125 | EXPORT_SYMBOL(enable_kernel_fp); | 167 | EXPORT_SYMBOL(enable_kernel_fp); |
| @@ -131,11 +173,11 @@ void enable_kernel_altivec(void) | |||
| 131 | 173 | ||
| 132 | #ifdef CONFIG_SMP | 174 | #ifdef CONFIG_SMP |
| 133 | if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) | 175 | if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) |
| 134 | giveup_altivec(current); | 176 | giveup_altivec_maybe_transactional(current); |
| 135 | else | 177 | else |
| 136 | giveup_altivec_notask(); | 178 | giveup_altivec_notask(); |
| 137 | #else | 179 | #else |
| 138 | giveup_altivec(last_task_used_altivec); | 180 | giveup_altivec_maybe_transactional(last_task_used_altivec); |
| 139 | #endif /* CONFIG_SMP */ | 181 | #endif /* CONFIG_SMP */ |
| 140 | } | 182 | } |
| 141 | EXPORT_SYMBOL(enable_kernel_altivec); | 183 | EXPORT_SYMBOL(enable_kernel_altivec); |
| @@ -152,7 +194,7 @@ void flush_altivec_to_thread(struct task_struct *tsk) | |||
| 152 | #ifdef CONFIG_SMP | 194 | #ifdef CONFIG_SMP |
| 153 | BUG_ON(tsk != current); | 195 | BUG_ON(tsk != current); |
| 154 | #endif | 196 | #endif |
| 155 | giveup_altivec(tsk); | 197 | giveup_altivec_maybe_transactional(tsk); |
| 156 | } | 198 | } |
| 157 | preempt_enable(); | 199 | preempt_enable(); |
| 158 | } | 200 | } |
| @@ -181,8 +223,8 @@ EXPORT_SYMBOL(enable_kernel_vsx); | |||
| 181 | 223 | ||
| 182 | void giveup_vsx(struct task_struct *tsk) | 224 | void giveup_vsx(struct task_struct *tsk) |
| 183 | { | 225 | { |
| 184 | giveup_fpu(tsk); | 226 | giveup_fpu_maybe_transactional(tsk); |
| 185 | giveup_altivec(tsk); | 227 | giveup_altivec_maybe_transactional(tsk); |
| 186 | __giveup_vsx(tsk); | 228 | __giveup_vsx(tsk); |
| 187 | } | 229 | } |
| 188 | 230 | ||
| @@ -478,7 +520,48 @@ static inline bool hw_brk_match(struct arch_hw_breakpoint *a, | |||
| 478 | return false; | 520 | return false; |
| 479 | return true; | 521 | return true; |
| 480 | } | 522 | } |
| 523 | |||
| 481 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | 524 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
| 525 | static void tm_reclaim_thread(struct thread_struct *thr, | ||
| 526 | struct thread_info *ti, uint8_t cause) | ||
| 527 | { | ||
| 528 | unsigned long msr_diff = 0; | ||
| 529 | |||
| 530 | /* | ||
| 531 | * If FP/VSX registers have been already saved to the | ||
| 532 | * thread_struct, move them to the transact_fp array. | ||
| 533 | * We clear the TIF_RESTORE_TM bit since after the reclaim | ||
| 534 | * the thread will no longer be transactional. | ||
| 535 | */ | ||
| 536 | if (test_ti_thread_flag(ti, TIF_RESTORE_TM)) { | ||
| 537 | msr_diff = thr->tm_orig_msr & ~thr->regs->msr; | ||
| 538 | if (msr_diff & MSR_FP) | ||
| 539 | memcpy(&thr->transact_fp, &thr->fp_state, | ||
| 540 | sizeof(struct thread_fp_state)); | ||
| 541 | if (msr_diff & MSR_VEC) | ||
| 542 | memcpy(&thr->transact_vr, &thr->vr_state, | ||
| 543 | sizeof(struct thread_vr_state)); | ||
| 544 | clear_ti_thread_flag(ti, TIF_RESTORE_TM); | ||
| 545 | msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; | ||
| 546 | } | ||
| 547 | |||
| 548 | tm_reclaim(thr, thr->regs->msr, cause); | ||
| 549 | |||
| 550 | /* Having done the reclaim, we now have the checkpointed | ||
| 551 | * FP/VSX values in the registers. These might be valid | ||
| 552 | * even if we have previously called enable_kernel_fp() or | ||
| 553 | * flush_fp_to_thread(), so update thr->regs->msr to | ||
| 554 | * indicate their current validity. | ||
| 555 | */ | ||
| 556 | thr->regs->msr |= msr_diff; | ||
| 557 | } | ||
| 558 | |||
| 559 | void tm_reclaim_current(uint8_t cause) | ||
| 560 | { | ||
| 561 | tm_enable(); | ||
| 562 | tm_reclaim_thread(¤t->thread, current_thread_info(), cause); | ||
| 563 | } | ||
| 564 | |||
| 482 | static inline void tm_reclaim_task(struct task_struct *tsk) | 565 | static inline void tm_reclaim_task(struct task_struct *tsk) |
| 483 | { | 566 | { |
| 484 | /* We have to work out if we're switching from/to a task that's in the | 567 | /* We have to work out if we're switching from/to a task that's in the |
| @@ -501,9 +584,11 @@ static inline void tm_reclaim_task(struct task_struct *tsk) | |||
| 501 | 584 | ||
| 502 | /* Stash the original thread MSR, as giveup_fpu et al will | 585 | /* Stash the original thread MSR, as giveup_fpu et al will |
| 503 | * modify it. We hold onto it to see whether the task used | 586 | * modify it. We hold onto it to see whether the task used |
| 504 | * FP & vector regs. | 587 | * FP & vector regs. If the TIF_RESTORE_TM flag is set, |
| 588 | * tm_orig_msr is already set. | ||
| 505 | */ | 589 | */ |
| 506 | thr->tm_orig_msr = thr->regs->msr; | 590 | if (!test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_TM)) |
| 591 | thr->tm_orig_msr = thr->regs->msr; | ||
| 507 | 592 | ||
| 508 | TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, " | 593 | TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, " |
| 509 | "ccr=%lx, msr=%lx, trap=%lx)\n", | 594 | "ccr=%lx, msr=%lx, trap=%lx)\n", |
| @@ -511,7 +596,7 @@ static inline void tm_reclaim_task(struct task_struct *tsk) | |||
| 511 | thr->regs->ccr, thr->regs->msr, | 596 | thr->regs->ccr, thr->regs->msr, |
| 512 | thr->regs->trap); | 597 | thr->regs->trap); |
| 513 | 598 | ||
| 514 | tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED); | 599 | tm_reclaim_thread(thr, task_thread_info(tsk), TM_CAUSE_RESCHED); |
| 515 | 600 | ||
| 516 | TM_DEBUG("--- tm_reclaim on pid %d complete\n", | 601 | TM_DEBUG("--- tm_reclaim on pid %d complete\n", |
| 517 | tsk->pid); | 602 | tsk->pid); |
| @@ -587,6 +672,43 @@ static inline void __switch_to_tm(struct task_struct *prev) | |||
| 587 | tm_reclaim_task(prev); | 672 | tm_reclaim_task(prev); |
| 588 | } | 673 | } |
| 589 | } | 674 | } |
| 675 | |||
| 676 | /* | ||
| 677 | * This is called if we are on the way out to userspace and the | ||
| 678 | * TIF_RESTORE_TM flag is set. It checks if we need to reload | ||
| 679 | * FP and/or vector state and does so if necessary. | ||
| 680 | * If userspace is inside a transaction (whether active or | ||
| 681 | * suspended) and FP/VMX/VSX instructions have ever been enabled | ||
| 682 | * inside that transaction, then we have to keep them enabled | ||
| 683 | * and keep the FP/VMX/VSX state loaded while ever the transaction | ||
| 684 | * continues. The reason is that if we didn't, and subsequently | ||
| 685 | * got a FP/VMX/VSX unavailable interrupt inside a transaction, | ||
| 686 | * we don't know whether it's the same transaction, and thus we | ||
| 687 | * don't know which of the checkpointed state and the transactional | ||
| 688 | * state to use. | ||
| 689 | */ | ||
| 690 | void restore_tm_state(struct pt_regs *regs) | ||
| 691 | { | ||
| 692 | unsigned long msr_diff; | ||
| 693 | |||
| 694 | clear_thread_flag(TIF_RESTORE_TM); | ||
| 695 | if (!MSR_TM_ACTIVE(regs->msr)) | ||
| 696 | return; | ||
| 697 | |||
| 698 | msr_diff = current->thread.tm_orig_msr & ~regs->msr; | ||
| 699 | msr_diff &= MSR_FP | MSR_VEC | MSR_VSX; | ||
| 700 | if (msr_diff & MSR_FP) { | ||
| 701 | fp_enable(); | ||
| 702 | load_fp_state(¤t->thread.fp_state); | ||
| 703 | regs->msr |= current->thread.fpexc_mode; | ||
| 704 | } | ||
| 705 | if (msr_diff & MSR_VEC) { | ||
| 706 | vec_enable(); | ||
| 707 | load_vr_state(¤t->thread.vr_state); | ||
| 708 | } | ||
| 709 | regs->msr |= msr_diff; | ||
| 710 | } | ||
| 711 | |||
| 590 | #else | 712 | #else |
| 591 | #define tm_recheckpoint_new_task(new) | 713 | #define tm_recheckpoint_new_task(new) |
| 592 | #define __switch_to_tm(prev) | 714 | #define __switch_to_tm(prev) |
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 457e97aa2945..8fc4177ed65a 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
| @@ -203,8 +203,7 @@ unsigned long get_tm_stackpointer(struct pt_regs *regs) | |||
| 203 | 203 | ||
| 204 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | 204 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
| 205 | if (MSR_TM_ACTIVE(regs->msr)) { | 205 | if (MSR_TM_ACTIVE(regs->msr)) { |
| 206 | tm_enable(); | 206 | tm_reclaim_current(TM_CAUSE_SIGNAL); |
| 207 | tm_reclaim(¤t->thread, regs->msr, TM_CAUSE_SIGNAL); | ||
| 208 | if (MSR_TM_TRANSACTIONAL(regs->msr)) | 207 | if (MSR_TM_TRANSACTIONAL(regs->msr)) |
| 209 | return current->thread.ckpt_regs.gpr[1]; | 208 | return current->thread.ckpt_regs.gpr[1]; |
| 210 | } | 209 | } |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 68027bfa5f8e..6ce69e6f1fcb 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
| @@ -519,6 +519,13 @@ static int save_tm_user_regs(struct pt_regs *regs, | |||
| 519 | { | 519 | { |
| 520 | unsigned long msr = regs->msr; | 520 | unsigned long msr = regs->msr; |
| 521 | 521 | ||
| 522 | /* Remove TM bits from thread's MSR. The MSR in the sigcontext | ||
| 523 | * just indicates to userland that we were doing a transaction, but we | ||
| 524 | * don't want to return in transactional state. This also ensures | ||
| 525 | * that flush_fp_to_thread won't set TIF_RESTORE_TM again. | ||
| 526 | */ | ||
| 527 | regs->msr &= ~MSR_TS_MASK; | ||
| 528 | |||
| 522 | /* Make sure floating point registers are stored in regs */ | 529 | /* Make sure floating point registers are stored in regs */ |
| 523 | flush_fp_to_thread(current); | 530 | flush_fp_to_thread(current); |
| 524 | 531 | ||
| @@ -1056,13 +1063,6 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, | |||
| 1056 | /* enter the signal handler in native-endian mode */ | 1063 | /* enter the signal handler in native-endian mode */ |
| 1057 | regs->msr &= ~MSR_LE; | 1064 | regs->msr &= ~MSR_LE; |
| 1058 | regs->msr |= (MSR_KERNEL & MSR_LE); | 1065 | regs->msr |= (MSR_KERNEL & MSR_LE); |
| 1059 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
| 1060 | /* Remove TM bits from thread's MSR. The MSR in the sigcontext | ||
| 1061 | * just indicates to userland that we were doing a transaction, but we | ||
| 1062 | * don't want to return in transactional state: | ||
| 1063 | */ | ||
| 1064 | regs->msr &= ~MSR_TS_MASK; | ||
| 1065 | #endif | ||
| 1066 | return 1; | 1066 | return 1; |
| 1067 | 1067 | ||
| 1068 | badframe: | 1068 | badframe: |
| @@ -1484,13 +1484,6 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, | |||
| 1484 | regs->nip = (unsigned long) ka->sa.sa_handler; | 1484 | regs->nip = (unsigned long) ka->sa.sa_handler; |
| 1485 | /* enter the signal handler in big-endian mode */ | 1485 | /* enter the signal handler in big-endian mode */ |
| 1486 | regs->msr &= ~MSR_LE; | 1486 | regs->msr &= ~MSR_LE; |
| 1487 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
| 1488 | /* Remove TM bits from thread's MSR. The MSR in the sigcontext | ||
| 1489 | * just indicates to userland that we were doing a transaction, but we | ||
| 1490 | * don't want to return in transactional state: | ||
| 1491 | */ | ||
| 1492 | regs->msr &= ~MSR_TS_MASK; | ||
| 1493 | #endif | ||
| 1494 | return 1; | 1487 | return 1; |
| 1495 | 1488 | ||
| 1496 | badframe: | 1489 | badframe: |
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 42991045349f..e35bf773df7a 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
| @@ -192,6 +192,13 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, | |||
| 192 | 192 | ||
| 193 | BUG_ON(!MSR_TM_ACTIVE(regs->msr)); | 193 | BUG_ON(!MSR_TM_ACTIVE(regs->msr)); |
| 194 | 194 | ||
| 195 | /* Remove TM bits from thread's MSR. The MSR in the sigcontext | ||
| 196 | * just indicates to userland that we were doing a transaction, but we | ||
| 197 | * don't want to return in transactional state. This also ensures | ||
| 198 | * that flush_fp_to_thread won't set TIF_RESTORE_TM again. | ||
| 199 | */ | ||
| 200 | regs->msr &= ~MSR_TS_MASK; | ||
| 201 | |||
| 195 | flush_fp_to_thread(current); | 202 | flush_fp_to_thread(current); |
| 196 | 203 | ||
| 197 | #ifdef CONFIG_ALTIVEC | 204 | #ifdef CONFIG_ALTIVEC |
| @@ -749,13 +756,6 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
| 749 | 756 | ||
| 750 | /* Make sure signal handler doesn't get spurious FP exceptions */ | 757 | /* Make sure signal handler doesn't get spurious FP exceptions */ |
| 751 | current->thread.fp_state.fpscr = 0; | 758 | current->thread.fp_state.fpscr = 0; |
| 752 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
| 753 | /* Remove TM bits from thread's MSR. The MSR in the sigcontext | ||
| 754 | * just indicates to userland that we were doing a transaction, but we | ||
| 755 | * don't want to return in transactional state: | ||
| 756 | */ | ||
| 757 | regs->msr &= ~MSR_TS_MASK; | ||
| 758 | #endif | ||
| 759 | 759 | ||
| 760 | /* Set up to return from userspace. */ | 760 | /* Set up to return from userspace. */ |
| 761 | if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { | 761 | if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 330841766b09..26e1358ff0bc 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
| @@ -1399,7 +1399,6 @@ void fp_unavailable_tm(struct pt_regs *regs) | |||
| 1399 | 1399 | ||
| 1400 | TM_DEBUG("FP Unavailable trap whilst transactional at 0x%lx, MSR=%lx\n", | 1400 | TM_DEBUG("FP Unavailable trap whilst transactional at 0x%lx, MSR=%lx\n", |
| 1401 | regs->nip, regs->msr); | 1401 | regs->nip, regs->msr); |
| 1402 | tm_enable(); | ||
| 1403 | 1402 | ||
| 1404 | /* We can only have got here if the task started using FP after | 1403 | /* We can only have got here if the task started using FP after |
| 1405 | * beginning the transaction. So, the transactional regs are just a | 1404 | * beginning the transaction. So, the transactional regs are just a |
| @@ -1408,8 +1407,7 @@ void fp_unavailable_tm(struct pt_regs *regs) | |||
| 1408 | * transaction, and probably retry but now with FP enabled. So the | 1407 | * transaction, and probably retry but now with FP enabled. So the |
| 1409 | * checkpointed FP registers need to be loaded. | 1408 | * checkpointed FP registers need to be loaded. |
| 1410 | */ | 1409 | */ |
| 1411 | tm_reclaim(¤t->thread, current->thread.regs->msr, | 1410 | tm_reclaim_current(TM_CAUSE_FAC_UNAV); |
| 1412 | TM_CAUSE_FAC_UNAV); | ||
| 1413 | /* Reclaim didn't save out any FPRs to transact_fprs. */ | 1411 | /* Reclaim didn't save out any FPRs to transact_fprs. */ |
| 1414 | 1412 | ||
| 1415 | /* Enable FP for the task: */ | 1413 | /* Enable FP for the task: */ |
| @@ -1432,9 +1430,7 @@ void altivec_unavailable_tm(struct pt_regs *regs) | |||
| 1432 | TM_DEBUG("Vector Unavailable trap whilst transactional at 0x%lx," | 1430 | TM_DEBUG("Vector Unavailable trap whilst transactional at 0x%lx," |
| 1433 | "MSR=%lx\n", | 1431 | "MSR=%lx\n", |
| 1434 | regs->nip, regs->msr); | 1432 | regs->nip, regs->msr); |
| 1435 | tm_enable(); | 1433 | tm_reclaim_current(TM_CAUSE_FAC_UNAV); |
| 1436 | tm_reclaim(¤t->thread, current->thread.regs->msr, | ||
| 1437 | TM_CAUSE_FAC_UNAV); | ||
| 1438 | regs->msr |= MSR_VEC; | 1434 | regs->msr |= MSR_VEC; |
| 1439 | tm_recheckpoint(¤t->thread, regs->msr); | 1435 | tm_recheckpoint(¤t->thread, regs->msr); |
| 1440 | current->thread.used_vr = 1; | 1436 | current->thread.used_vr = 1; |
| @@ -1455,10 +1451,8 @@ void vsx_unavailable_tm(struct pt_regs *regs) | |||
| 1455 | "MSR=%lx\n", | 1451 | "MSR=%lx\n", |
| 1456 | regs->nip, regs->msr); | 1452 | regs->nip, regs->msr); |
| 1457 | 1453 | ||
| 1458 | tm_enable(); | ||
| 1459 | /* This reclaims FP and/or VR regs if they're already enabled */ | 1454 | /* This reclaims FP and/or VR regs if they're already enabled */ |
| 1460 | tm_reclaim(¤t->thread, current->thread.regs->msr, | 1455 | tm_reclaim_current(TM_CAUSE_FAC_UNAV); |
| 1461 | TM_CAUSE_FAC_UNAV); | ||
| 1462 | 1456 | ||
| 1463 | regs->msr |= MSR_VEC | MSR_FP | current->thread.fpexc_mode | | 1457 | regs->msr |= MSR_VEC | MSR_FP | current->thread.fpexc_mode | |
| 1464 | MSR_VSX; | 1458 | MSR_VSX; |
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 0458a9aaba9d..74f8050518d6 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S | |||
| @@ -37,6 +37,16 @@ _GLOBAL(do_load_up_transact_altivec) | |||
| 37 | #endif | 37 | #endif |
| 38 | 38 | ||
| 39 | /* | 39 | /* |
| 40 | * Enable use of VMX/Altivec for the caller. | ||
| 41 | */ | ||
| 42 | _GLOBAL(vec_enable) | ||
| 43 | mfmsr r3 | ||
| 44 | oris r3,r3,MSR_VEC@h | ||
| 45 | MTMSRD(r3) | ||
| 46 | isync | ||
| 47 | blr | ||
| 48 | |||
| 49 | /* | ||
| 40 | * Load state from memory into VMX registers including VSCR. | 50 | * Load state from memory into VMX registers including VSCR. |
| 41 | * Assumes the caller has enabled VMX in the MSR. | 51 | * Assumes the caller has enabled VMX in the MSR. |
| 42 | */ | 52 | */ |
