1/* 2 * FPU support code, moved here from head.S so that it can be used 3 * by chips which use other head-whatever.S files. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 8 * 2 of the License, or (at your option) any later version. 9 * 10 */ 11 12#include <linux/config.h> 13#include <asm/reg.h> 14#include <asm/page.h> 15#include <asm/mmu.h> 16#include <asm/pgtable.h> 17#include <asm/cputable.h> 18#include <asm/cache.h> 19#include <asm/thread_info.h> 20#include <asm/ppc_asm.h> 21#include <asm/asm-offsets.h> 22 23/* 24 * This task wants to use the FPU now. 25 * On UP, disable FP for the task which had the FPU previously, 26 * and save its floating-point registers in its thread_struct. 27 * Load up this task's FP registers from its thread_struct, 28 * enable the FPU for the current task and return to the task. 29 */ 30_GLOBAL(load_up_fpu) 31 mfmsr r5 32 ori r5,r5,MSR_FP 33 SYNC 34 MTMSRD(r5) /* enable use of fpu now */ 35 isync 36/* 37 * For SMP, we don't do lazy FPU switching because it just gets too 38 * horrendously complex, especially when a task switches from one CPU 39 * to another. Instead we call giveup_fpu in switch_to. 40 */ 41#ifndef CONFIG_SMP 42 LOADBASE(r3, last_task_used_math) 43 toreal(r3) 44 LDL r4,OFF(last_task_used_math)(r3) 45 CMPI 0,r4,0 46 beq 1f 47 toreal(r4) 48 addi r4,r4,THREAD /* want last_task_used_math->thread */ 49 SAVE_32FPRS(0, r4) 50 mffs fr0 51 stfd fr0,THREAD_FPSCR(r4) 52 LDL r5,PT_REGS(r4) 53 toreal(r5) 54 LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) 55 li r10,MSR_FP|MSR_FE0|MSR_FE1 56 andc r4,r4,r10 /* disable FP for previous task */ 57 STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) 581: 59#endif /* CONFIG_SMP */ 60 /* enable use of FP after return */ 61#ifdef CONFIG_PPC32 62 mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ 63 lwz r4,THREAD_FPEXC_MODE(r5) 64 ori r9,r9,MSR_FP /* enable FP for current */ 65 or r9,r9,r4 66#else 67 ld r4,PACACURRENT(r13) 68 addi r5,r4,THREAD /* Get THREAD */ 69 ld r4,THREAD_FPEXC_MODE(r5) 70 ori r12,r12,MSR_FP 71 or r12,r12,r4 72 std r12,_MSR(r1) 73#endif 74 lfd fr0,THREAD_FPSCR(r5) 75 mtfsf 0xff,fr0 76 REST_32FPRS(0, r5) 77#ifndef CONFIG_SMP 78 subi r4,r5,THREAD 79 fromreal(r4) 80 STL r4,OFF(last_task_used_math)(r3) 81#endif /* CONFIG_SMP */ 82 /* restore registers and return */ 83 /* we haven't used ctr or xer or lr */ 84 b fast_exception_return 85 86/* 87 * giveup_fpu(tsk) 88 * Disable FP for the task given as the argument, 89 * and save the floating-point registers in its thread_struct. 90 * Enables the FPU for use in the kernel on return. 91 */ 92_GLOBAL(giveup_fpu) 93 mfmsr r5 94 ori r5,r5,MSR_FP 95 SYNC_601 96 ISYNC_601 97 MTMSRD(r5) /* enable use of fpu now */ 98 SYNC_601 99 isync 100 CMPI 0,r3,0 101 beqlr- /* if no previous owner, done */ 102 addi r3,r3,THREAD /* want THREAD of task */ 103 LDL r5,PT_REGS(r3) 104 CMPI 0,r5,0 105 SAVE_32FPRS(0, r3) 106 mffs fr0 107 stfd fr0,THREAD_FPSCR(r3) 108 beq 1f 109 LDL r4,_MSR-STACK_FRAME_OVERHEAD(r5) 110 li r3,MSR_FP|MSR_FE0|MSR_FE1 111 andc r4,r4,r3 /* disable FP for previous task */ 112 STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1131: 114#ifndef CONFIG_SMP 115 li r5,0 116 LOADBASE(r4,last_task_used_math) 117 STL r5,OFF(last_task_used_math)(r4) 118#endif /* CONFIG_SMP */ 119 blr 120 121/* 122 * These are used in the alignment trap handler when emulating 123 * single-precision loads and stores. 124 * We restore and save the fpscr so the task gets the same result 125 * and exceptions as if the cpu had performed the load or store. 126 */ 127 128_GLOBAL(cvt_fd) 129 lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */ 130 mtfsf 0xff,0 131 lfs 0,0(r3) 132 stfd 0,0(r4) 133 mffs 0 134 stfd 0,THREAD_FPSCR(r5) /* save new fpscr value */ 135 blr 136 137_GLOBAL(cvt_df) 138 lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */ 139 mtfsf 0xff,0 140 lfd 0,0(r3) 141 stfs 0,0(r4) 142 mffs 0 143 stfd 0,THREAD_FPSCR(r5) /* save new fpscr value */ 144 blr 145