aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
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
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')
-rw-r--r--arch/x86/include/asm/i387.h78
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/i387.c80
3 files changed, 84 insertions, 76 deletions
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index 247904945d3f..0c1031d354f2 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -419,70 +419,9 @@ static inline void __clear_fpu(struct task_struct *tsk)
419 } 419 }
420} 420}
421 421
422/* 422extern bool irq_fpu_usable(void);
423 * Were we in an interrupt that interrupted kernel mode? 423extern void kernel_fpu_begin(void);
424 * 424extern void kernel_fpu_end(void);
425 * We can do a kernel_fpu_begin/end() pair *ONLY* if that
426 * pair does nothing at all: the thread must not have fpu (so
427 * that we don't try to save the FPU state), and TS must
428 * be set (so that the clts/stts pair does nothing that is
429 * visible in the interrupted kernel thread).
430 */
431static inline bool interrupted_kernel_fpu_idle(void)
432{
433 return !__thread_has_fpu(current) &&
434 (read_cr0() & X86_CR0_TS);
435}
436
437/*
438 * Were we in user mode (or vm86 mode) when we were
439 * interrupted?
440 *
441 * Doing kernel_fpu_begin/end() is ok if we are running
442 * in an interrupt context from user mode - we'll just
443 * save the FPU state as required.
444 */
445static inline bool interrupted_user_mode(void)
446{
447 struct pt_regs *regs = get_irq_regs();
448 return regs && user_mode_vm(regs);
449}
450
451/*
452 * Can we use the FPU in kernel mode with the
453 * whole "kernel_fpu_begin/end()" sequence?
454 *
455 * It's always ok in process context (ie "not interrupt")
456 * but it is sometimes ok even from an irq.
457 */
458static inline bool irq_fpu_usable(void)
459{
460 return !in_interrupt() ||
461 interrupted_user_mode() ||
462 interrupted_kernel_fpu_idle();
463}
464
465static inline void kernel_fpu_begin(void)
466{
467 struct task_struct *me = current;
468
469 WARN_ON_ONCE(!irq_fpu_usable());
470 preempt_disable();
471 if (__thread_has_fpu(me)) {
472 __save_init_fpu(me);
473 __thread_clear_has_fpu(me);
474 /* We do 'stts()' in kernel_fpu_end() */
475 } else {
476 percpu_write(fpu_owner_task, NULL);
477 clts();
478 }
479}
480
481static inline void kernel_fpu_end(void)
482{
483 stts();
484 preempt_enable();
485}
486 425
487/* 426/*
488 * Some instructions like VIA's padlock instructions generate a spurious 427 * Some instructions like VIA's padlock instructions generate a spurious
@@ -566,16 +505,7 @@ static inline void save_init_fpu(struct task_struct *tsk)
566 preempt_enable(); 505 preempt_enable();
567} 506}
568 507
569static inline void unlazy_fpu(struct task_struct *tsk) 508extern void unlazy_fpu(struct task_struct *tsk);
570{
571 preempt_disable();
572 if (__thread_has_fpu(tsk)) {
573 __save_init_fpu(tsk);
574 __thread_fpu_end(tsk);
575 } else
576 tsk->fpu_counter = 0;
577 preempt_enable();
578}
579 509
580static inline void clear_fpu(struct task_struct *tsk) 510static inline void clear_fpu(struct task_struct *tsk)
581{ 511{
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index c0f7d68d318f..cb71b01ab66e 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1045,7 +1045,6 @@ DEFINE_PER_CPU(char *, irq_stack_ptr) =
1045DEFINE_PER_CPU(unsigned int, irq_count) = -1; 1045DEFINE_PER_CPU(unsigned int, irq_count) = -1;
1046 1046
1047DEFINE_PER_CPU(struct task_struct *, fpu_owner_task); 1047DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
1048EXPORT_PER_CPU_SYMBOL(fpu_owner_task);
1049 1048
1050/* 1049/*
1051 * Special IST stacks which the CPU switches to when it calls 1050 * Special IST stacks which the CPU switches to when it calls
@@ -1115,7 +1114,6 @@ void debug_stack_reset(void)
1115DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; 1114DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
1116EXPORT_PER_CPU_SYMBOL(current_task); 1115EXPORT_PER_CPU_SYMBOL(current_task);
1117DEFINE_PER_CPU(struct task_struct *, fpu_owner_task); 1116DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
1118EXPORT_PER_CPU_SYMBOL(fpu_owner_task);
1119 1117
1120#ifdef CONFIG_CC_STACKPROTECTOR 1118#ifdef CONFIG_CC_STACKPROTECTOR
1121DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); 1119DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 739d8598f789..17b7549c4134 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