Merge tag 'v3.10.103' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / powerpc / kernel / process.c
index 076d1242507a7fdcf32c374b66b3b005eb4e0db9..a5e339806589d1bfe283f6d87346b3ca354d18a4 100644 (file)
@@ -523,6 +523,31 @@ out_and_saveregs:
        tm_save_sprs(thr);
 }
 
+extern void __tm_recheckpoint(struct thread_struct *thread,
+                             unsigned long orig_msr);
+
+void tm_recheckpoint(struct thread_struct *thread,
+                    unsigned long orig_msr)
+{
+       unsigned long flags;
+
+       /* We really can't be interrupted here as the TEXASR registers can't
+        * change and later in the trecheckpoint code, we have a userspace R1.
+        * So let's hard disable over this region.
+        */
+       local_irq_save(flags);
+       hard_irq_disable();
+
+       /* The TM SPRs are restored here, so that TEXASR.FS can be set
+        * before the trecheckpoint and no explosion occurs.
+        */
+       tm_restore_sprs(thread);
+
+       __tm_recheckpoint(thread, orig_msr);
+
+       local_irq_restore(flags);
+}
+
 static inline void tm_recheckpoint_new_task(struct task_struct *new)
 {
        unsigned long msr;
@@ -541,13 +566,10 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new)
        if (!new->thread.regs)
                return;
 
-       /* The TM SPRs are restored here, so that TEXASR.FS can be set
-        * before the trecheckpoint and no explosion occurs.
-        */
-       tm_restore_sprs(&new->thread);
-
-       if (!MSR_TM_ACTIVE(new->thread.regs->msr))
+       if (!MSR_TM_ACTIVE(new->thread.regs->msr)){
+               tm_restore_sprs(&new->thread);
                return;
+       }
        msr = new->thread.tm_orig_msr;
        /* Recheckpoint to restore original checkpointed register state. */
        TM_DEBUG("*** tm_recheckpoint of pid %d "
@@ -600,6 +622,16 @@ struct task_struct *__switch_to(struct task_struct *prev,
        struct ppc64_tlb_batch *batch;
 #endif
 
+       /* Back up the TAR across context switches.
+        * Note that the TAR is not available for use in the kernel.  (To
+        * provide this, the TAR should be backed up/restored on exception
+        * entry/exit instead, and be in pt_regs.  FIXME, this should be in
+        * pt_regs anyway (for debug).)
+        * Save the TAR here before we do treclaim/trecheckpoint as these
+        * will change the TAR.
+        */
+       save_tar(&prev->thread);
+
        __switch_to_tm(prev);
 
 #ifdef CONFIG_SMP
@@ -916,6 +948,16 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
        flush_altivec_to_thread(src);
        flush_vsx_to_thread(src);
        flush_spe_to_thread(src);
+       /*
+       * Flush TM state out so we can copy it.  __switch_to_tm() does this
+       * flush but it removes the checkpointed state from the current CPU and
+       * transitions the CPU out of TM mode.  Hence we need to call
+       * tm_recheckpoint_new_task() (on the same task) to restore the
+       * checkpointed state back and the TM mode.
+       */
+       __switch_to_tm(src);
+       tm_recheckpoint_new_task(src);
+
        *dst = *src;
        return 0;
 }
@@ -1046,6 +1088,16 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
                current->thread.regs = regs - 1;
        }
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       /*
+        * Clear any transactional state, we're exec()ing. The cause is
+        * not important as there will never be a recheckpoint so it's not
+        * user visible.
+        */
+       if (MSR_TM_SUSPENDED(mfmsr()))
+               tm_reclaim_current(0);
+#endif
+
        memset(regs->gpr, 0, sizeof(regs->gpr));
        regs->ctr = 0;
        regs->link = 0;