Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.c

Signed-off-by: Anton Blanchard <anton@samba.org>
Cc: <stable@kernel.org> # 3.0+
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Anton Blanchard and committed by
Benjamin Herrenschmidt
71433285 1021cb26

+18 -6
+1
arch/powerpc/kernel/asm-offsets.c
··· 76 76 DEFINE(SIGSEGV, SIGSEGV); 77 77 DEFINE(NMI_MASK, NMI_MASK); 78 78 DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); 79 + DEFINE(THREAD_DSCR_INHERIT, offsetof(struct thread_struct, dscr_inherit)); 79 80 #else 80 81 DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); 81 82 #endif /* CONFIG_PPC64 */
+17 -6
arch/powerpc/kernel/entry_64.S
··· 370 370 li r3,0 371 371 b syscall_exit 372 372 373 + .section ".toc","aw" 374 + DSCR_DEFAULT: 375 + .tc dscr_default[TC],dscr_default 376 + 377 + .section ".text" 378 + 373 379 /* 374 380 * This routine switches between two different tasks. The process 375 381 * state of one is saved on its kernel stack. Then the state ··· 515 509 mr r1,r8 /* start using new stack pointer */ 516 510 std r7,PACAKSAVE(r13) 517 511 518 - ld r6,_CCR(r1) 519 - mtcrf 0xFF,r6 520 - 521 512 #ifdef CONFIG_ALTIVEC 522 513 BEGIN_FTR_SECTION 523 514 ld r0,THREAD_VRSAVE(r4) ··· 523 520 #endif /* CONFIG_ALTIVEC */ 524 521 #ifdef CONFIG_PPC64 525 522 BEGIN_FTR_SECTION 523 + lwz r6,THREAD_DSCR_INHERIT(r4) 524 + ld r7,DSCR_DEFAULT@toc(2) 526 525 ld r0,THREAD_DSCR(r4) 527 - cmpd r0,r25 528 - beq 1f 526 + cmpwi r6,0 527 + bne 1f 528 + ld r0,0(r7) 529 + 1: cmpd r0,r25 530 + beq 2f 529 531 mtspr SPRN_DSCR,r0 530 - 1: 532 + 2: 531 533 END_FTR_SECTION_IFSET(CPU_FTR_DSCR) 532 534 #endif 535 + 536 + ld r6,_CCR(r1) 537 + mtcrf 0xFF,r6 533 538 534 539 /* r3-r13 are destroyed -- Cort */ 535 540 REST_8GPRS(14, r1)