powerpc: Improve FSCR init and context switching
authorMichael Neuling <mikey@neuling.org>
Thu, 9 Jun 2016 02:31:08 +0000 (12:31 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 21 Jun 2016 05:30:50 +0000 (15:30 +1000)
This fixes a few issues with FSCR init and switching.

In commit 152d523e6307 ("powerpc: Create context switch helpers
save_sprs() and restore_sprs()") we moved the setting of the FSCR
register from inside an CPU_FTR_ARCH_207S section to inside just a
CPU_FTR_ARCH_DSCR section. Hence we are setting FSCR on POWER6/7 where
the FSCR doesn't exist. This is harmless but we shouldn't do it.

Also, we can simplify the FSCR context switch. We don't need to go
through the calculation involving dscr_inherit. We can just restore
what we saved last time.

We also set an initial value in INIT_THREAD, so that pid 1 which is
cloned from that gets a sane value.

Based on patch by Jack Miller.

Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/processor.h
arch/powerpc/kernel/process.c
arch/powerpc/kernel/traps.c

index c0c27bdbb0690096d590dc0256a6346d20b0de5a..f6b1a5f51d0577caf0e918a529875dab08f62b74 100644 (file)
@@ -347,6 +347,7 @@ struct thread_struct {
        .fs = KERNEL_DS, \
        .fpexc_mode = 0, \
        .ppr = INIT_PPR, \
+       .fscr = FSCR_TAR | FSCR_EBB \
 }
 #endif
 
index c5c3ae2ef3c10258418a2c45b62ef21634b8560d..6d0a831bc7d8e70a110c17dbd7a9c08168ee0463 100644 (file)
@@ -1031,18 +1031,11 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 #ifdef CONFIG_PPC_BOOK3S_64
        if (cpu_has_feature(CPU_FTR_DSCR)) {
                u64 dscr = get_paca()->dscr_default;
-               u64 fscr = old_thread->fscr & ~FSCR_DSCR;
-
-               if (new_thread->dscr_inherit) {
+               if (new_thread->dscr_inherit)
                        dscr = new_thread->dscr;
-                       fscr |= FSCR_DSCR;
-               }
 
                if (old_thread->dscr != dscr)
                        mtspr(SPRN_DSCR, dscr);
-
-               if (old_thread->fscr != fscr)
-                       mtspr(SPRN_FSCR, fscr);
        }
 
        if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
@@ -1053,6 +1046,9 @@ static inline void restore_sprs(struct thread_struct *old_thread,
                if (old_thread->ebbrr != new_thread->ebbrr)
                        mtspr(SPRN_EBBRR, new_thread->ebbrr);
 
+               if (old_thread->fscr != new_thread->fscr)
+                       mtspr(SPRN_FSCR, new_thread->fscr);
+
                if (old_thread->tar != new_thread->tar)
                        mtspr(SPRN_TAR, new_thread->tar);
        }
index 11d15e7270e0a3be2d1bf0b12776a3217d569179..d2518c3cbf040c6eff22edc0ae9ce38e9a7dad77 100644 (file)
@@ -1419,7 +1419,8 @@ void facility_unavailable_exception(struct pt_regs *regs)
                        rd = (instword >> 21) & 0x1f;
                        current->thread.dscr = regs->gpr[rd];
                        current->thread.dscr_inherit = 1;
-                       mtspr(SPRN_FSCR, value | FSCR_DSCR);
+                       current->thread.fscr |= FSCR_DSCR;
+                       mtspr(SPRN_FSCR, current->thread.fscr);
                }
 
                /* Read from DSCR (mfspr RT, 0x03) */