Skip to content

Commit

Permalink
powerpc: Restore correct DSCR in context switch
Browse files Browse the repository at this point in the history
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.c

Signed-off-by: Anton Blanchard <[email protected]>
Cc: <[email protected]> # 3.0+
Signed-off-by: Benjamin Herrenschmidt <[email protected]>
  • Loading branch information
antonblanchard authored and ozbenh committed Sep 5, 2012
1 parent 1021cb2 commit 7143328
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 6 deletions.
1 change: 1 addition & 0 deletions arch/powerpc/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ int main(void)
DEFINE(SIGSEGV, SIGSEGV);
DEFINE(NMI_MASK, NMI_MASK);
DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr));
DEFINE(THREAD_DSCR_INHERIT, offsetof(struct thread_struct, dscr_inherit));
#else
DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
#endif /* CONFIG_PPC64 */
Expand Down
23 changes: 17 additions & 6 deletions arch/powerpc/kernel/entry_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,12 @@ _GLOBAL(ret_from_fork)
li r3,0
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
* state of one is saved on its kernel stack. Then the state
Expand Down Expand Up @@ -509,9 +515,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
mr r1,r8 /* start using new stack pointer */
std r7,PACAKSAVE(r13)

ld r6,_CCR(r1)
mtcrf 0xFF,r6

#ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION
ld r0,THREAD_VRSAVE(r4)
Expand All @@ -520,14 +523,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_PPC64
BEGIN_FTR_SECTION
lwz r6,THREAD_DSCR_INHERIT(r4)
ld r7,DSCR_DEFAULT@toc(2)
ld r0,THREAD_DSCR(r4)
cmpd r0,r25
beq 1f
cmpwi r6,0
bne 1f
ld r0,0(r7)
1: cmpd r0,r25
beq 2f
mtspr SPRN_DSCR,r0
1:
2:
END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
#endif

ld r6,_CCR(r1)
mtcrf 0xFF,r6

/* r3-r13 are destroyed -- Cort */
REST_8GPRS(14, r1)
REST_10GPRS(22, r1)
Expand Down

0 comments on commit 7143328

Please sign in to comment.