[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>

authored by Paolo Galtieri and committed by Linus Torvalds 9f232a12 123d3c13

+6
+6
arch/ppc/kernel/process.c
··· 417 418 void exit_thread(void) 419 { 420 if (last_task_used_math == current) 421 last_task_used_math = NULL; 422 if (last_task_used_altivec == current) ··· 426 if (last_task_used_spe == current) 427 last_task_used_spe = NULL; 428 #endif 429 } 430 431 void flush_thread(void) 432 { 433 if (last_task_used_math == current) 434 last_task_used_math = NULL; 435 if (last_task_used_altivec == current) ··· 440 if (last_task_used_spe == current) 441 last_task_used_spe = NULL; 442 #endif 443 } 444 445 void ··· 539 regs->nip = nip; 540 regs->gpr[1] = sp; 541 regs->msr = MSR_USER; 542 if (last_task_used_math == current) 543 last_task_used_math = NULL; 544 if (last_task_used_altivec == current) ··· 548 if (last_task_used_spe == current) 549 last_task_used_spe = NULL; 550 #endif 551 memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); 552 current->thread.fpscr.val = 0; 553 #ifdef CONFIG_ALTIVEC
··· 417 418 void exit_thread(void) 419 { 420 + preempt_disable(); 421 if (last_task_used_math == current) 422 last_task_used_math = NULL; 423 if (last_task_used_altivec == current) ··· 425 if (last_task_used_spe == current) 426 last_task_used_spe = NULL; 427 #endif 428 + preempt_enable(); 429 } 430 431 void flush_thread(void) 432 { 433 + preempt_disable(); 434 if (last_task_used_math == current) 435 last_task_used_math = NULL; 436 if (last_task_used_altivec == current) ··· 437 if (last_task_used_spe == current) 438 last_task_used_spe = NULL; 439 #endif 440 + preempt_enable(); 441 } 442 443 void ··· 535 regs->nip = nip; 536 regs->gpr[1] = sp; 537 regs->msr = MSR_USER; 538 + preempt_disable(); 539 if (last_task_used_math == current) 540 last_task_used_math = NULL; 541 if (last_task_used_altivec == current) ··· 543 if (last_task_used_spe == current) 544 last_task_used_spe = NULL; 545 #endif 546 + preempt_enable(); 547 memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); 548 current->thread.fpscr.val = 0; 549 #ifdef CONFIG_ALTIVEC