diff options
author | Paolo Galtieri <pgaltieri@mvista.com> | 2005-11-29 14:26:47 -0800 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-11-30 13:17:05 +1100 |
commit | 8117ce76c28ef0cab8545b518fa0543f6d1437e6 (patch) | |
tree | eeff68fc67e3b48cfb0156cd041d136c97229083 | |
parent | 12074a35b4ef36d7a971beaf42412b22f304cdd1 (diff) | |
download | op-kernel-dev-8117ce76c28ef0cab8545b518fa0543f6d1437e6.zip op-kernel-dev-8117ce76c28ef0cab8545b518fa0543f6d1437e6.tar.gz |
[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>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Paul Mackerras <paulus@samba.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 cb1c7b9..25cbdc8 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -417,6 +417,7 @@ void show_regs(struct pt_regs * regs) void exit_thread(void) { + preempt_disable(); if (last_task_used_math == current) last_task_used_math = NULL; if (last_task_used_altivec == current) @@ -425,10 +426,12 @@ void exit_thread(void) if (last_task_used_spe == current) last_task_used_spe = NULL; #endif + preempt_enable(); } void flush_thread(void) { + preempt_disable(); if (last_task_used_math == current) last_task_used_math = NULL; if (last_task_used_altivec == current) @@ -437,6 +440,7 @@ void flush_thread(void) if (last_task_used_spe == current) last_task_used_spe = NULL; #endif + preempt_enable(); } void @@ -535,6 +539,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER; + preempt_disable(); if (last_task_used_math == current) last_task_used_math = NULL; if (last_task_used_altivec == current) @@ -543,6 +548,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) if (last_task_used_spe == current) last_task_used_spe = NULL; #endif + preempt_enable(); memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); current->thread.fpscr.val = 0; #ifdef CONFIG_ALTIVEC |