| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2002 MontaVista Software Inc. | 
 | 3 |  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | 
 | 4 |  * | 
 | 5 |  * This program is free software; you can redistribute it and/or modify it | 
 | 6 |  * under the terms of the GNU General Public License as published by the | 
 | 7 |  * Free Software Foundation;  either version 2 of the  License, or (at your | 
 | 8 |  * option) any later version. | 
 | 9 |  */ | 
 | 10 | #ifndef _ASM_FPU_H | 
 | 11 | #define _ASM_FPU_H | 
 | 12 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 | #include <linux/sched.h> | 
 | 14 | #include <linux/thread_info.h> | 
| Jiri Slaby | 1977f03 | 2007-10-18 23:40:25 -0700 | [diff] [blame] | 15 | #include <linux/bitops.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 |  | 
 | 17 | #include <asm/mipsregs.h> | 
 | 18 | #include <asm/cpu.h> | 
 | 19 | #include <asm/cpu-features.h> | 
| Chris Dearman | 0b62495 | 2007-05-08 16:09:13 +0100 | [diff] [blame] | 20 | #include <asm/hazards.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 | #include <asm/processor.h> | 
 | 22 | #include <asm/current.h> | 
 | 23 |  | 
| Ralf Baechle | f088fc8 | 2006-04-05 09:45:47 +0100 | [diff] [blame] | 24 | #ifdef CONFIG_MIPS_MT_FPAFF | 
 | 25 | #include <asm/mips_mt.h> | 
 | 26 | #endif | 
 | 27 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 | struct sigcontext; | 
 | 29 | struct sigcontext32; | 
 | 30 |  | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 31 | extern asmlinkage int (*save_fp_context)(struct sigcontext __user *sc); | 
 | 32 | extern asmlinkage int (*restore_fp_context)(struct sigcontext __user *sc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 |  | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 34 | extern asmlinkage int (*save_fp_context32)(struct sigcontext32 __user *sc); | 
 | 35 | extern asmlinkage int (*restore_fp_context32)(struct sigcontext32 __user *sc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 |  | 
 | 37 | extern void fpu_emulator_init_fpu(void); | 
 | 38 | extern void _init_fpu(void); | 
 | 39 | extern void _save_fp(struct task_struct *); | 
 | 40 | extern void _restore_fp(struct task_struct *); | 
 | 41 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | #define __enable_fpu()							\ | 
 | 43 | do {									\ | 
 | 44 |         set_c0_status(ST0_CU1);						\ | 
| Chris Dearman | 0b62495 | 2007-05-08 16:09:13 +0100 | [diff] [blame] | 45 |         enable_fpu_hazard();						\ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 46 | } while (0) | 
 | 47 |  | 
 | 48 | #define __disable_fpu()							\ | 
 | 49 | do {									\ | 
 | 50 | 	clear_c0_status(ST0_CU1);					\ | 
| Chris Dearman | 0b62495 | 2007-05-08 16:09:13 +0100 | [diff] [blame] | 51 |         disable_fpu_hazard();						\ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | } while (0) | 
 | 53 |  | 
 | 54 | #define enable_fpu()							\ | 
 | 55 | do {									\ | 
 | 56 | 	if (cpu_has_fpu)						\ | 
 | 57 | 		__enable_fpu();						\ | 
 | 58 | } while (0) | 
 | 59 |  | 
 | 60 | #define disable_fpu()							\ | 
 | 61 | do {									\ | 
 | 62 | 	if (cpu_has_fpu)						\ | 
 | 63 | 		__disable_fpu();					\ | 
 | 64 | } while (0) | 
 | 65 |  | 
 | 66 |  | 
 | 67 | #define clear_fpu_owner()	clear_thread_flag(TIF_USEDFPU) | 
 | 68 |  | 
| Ralf Baechle | 1d74f6b | 2005-05-09 13:16:07 +0000 | [diff] [blame] | 69 | static inline int __is_fpu_owner(void) | 
 | 70 | { | 
 | 71 | 	return test_thread_flag(TIF_USEDFPU); | 
 | 72 | } | 
 | 73 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | static inline int is_fpu_owner(void) | 
 | 75 | { | 
| Ralf Baechle | 1d74f6b | 2005-05-09 13:16:07 +0000 | [diff] [blame] | 76 | 	return cpu_has_fpu && __is_fpu_owner(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | } | 
 | 78 |  | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 79 | static inline void __own_fpu(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | { | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 81 | 	__enable_fpu(); | 
 | 82 | 	KSTK_STATUS(current) |= ST0_CU1; | 
 | 83 | 	set_thread_flag(TIF_USEDFPU); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | } | 
 | 85 |  | 
| Atsushi Nemoto | faea623 | 2007-04-16 23:19:44 +0900 | [diff] [blame] | 86 | static inline void own_fpu_inatomic(int restore) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | { | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 88 | 	if (cpu_has_fpu && !__is_fpu_owner()) { | 
 | 89 | 		__own_fpu(); | 
 | 90 | 		if (restore) | 
 | 91 | 			_restore_fp(current); | 
 | 92 | 	} | 
| Atsushi Nemoto | faea623 | 2007-04-16 23:19:44 +0900 | [diff] [blame] | 93 | } | 
 | 94 |  | 
 | 95 | static inline void own_fpu(int restore) | 
 | 96 | { | 
 | 97 | 	preempt_disable(); | 
 | 98 | 	own_fpu_inatomic(restore); | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 99 | 	preempt_enable(); | 
 | 100 | } | 
 | 101 |  | 
 | 102 | static inline void lose_fpu(int save) | 
 | 103 | { | 
 | 104 | 	preempt_disable(); | 
 | 105 | 	if (is_fpu_owner()) { | 
 | 106 | 		if (save) | 
 | 107 | 			_save_fp(current); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | 		KSTK_STATUS(current) &= ~ST0_CU1; | 
| Ralf Baechle | 42a3b4f | 2005-09-03 15:56:17 -0700 | [diff] [blame] | 109 | 		clear_thread_flag(TIF_USEDFPU); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | 		__disable_fpu(); | 
 | 111 | 	} | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 112 | 	preempt_enable(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 113 | } | 
 | 114 |  | 
 | 115 | static inline void init_fpu(void) | 
 | 116 | { | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 117 | 	preempt_disable(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | 	if (cpu_has_fpu) { | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 119 | 		__own_fpu(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | 		_init_fpu(); | 
 | 121 | 	} else { | 
 | 122 | 		fpu_emulator_init_fpu(); | 
 | 123 | 	} | 
| Atsushi Nemoto | 53dc802 | 2007-03-10 01:07:45 +0900 | [diff] [blame] | 124 | 	preempt_enable(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | } | 
 | 126 |  | 
 | 127 | static inline void save_fp(struct task_struct *tsk) | 
 | 128 | { | 
 | 129 | 	if (cpu_has_fpu) | 
 | 130 | 		_save_fp(tsk); | 
 | 131 | } | 
 | 132 |  | 
 | 133 | static inline void restore_fp(struct task_struct *tsk) | 
 | 134 | { | 
 | 135 | 	if (cpu_has_fpu) | 
 | 136 | 		_restore_fp(tsk); | 
 | 137 | } | 
 | 138 |  | 
 | 139 | static inline fpureg_t *get_fpu_regs(struct task_struct *tsk) | 
 | 140 | { | 
| Atsushi Nemoto | e04582b | 2006-10-09 00:10:01 +0900 | [diff] [blame] | 141 | 	if (tsk == current) { | 
 | 142 | 		preempt_disable(); | 
 | 143 | 		if (is_fpu_owner()) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 144 | 			_save_fp(current); | 
| Atsushi Nemoto | e04582b | 2006-10-09 00:10:01 +0900 | [diff] [blame] | 145 | 		preempt_enable(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | 	} | 
 | 147 |  | 
| Atsushi Nemoto | eae8907 | 2006-05-16 01:26:03 +0900 | [diff] [blame] | 148 | 	return tsk->thread.fpu.fpr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 149 | } | 
 | 150 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 151 | #endif /* _ASM_FPU_H */ |