aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/i387.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-02-21 13:25:45 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2012-02-21 17:12:46 -0500
commit8546c008924d5fd1724fa698eaa92b414bafd50d (patch)
treefe2d3f50b350c884201c57ca6c331dd867c5d1e8 /arch/x86/kernel/i387.c
parent27e74da9800289e69ba907777df1e2085231eff7 (diff)
i387: Uninline the generic FP helpers that we expose to kernel modules
Instead of exporting the very low-level internals of the FPU state save/restore code (ie things like 'fpu_owner_task'), we should export the higher-level interfaces. Inlining these things is pointless anyway: sure, sometimes the end result is small, but while 'stts()' can result in just three x86 instructions, those are not cheap instructions (writing %cr0 is a serializing instruction and a very slow one at that). So the overhead of a function call is not noticeable, and we really don't want random modules mucking about with our internal state save logic anyway. So this unexports 'fpu_owner_task', and instead uninlines and exports the actual functions that modules can use: fpu_kernel_begin/end() and unlazy_fpu(). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1202211339590.5354@i5.linux-foundation.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/i387.c')
-rw-r--r--arch/x86/kernel/i387.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 739d8598f78..17b7549c413 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -32,6 +32,86 @@
32# define user32_fxsr_struct user_fxsr_struct 32# define user32_fxsr_struct user_fxsr_struct
33#endif 33#endif
34 34
35/*
36 * Were we in an interrupt that interrupted kernel mode?
37 *
38 * We can do a kernel_fpu_begin/end() pair *ONLY* if that
39 * pair does nothing at all: the thread must not have fpu (so
40 * that we don't try to save the FPU state), and TS must
41 * be set (so that the clts/stts pair does nothing that is
42 * visible in the interrupted kernel thread).
43 */
44static inline bool interrupted_kernel_fpu_idle(void)
45{
46 return !__thread_has_fpu(current) &&
47 (read_cr0() & X86_CR0_TS);
48}
49
50/*
51 * Were we in user mode (or vm86 mode) when we were
52 * interrupted?
53 *
54 * Doing kernel_fpu_begin/end() is ok if we are running
55 * in an interrupt context from user mode - we'll just
56 * save the FPU state as required.
57 */
58static inline bool interrupted_user_mode(void)
59{
60 struct pt_regs *regs = get_irq_regs();
61 return regs && user_mode_vm(regs);
62}
63
64/*
65 * Can we use the FPU in kernel mode with the
66 * whole "kernel_fpu_begin/end()" sequence?
67 *
68 * It's always ok in process context (ie "not interrupt")
69 * but it is sometimes ok even from an irq.
70 */
71bool irq_fpu_usable(void)
72{
73 return !in_interrupt() ||
74 interrupted_user_mode() ||
75 interrupted_kernel_fpu_idle();
76}
77EXPORT_SYMBOL(irq_fpu_usable);
78
79void kernel_fpu_begin(void)
80{
81 struct task_struct *me = current;
82
83 WARN_ON_ONCE(!irq_fpu_usable());
84 preempt_disable();
85 if (__thread_has_fpu(me)) {
86 __save_init_fpu(me);
87 __thread_clear_has_fpu(me);
88 /* We do 'stts()' in kernel_fpu_end() */
89 } else {
90 percpu_write(fpu_owner_task, NULL);
91 clts();
92 }
93}
94EXPORT_SYMBOL(kernel_fpu_begin);
95
96void kernel_fpu_end(void)
97{
98 stts();
99 preempt_enable();
100}
101EXPORT_SYMBOL(kernel_fpu_end);
102
103void unlazy_fpu(struct task_struct *tsk)
104{
105 preempt_disable();
106 if (__thread_has_fpu(tsk)) {
107 __save_init_fpu(tsk);
108 __thread_fpu_end(tsk);
109 } else
110 tsk->fpu_counter = 0;
111 preempt_enable();
112}
113EXPORT_SYMBOL(unlazy_fpu);
114
35#ifdef CONFIG_MATH_EMULATION 115#ifdef CONFIG_MATH_EMULATION
36# define HAVE_HWFP (boot_cpu_data.hard_math) 116# define HAVE_HWFP (boot_cpu_data.hard_math)
37#else 117#else