powerpc: Per process DSCR + some fixes (try#4)
authorAlexey Kardashevskiy <aik@au1.ibm.com>
Wed, 2 Mar 2011 15:18:48 +0000 (15:18 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 27 Apr 2011 04:18:19 +0000 (14:18 +1000)
The DSCR (aka Data Stream Control Register) is supported on some
server PowerPC chips and allow some control over the prefetch
of data streams.

This patch allows the value to be specified per thread by emulating
the corresponding mfspr and mtspr instructions. Children of such
threads inherit the value. Other threads use a default value that
can be specified in sysfs - /sys/devices/system/cpu/dscr_default.

If a thread starts with non default value in the sysfs entry,
all children threads inherit this non default value even if
the sysfs value is changed later.

Signed-off-by: Alexey Kardashevskiy <aik@au1.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/emulated_ops.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/processor.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/process.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/traps.c

index f0fb4fc1f6e6878a2617fbdf6782c5e2883af39b..45921672b97af14c0bb645de7bbf8772f2c3fb5f 100644 (file)
@@ -52,6 +52,10 @@ extern struct ppc_emulated {
 #ifdef CONFIG_VSX
        struct ppc_emulated_entry vsx;
 #endif
+#ifdef CONFIG_PPC64
+       struct ppc_emulated_entry mfdscr;
+       struct ppc_emulated_entry mtdscr;
+#endif
 } ppc_emulated;
 
 extern u32 ppc_warn_emulated;
index 3e25b258568e48784c257536dd51eda280943305..e472659d906c3203e5da6be8b8e1d3baa9fa967c 100644 (file)
 #define PPC_INST_RFCI                  0x4c000066
 #define PPC_INST_RFDI                  0x4c00004e
 #define PPC_INST_RFMCI                 0x4c00004c
+#define PPC_INST_MFSPR_DSCR            0x7c1102a6
+#define PPC_INST_MFSPR_DSCR_MASK       0xfc1fffff
+#define PPC_INST_MTSPR_DSCR            0x7c1103a6
+#define PPC_INST_MTSPR_DSCR_MASK       0xfc1fffff
 
 #define PPC_INST_STRING                        0x7c00042a
 #define PPC_INST_STRING_MASK           0xfc0007fe
index de1967a1ff579258d3fbabd1e45764f2cdc4d455..d50c2b6d9bc31f4bff44e9e7b8edb085cbac367e 100644 (file)
@@ -238,6 +238,10 @@ struct thread_struct {
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
        void*           kvm_shadow_vcpu; /* KVM internal data */
 #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
+#ifdef CONFIG_PPC64
+       unsigned long   dscr;
+       int             dscr_inherit;
+#endif
 };
 
 #define ARCH_MIN_TASKALIGN 16
index 23e6a93145ab3d95e136fe211004c2234e7dba44..6887661ac07291d33cf968d5e282ce8f49eb1409 100644 (file)
@@ -74,6 +74,7 @@ int main(void)
        DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
        DEFINE(SIGSEGV, SIGSEGV);
        DEFINE(NMI_MASK, NMI_MASK);
+       DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr));
 #else
        DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
 #endif /* CONFIG_PPC64 */
index dbf5bfafd7bc3dcbaa42e48c5675ac405456a5ee..64693706ebfd4833e8ab0ef601c7a638d40d85c3 100644 (file)
@@ -421,6 +421,12 @@ BEGIN_FTR_SECTION
        std     r24,THREAD_VRSAVE(r3)
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_PPC64
+BEGIN_FTR_SECTION
+       mfspr   r25,SPRN_DSCR
+       std     r25,THREAD_DSCR(r3)
+END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
+#endif
        and.    r0,r0,r22
        beq+    1f
        andc    r22,r22,r0
@@ -522,6 +528,15 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_VRSAVE,r0          /* if G4, restore VRSAVE reg */
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_PPC64
+BEGIN_FTR_SECTION
+       ld      r0,THREAD_DSCR(r4)
+       cmpd    r0,r25
+       beq     1f
+       mtspr   SPRN_DSCR,r0
+1:     
+END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
+#endif
 
        /* r3-r13 are destroyed -- Cort */
        REST_8GPRS(14, r1)
index f74f355a9617a97ea05e174efaa9f67f4db3e275..a01c2d93fd2f9fd31a9a05b5f7e8304ccfe0b6c3 100644 (file)
@@ -702,6 +702,8 @@ void prepare_to_copy(struct task_struct *tsk)
 /*
  * Copy a thread..
  */
+extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
+
 int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long unused, struct task_struct *p,
                struct pt_regs *regs)
@@ -769,6 +771,20 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                p->thread.ksp_vsid = sp_vsid;
        }
 #endif /* CONFIG_PPC_STD_MMU_64 */
+#ifdef CONFIG_PPC64 
+       if (cpu_has_feature(CPU_FTR_DSCR)) {
+               if (current->thread.dscr_inherit) {
+                       p->thread.dscr_inherit = 1;
+                       p->thread.dscr = current->thread.dscr;
+               } else if (0 != dscr_default) {
+                       p->thread.dscr_inherit = 1;
+                       p->thread.dscr = dscr_default;
+               } else {
+                       p->thread.dscr_inherit = 0;
+                       p->thread.dscr = 0;
+               }
+       }
+#endif
 
        /*
         * The PPC64 ABI makes use of a TOC to contain function 
index c0d8c2006bf4c7e29d37ef10863929d17d48f38f..f0f2199e64e123a0fcf96ec311b1d3a00bb196b4 100644 (file)
@@ -182,6 +182,41 @@ static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
 static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
 static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
 static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
+
+unsigned long dscr_default = 0;
+EXPORT_SYMBOL(dscr_default);
+
+static ssize_t show_dscr_default(struct sysdev_class *class,
+               struct sysdev_class_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%lx\n", dscr_default);
+}
+
+static ssize_t __used store_dscr_default(struct sysdev_class *class,
+               struct sysdev_class_attribute *attr, const char *buf,
+               size_t count)
+{
+       unsigned long val;
+       int ret = 0;
+       
+       ret = sscanf(buf, "%lx", &val);
+       if (ret != 1)
+               return -EINVAL;
+       dscr_default = val;
+
+       return count;
+}
+
+static SYSDEV_CLASS_ATTR(dscr_default, 0600,
+               show_dscr_default, store_dscr_default);
+
+static void sysfs_create_dscr_default(void)
+{
+       int err = 0;
+       if (cpu_has_feature(CPU_FTR_DSCR))
+               err = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
+                       &attr_dscr_default.attr);
+}
 #endif /* CONFIG_PPC64 */
 
 #ifdef HAS_PPC_PMC_PA6T
@@ -617,6 +652,9 @@ static int __init topology_init(void)
                if (cpu_online(cpu))
                        register_cpu_online(cpu);
        }
+#ifdef CONFIG_PPC64
+       sysfs_create_dscr_default();
+#endif /* CONFIG_PPC64 */
 
        return 0;
 }
index 5ddb801bc15409ada686ee7fec56de73fac438cf..cb71cf29edea3e80bd3fe2d698adb92063116a84 100644 (file)
@@ -909,6 +909,26 @@ static int emulate_instruction(struct pt_regs *regs)
                return emulate_isel(regs, instword);
        }
 
+#ifdef CONFIG_PPC64
+       /* Emulate the mfspr rD, DSCR. */
+       if (((instword & PPC_INST_MFSPR_DSCR_MASK) == PPC_INST_MFSPR_DSCR) &&
+                       cpu_has_feature(CPU_FTR_DSCR)) {
+               PPC_WARN_EMULATED(mfdscr, regs);
+               rd = (instword >> 21) & 0x1f;
+               regs->gpr[rd] = mfspr(SPRN_DSCR);
+               return 0;
+       }
+       /* Emulate the mtspr DSCR, rD. */
+       if (((instword & PPC_INST_MTSPR_DSCR_MASK) == PPC_INST_MTSPR_DSCR) &&
+                       cpu_has_feature(CPU_FTR_DSCR)) {
+               PPC_WARN_EMULATED(mtdscr, regs);
+               rd = (instword >> 21) & 0x1f;
+               mtspr(SPRN_DSCR, regs->gpr[rd]);
+               current->thread.dscr_inherit = 1;
+               return 0;
+       }
+#endif
+
        return -EINVAL;
 }
 
@@ -1506,6 +1526,10 @@ struct ppc_emulated ppc_emulated = {
 #ifdef CONFIG_VSX
        WARN_EMULATED_SETUP(vsx),
 #endif
+#ifdef CONFIG_PPC64
+       WARN_EMULATED_SETUP(mfdscr),
+       WARN_EMULATED_SETUP(mtdscr),
+#endif
 };
 
 u32 ppc_warn_emulated;