Commit 71433285 authored by Anton Blanchard's avatar Anton Blanchard Committed by Benjamin Herrenschmidt

powerpc: Restore correct DSCR in context switch

During a context switch we always restore the per thread DSCR value.
If we aren't doing explicit DSCR management
(ie thread.dscr_inherit == 0) and the default DSCR changed while
the process has been sleeping we end up with the wrong value.

Check thread.dscr_inherit and select the default DSCR or per thread
DSCR as required.

This was found with the following test case, when running with
more threads than CPUs (ie forcing context switching):

http://ozlabs.org/~anton/junkcode/dscr_default_test.c

With the four patches applied I can run a combination of all
test cases successfully at the same time:

http://ozlabs.org/~anton/junkcode/dscr_default_test.c
http://ozlabs.org/~anton/junkcode/dscr_explicit_test.c
http://ozlabs.org/~anton/junkcode/dscr_inherit_test.cSigned-off-by: default avatarAnton Blanchard <anton@samba.org>
Cc: <stable@kernel.org> # 3.0+
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 1021cb26
...@@ -76,6 +76,7 @@ int main(void) ...@@ -76,6 +76,7 @@ int main(void)
DEFINE(SIGSEGV, SIGSEGV); DEFINE(SIGSEGV, SIGSEGV);
DEFINE(NMI_MASK, NMI_MASK); DEFINE(NMI_MASK, NMI_MASK);
DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr));
DEFINE(THREAD_DSCR_INHERIT, offsetof(struct thread_struct, dscr_inherit));
#else #else
DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
......
...@@ -370,6 +370,12 @@ _GLOBAL(ret_from_fork) ...@@ -370,6 +370,12 @@ _GLOBAL(ret_from_fork)
li r3,0 li r3,0
b syscall_exit b syscall_exit
.section ".toc","aw"
DSCR_DEFAULT:
.tc dscr_default[TC],dscr_default
.section ".text"
/* /*
* This routine switches between two different tasks. The process * This routine switches between two different tasks. The process
* state of one is saved on its kernel stack. Then the state * state of one is saved on its kernel stack. Then the state
...@@ -509,9 +515,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) ...@@ -509,9 +515,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
mr r1,r8 /* start using new stack pointer */ mr r1,r8 /* start using new stack pointer */
std r7,PACAKSAVE(r13) std r7,PACAKSAVE(r13)
ld r6,_CCR(r1)
mtcrf 0xFF,r6
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
ld r0,THREAD_VRSAVE(r4) ld r0,THREAD_VRSAVE(r4)
...@@ -520,14 +523,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) ...@@ -520,14 +523,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
lwz r6,THREAD_DSCR_INHERIT(r4)
ld r7,DSCR_DEFAULT@toc(2)
ld r0,THREAD_DSCR(r4) ld r0,THREAD_DSCR(r4)
cmpd r0,r25 cmpwi r6,0
beq 1f bne 1f
ld r0,0(r7)
1: cmpd r0,r25
beq 2f
mtspr SPRN_DSCR,r0 mtspr SPRN_DSCR,r0
1: 2:
END_FTR_SECTION_IFSET(CPU_FTR_DSCR) END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
#endif #endif
ld r6,_CCR(r1)
mtcrf 0xFF,r6
/* r3-r13 are destroyed -- Cort */ /* r3-r13 are destroyed -- Cort */
REST_8GPRS(14, r1) REST_8GPRS(14, r1)
REST_10GPRS(22, r1) REST_10GPRS(22, r1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment