powerpc: Fix bug causing FP registers corruption on UP + preempt

This fixes a bug noticed by Paolo Galtieri and fixed for ARCH=ppc in
the previous commit (ppc: fix floating point register corruption).
This fixes the arch/powerpc code by adding preempt_disable/enable,
and also cleans it up a bit by pulling out the code that discards
any lazily-switched CPU register state into a new function, rather
than having that code repeated in three places.

Signed-off-by: Paul Mackerras <paulus@samba.org>

+25 -37
+25 -37
arch/powerpc/kernel/process.c
··· 201 201 } 202 202 #endif /* CONFIG_SPE */ 203 203 204 + /* 205 + * If we are doing lazy switching of CPU state (FP, altivec or SPE), 206 + * and the current task has some state, discard it. 207 + */ 208 + static inline void discard_lazy_cpu_state(void) 209 + { 210 + #ifndef CONFIG_SMP 211 + preempt_disable(); 212 + if (last_task_used_math == current) 213 + last_task_used_math = NULL; 214 + #ifdef CONFIG_ALTIVEC 215 + if (last_task_used_altivec == current) 216 + last_task_used_altivec = NULL; 217 + #endif /* CONFIG_ALTIVEC */ 218 + #ifdef CONFIG_SPE 219 + if (last_task_used_spe == current) 220 + last_task_used_spe = NULL; 221 + #endif 222 + preempt_enable(); 223 + #endif /* CONFIG_SMP */ 224 + } 225 + 204 226 int set_dabr(unsigned long dabr) 205 227 { 206 228 if (ppc_md.set_dabr) ··· 456 434 void exit_thread(void) 457 435 { 458 436 kprobe_flush_task(current); 459 - 460 - #ifndef CONFIG_SMP 461 - if (last_task_used_math == current) 462 - last_task_used_math = NULL; 463 - #ifdef CONFIG_ALTIVEC 464 - if (last_task_used_altivec == current) 465 - last_task_used_altivec = NULL; 466 - #endif /* CONFIG_ALTIVEC */ 467 - #ifdef CONFIG_SPE 468 - if (last_task_used_spe == current) 469 - last_task_used_spe = NULL; 470 - #endif 471 - #endif /* CONFIG_SMP */ 437 + discard_lazy_cpu_state(); 472 438 } 473 439 474 440 void flush_thread(void) ··· 468 458 t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); 469 459 #endif 470 460 471 - #ifndef CONFIG_SMP 472 - if (last_task_used_math == current) 473 - last_task_used_math = NULL; 474 - #ifdef CONFIG_ALTIVEC 475 - if (last_task_used_altivec == current) 476 - last_task_used_altivec = NULL; 477 - #endif /* CONFIG_ALTIVEC */ 478 - #ifdef CONFIG_SPE 479 - if (last_task_used_spe == current) 480 - last_task_used_spe = NULL; 481 - #endif 482 - #endif /* CONFIG_SMP */ 461 + discard_lazy_cpu_state(); 483 462 484 463 #ifdef CONFIG_PPC64 /* for now */ 485 464 if (current->thread.dabr) { ··· 634 635 } 635 636 #endif 636 637 637 - #ifndef CONFIG_SMP 638 - if (last_task_used_math == current) 639 - last_task_used_math = NULL; 640 - #ifdef CONFIG_ALTIVEC 641 - if (last_task_used_altivec == current) 642 - last_task_used_altivec = NULL; 643 - #endif 644 - #ifdef CONFIG_SPE 645 - if (last_task_used_spe == current) 646 - last_task_used_spe = NULL; 647 - #endif 648 - #endif /* CONFIG_SMP */ 638 + discard_lazy_cpu_state(); 649 639 memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); 650 640 current->thread.fpscr.val = 0; 651 641 #ifdef CONFIG_ALTIVEC