From 9f232a125bf86b0dae09f8ea4a0553535cf6b658 Mon Sep 17 00:00:00 2001 From: Paolo Galtieri Date: Tue, 29 Nov 2005 19:34:38 -0800 Subject: [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 Cc: Kumar Gala Cc: Matt Porter Cc: Tom Rini Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/kernel/process.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index cb1c7b92f8c601..25cbdc8d2941a9 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 -- cgit 1.2.3-korg