powerpc: Load Monitor Register Support
authorJack Miller <jack@codezen.org>
Thu, 9 Jun 2016 02:31:09 +0000 (12:31 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 21 Jun 2016 05:30:50 +0000 (15:30 +1000)
This enables new registers, LMRR and LMSER, that can trigger an EBB in
userspace code when a monitored load (via the new ldmx instruction)
loads memory from a monitored space. This facility is controlled by a
new FSCR bit, LM.

This patch disables the FSCR LM control bit on task init and enables
that bit when a load monitor facility unavailable exception is taken
for using it. On context switch, this bit is then used to determine
whether the two relevant registers are saved and restored. This is
done lazily for performance reasons.

Signed-off-by: Jack Miller <jack@codezen.org>
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/include/asm/reg.h
arch/powerpc/kernel/process.c
arch/powerpc/kernel/traps.c

index f6b1a5f51d0577caf0e918a529875dab08f62b74..b5925d5d498517c27c002cb6a17c35ef732e0810 100644 (file)
@@ -314,6 +314,8 @@ struct thread_struct {
        unsigned long   mmcr2;
        unsigned        mmcr0;
        unsigned        used_ebb;
+       unsigned long   lmrr;
+       unsigned long   lmser;
 #endif
 };
 
index a0948f40bc7bc96d60cf15d93fd252ef6d3d01f4..ce44fe27f48fd3f17188fd2bdd5907dca2448d46 100644 (file)
 #define SPRN_HRMOR     0x139   /* Real mode offset register */
 #define SPRN_HSRR0     0x13A   /* Hypervisor Save/Restore 0 */
 #define SPRN_HSRR1     0x13B   /* Hypervisor Save/Restore 1 */
+#define SPRN_LMRR      0x32D   /* Load Monitor Region Register */
+#define SPRN_LMSER     0x32E   /* Load Monitor Section Enable Register */
 #define SPRN_IC                0x350   /* Virtual Instruction Count */
 #define SPRN_VTB       0x351   /* Virtual Time Base */
 #define SPRN_LDBAR     0x352   /* LD Base Address Register */
 #define SPRN_PMCR      0x374   /* Power Management Control Register */
 
 /* HFSCR and FSCR bit numbers are the same */
+#define FSCR_LM_LG     11      /* Enable Load Monitor Registers */
 #define FSCR_TAR_LG    8       /* Enable Target Address Register */
 #define FSCR_EBB_LG    7       /* Enable Event Based Branching */
 #define FSCR_TM_LG     5       /* Enable Transactional Memory */
 #define FSCR_VECVSX_LG 1       /* Enable VMX/VSX  */
 #define FSCR_FP_LG     0       /* Enable Floating Point */
 #define SPRN_FSCR      0x099   /* Facility Status & Control Register */
+#define   FSCR_LM      __MASK(FSCR_LM_LG)
 #define   FSCR_TAR     __MASK(FSCR_TAR_LG)
 #define   FSCR_EBB     __MASK(FSCR_EBB_LG)
 #define   FSCR_DSCR    __MASK(FSCR_DSCR_LG)
 #define SPRN_HFSCR     0xbe    /* HV=1 Facility Status & Control Register */
+#define   HFSCR_LM     __MASK(FSCR_LM_LG)
 #define   HFSCR_TAR    __MASK(FSCR_TAR_LG)
 #define   HFSCR_EBB    __MASK(FSCR_EBB_LG)
 #define   HFSCR_TM     __MASK(FSCR_TM_LG)
index 6d0a831bc7d8e70a110c17dbd7a9c08168ee0463..ddceeb96e8fba666281ac822bea74d3ad3141be0 100644 (file)
@@ -1017,6 +1017,14 @@ static inline void save_sprs(struct thread_struct *t)
                 */
                t->tar = mfspr(SPRN_TAR);
        }
+
+       if (cpu_has_feature(CPU_FTR_ARCH_300)) {
+               /* Conditionally save Load Monitor registers, if enabled */
+               if (t->fscr & FSCR_LM) {
+                       t->lmrr = mfspr(SPRN_LMRR);
+                       t->lmser = mfspr(SPRN_LMSER);
+               }
+       }
 #endif
 }
 
@@ -1052,6 +1060,16 @@ static inline void restore_sprs(struct thread_struct *old_thread,
                if (old_thread->tar != new_thread->tar)
                        mtspr(SPRN_TAR, new_thread->tar);
        }
+
+       if (cpu_has_feature(CPU_FTR_ARCH_300)) {
+               /* Conditionally restore Load Monitor registers, if enabled */
+               if (new_thread->fscr & FSCR_LM) {
+                       if (old_thread->lmrr != new_thread->lmrr)
+                               mtspr(SPRN_LMRR, new_thread->lmrr);
+                       if (old_thread->lmser != new_thread->lmser)
+                               mtspr(SPRN_LMSER, new_thread->lmser);
+               }
+       }
 #endif
 }
 
index d2518c3cbf040c6eff22edc0ae9ce38e9a7dad77..f7e2f2e318bd64c2fd235f04118a5311269d46aa 100644 (file)
@@ -1377,6 +1377,7 @@ void facility_unavailable_exception(struct pt_regs *regs)
                [FSCR_TM_LG] = "TM",
                [FSCR_EBB_LG] = "EBB",
                [FSCR_TAR_LG] = "TAR",
+               [FSCR_LM_LG] = "LM",
        };
        char *facility = "unknown";
        u64 value;
@@ -1434,6 +1435,14 @@ void facility_unavailable_exception(struct pt_regs *regs)
                        emulate_single_step(regs);
                }
                return;
+       } else if ((status == FSCR_LM_LG) && cpu_has_feature(CPU_FTR_ARCH_300)) {
+               /*
+                * This process has touched LM, so turn it on forever
+                * for this process
+                */
+               current->thread.fscr |= FSCR_LM;
+               mtspr(SPRN_FSCR, current->thread.fscr);
+               return;
        }
 
        if ((status < ARRAY_SIZE(facility_strings)) &&