diff options
author | Alexey Kardashevskiy <aik@au1.ibm.com> | 2011-03-02 10:18:48 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-04-27 00:18:19 -0400 |
commit | efcac6589a277c10060e4be44b9455cf43838dc1 (patch) | |
tree | d2236c1e9385baff297f0652c5a22b74f6acb149 /arch/powerpc/kernel | |
parent | f0aae3238fc1c28b543cbaaa0e7c5d57685f5f89 (diff) |
powerpc: Per process DSCR + some fixes (try#4)
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>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 15 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 16 | ||||
-rw-r--r-- | arch/powerpc/kernel/sysfs.c | 38 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 24 |
5 files changed, 94 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 23e6a93145ab..6887661ac072 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -74,6 +74,7 @@ int main(void) | |||
74 | DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); | 74 | DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); |
75 | DEFINE(SIGSEGV, SIGSEGV); | 75 | DEFINE(SIGSEGV, SIGSEGV); |
76 | DEFINE(NMI_MASK, NMI_MASK); | 76 | DEFINE(NMI_MASK, NMI_MASK); |
77 | DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); | ||
77 | #else | 78 | #else |
78 | DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); | 79 | DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); |
79 | #endif /* CONFIG_PPC64 */ | 80 | #endif /* CONFIG_PPC64 */ |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index dbf5bfafd7bc..64693706ebfd 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -421,6 +421,12 @@ BEGIN_FTR_SECTION | |||
421 | std r24,THREAD_VRSAVE(r3) | 421 | std r24,THREAD_VRSAVE(r3) |
422 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | 422 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
423 | #endif /* CONFIG_ALTIVEC */ | 423 | #endif /* CONFIG_ALTIVEC */ |
424 | #ifdef CONFIG_PPC64 | ||
425 | BEGIN_FTR_SECTION | ||
426 | mfspr r25,SPRN_DSCR | ||
427 | std r25,THREAD_DSCR(r3) | ||
428 | END_FTR_SECTION_IFSET(CPU_FTR_DSCR) | ||
429 | #endif | ||
424 | and. r0,r0,r22 | 430 | and. r0,r0,r22 |
425 | beq+ 1f | 431 | beq+ 1f |
426 | andc r22,r22,r0 | 432 | andc r22,r22,r0 |
@@ -522,6 +528,15 @@ BEGIN_FTR_SECTION | |||
522 | mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ | 528 | mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ |
523 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | 529 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
524 | #endif /* CONFIG_ALTIVEC */ | 530 | #endif /* CONFIG_ALTIVEC */ |
531 | #ifdef CONFIG_PPC64 | ||
532 | BEGIN_FTR_SECTION | ||
533 | ld r0,THREAD_DSCR(r4) | ||
534 | cmpd r0,r25 | ||
535 | beq 1f | ||
536 | mtspr SPRN_DSCR,r0 | ||
537 | 1: | ||
538 | END_FTR_SECTION_IFSET(CPU_FTR_DSCR) | ||
539 | #endif | ||
525 | 540 | ||
526 | /* r3-r13 are destroyed -- Cort */ | 541 | /* r3-r13 are destroyed -- Cort */ |
527 | REST_8GPRS(14, r1) | 542 | REST_8GPRS(14, r1) |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index f74f355a9617..a01c2d93fd2f 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -702,6 +702,8 @@ void prepare_to_copy(struct task_struct *tsk) | |||
702 | /* | 702 | /* |
703 | * Copy a thread.. | 703 | * Copy a thread.. |
704 | */ | 704 | */ |
705 | extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */ | ||
706 | |||
705 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 707 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
706 | unsigned long unused, struct task_struct *p, | 708 | unsigned long unused, struct task_struct *p, |
707 | struct pt_regs *regs) | 709 | struct pt_regs *regs) |
@@ -769,6 +771,20 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
769 | p->thread.ksp_vsid = sp_vsid; | 771 | p->thread.ksp_vsid = sp_vsid; |
770 | } | 772 | } |
771 | #endif /* CONFIG_PPC_STD_MMU_64 */ | 773 | #endif /* CONFIG_PPC_STD_MMU_64 */ |
774 | #ifdef CONFIG_PPC64 | ||
775 | if (cpu_has_feature(CPU_FTR_DSCR)) { | ||
776 | if (current->thread.dscr_inherit) { | ||
777 | p->thread.dscr_inherit = 1; | ||
778 | p->thread.dscr = current->thread.dscr; | ||
779 | } else if (0 != dscr_default) { | ||
780 | p->thread.dscr_inherit = 1; | ||
781 | p->thread.dscr = dscr_default; | ||
782 | } else { | ||
783 | p->thread.dscr_inherit = 0; | ||
784 | p->thread.dscr = 0; | ||
785 | } | ||
786 | } | ||
787 | #endif | ||
772 | 788 | ||
773 | /* | 789 | /* |
774 | * The PPC64 ABI makes use of a TOC to contain function | 790 | * The PPC64 ABI makes use of a TOC to contain function |
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index c0d8c2006bf4..f0f2199e64e1 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -182,6 +182,41 @@ static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); | |||
182 | static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL); | 182 | static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL); |
183 | static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr); | 183 | static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr); |
184 | static SYSDEV_ATTR(purr, 0600, show_purr, store_purr); | 184 | static SYSDEV_ATTR(purr, 0600, show_purr, store_purr); |
185 | |||
186 | unsigned long dscr_default = 0; | ||
187 | EXPORT_SYMBOL(dscr_default); | ||
188 | |||
189 | static ssize_t show_dscr_default(struct sysdev_class *class, | ||
190 | struct sysdev_class_attribute *attr, char *buf) | ||
191 | { | ||
192 | return sprintf(buf, "%lx\n", dscr_default); | ||
193 | } | ||
194 | |||
195 | static ssize_t __used store_dscr_default(struct sysdev_class *class, | ||
196 | struct sysdev_class_attribute *attr, const char *buf, | ||
197 | size_t count) | ||
198 | { | ||
199 | unsigned long val; | ||
200 | int ret = 0; | ||
201 | |||
202 | ret = sscanf(buf, "%lx", &val); | ||
203 | if (ret != 1) | ||
204 | return -EINVAL; | ||
205 | dscr_default = val; | ||
206 | |||
207 | return count; | ||
208 | } | ||
209 | |||
210 | static SYSDEV_CLASS_ATTR(dscr_default, 0600, | ||
211 | show_dscr_default, store_dscr_default); | ||
212 | |||
213 | static void sysfs_create_dscr_default(void) | ||
214 | { | ||
215 | int err = 0; | ||
216 | if (cpu_has_feature(CPU_FTR_DSCR)) | ||
217 | err = sysfs_create_file(&cpu_sysdev_class.kset.kobj, | ||
218 | &attr_dscr_default.attr); | ||
219 | } | ||
185 | #endif /* CONFIG_PPC64 */ | 220 | #endif /* CONFIG_PPC64 */ |
186 | 221 | ||
187 | #ifdef HAS_PPC_PMC_PA6T | 222 | #ifdef HAS_PPC_PMC_PA6T |
@@ -617,6 +652,9 @@ static int __init topology_init(void) | |||
617 | if (cpu_online(cpu)) | 652 | if (cpu_online(cpu)) |
618 | register_cpu_online(cpu); | 653 | register_cpu_online(cpu); |
619 | } | 654 | } |
655 | #ifdef CONFIG_PPC64 | ||
656 | sysfs_create_dscr_default(); | ||
657 | #endif /* CONFIG_PPC64 */ | ||
620 | 658 | ||
621 | return 0; | 659 | return 0; |
622 | } | 660 | } |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5ddb801bc154..cb71cf29edea 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -909,6 +909,26 @@ static int emulate_instruction(struct pt_regs *regs) | |||
909 | return emulate_isel(regs, instword); | 909 | return emulate_isel(regs, instword); |
910 | } | 910 | } |
911 | 911 | ||
912 | #ifdef CONFIG_PPC64 | ||
913 | /* Emulate the mfspr rD, DSCR. */ | ||
914 | if (((instword & PPC_INST_MFSPR_DSCR_MASK) == PPC_INST_MFSPR_DSCR) && | ||
915 | cpu_has_feature(CPU_FTR_DSCR)) { | ||
916 | PPC_WARN_EMULATED(mfdscr, regs); | ||
917 | rd = (instword >> 21) & 0x1f; | ||
918 | regs->gpr[rd] = mfspr(SPRN_DSCR); | ||
919 | return 0; | ||
920 | } | ||
921 | /* Emulate the mtspr DSCR, rD. */ | ||
922 | if (((instword & PPC_INST_MTSPR_DSCR_MASK) == PPC_INST_MTSPR_DSCR) && | ||
923 | cpu_has_feature(CPU_FTR_DSCR)) { | ||
924 | PPC_WARN_EMULATED(mtdscr, regs); | ||
925 | rd = (instword >> 21) & 0x1f; | ||
926 | mtspr(SPRN_DSCR, regs->gpr[rd]); | ||
927 | current->thread.dscr_inherit = 1; | ||
928 | return 0; | ||
929 | } | ||
930 | #endif | ||
931 | |||
912 | return -EINVAL; | 932 | return -EINVAL; |
913 | } | 933 | } |
914 | 934 | ||
@@ -1506,6 +1526,10 @@ struct ppc_emulated ppc_emulated = { | |||
1506 | #ifdef CONFIG_VSX | 1526 | #ifdef CONFIG_VSX |
1507 | WARN_EMULATED_SETUP(vsx), | 1527 | WARN_EMULATED_SETUP(vsx), |
1508 | #endif | 1528 | #endif |
1529 | #ifdef CONFIG_PPC64 | ||
1530 | WARN_EMULATED_SETUP(mfdscr), | ||
1531 | WARN_EMULATED_SETUP(mtdscr), | ||
1532 | #endif | ||
1509 | }; | 1533 | }; |
1510 | 1534 | ||
1511 | u32 ppc_warn_emulated; | 1535 | u32 ppc_warn_emulated; |