aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Galtieri <pgaltieri@mvista.com>2005-11-29 22:34:38 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-29 22:47:03 -0500
commit9f232a125bf86b0dae09f8ea4a0553535cf6b658 (patch)
tree2ba12b9889cef8568ae9ce04b8672162fa2283ff
parent123d3c13e2853a11b4d599d754b356acb12886e2 (diff)
[PATCH] ppc: fix floating point register corruption
I recently discovered a bug on PPC which causes the floating point registers to get corrupted when CONFIG_PREEMPT=y. The problem occurred while running a multi threaded Java application that does floating point. The problem could be reproduced in anywhere from 2 to 6 hours. With the patch I have included below it ran for over a week without failure. Signed-off-by: Paolo Galtieri <pgaltieri@mvista.com> Cc: Kumar Gala <galak@gate.crashing.org> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Tom Rini <trini@kernel.crashing.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/ppc/kernel/process.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index cb1c7b92f8c6..25cbdc8d2941 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -417,6 +417,7 @@ void show_regs(struct pt_regs * regs)
417 417
418void exit_thread(void) 418void exit_thread(void)
419{ 419{
420 preempt_disable();
420 if (last_task_used_math == current) 421 if (last_task_used_math == current)
421 last_task_used_math = NULL; 422 last_task_used_math = NULL;
422 if (last_task_used_altivec == current) 423 if (last_task_used_altivec == current)
@@ -425,10 +426,12 @@ void exit_thread(void)
425 if (last_task_used_spe == current) 426 if (last_task_used_spe == current)
426 last_task_used_spe = NULL; 427 last_task_used_spe = NULL;
427#endif 428#endif
429 preempt_enable();
428} 430}
429 431
430void flush_thread(void) 432void flush_thread(void)
431{ 433{
434 preempt_disable();
432 if (last_task_used_math == current) 435 if (last_task_used_math == current)
433 last_task_used_math = NULL; 436 last_task_used_math = NULL;
434 if (last_task_used_altivec == current) 437 if (last_task_used_altivec == current)
@@ -437,6 +440,7 @@ void flush_thread(void)
437 if (last_task_used_spe == current) 440 if (last_task_used_spe == current)
438 last_task_used_spe = NULL; 441 last_task_used_spe = NULL;
439#endif 442#endif
443 preempt_enable();
440} 444}
441 445
442void 446void
@@ -535,6 +539,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
535 regs->nip = nip; 539 regs->nip = nip;
536 regs->gpr[1] = sp; 540 regs->gpr[1] = sp;
537 regs->msr = MSR_USER; 541 regs->msr = MSR_USER;
542 preempt_disable();
538 if (last_task_used_math == current) 543 if (last_task_used_math == current)
539 last_task_used_math = NULL; 544 last_task_used_math = NULL;
540 if (last_task_used_altivec == current) 545 if (last_task_used_altivec == current)
@@ -543,6 +548,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
543 if (last_task_used_spe == current) 548 if (last_task_used_spe == current)
544 last_task_used_spe = NULL; 549 last_task_used_spe = NULL;
545#endif 550#endif
551 preempt_enable();
546 memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); 552 memset(current->thread.fpr, 0, sizeof(current->thread.fpr));
547 current->thread.fpscr.val = 0; 553 current->thread.fpscr.val = 0;
548#ifdef CONFIG_ALTIVEC 554#ifdef CONFIG_ALTIVEC