diff options
author | Paolo Galtieri <pgaltieri@mvista.com> | 2005-11-29 22:34:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-29 22:47:03 -0500 |
commit | 9f232a125bf86b0dae09f8ea4a0553535cf6b658 (patch) | |
tree | 2ba12b9889cef8568ae9ce04b8672162fa2283ff | |
parent | 123d3c13e2853a11b4d599d754b356acb12886e2 (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.c | 6 |
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 | ||
418 | void exit_thread(void) | 418 | void 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 | ||
430 | void flush_thread(void) | 432 | void 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 | ||
442 | void | 446 | void |
@@ -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 |