aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-02-19 05:17:42 -0500
committerIngo Molnar <mingo@kernel.org>2015-02-19 05:19:05 -0500
commitf353e612304ba752d6b613dc02eae8116cd3e27b (patch)
treea43ba46e221d91e5b958f9e30a23139166947f78
parente07e0d4cb0c4bfe822ec8491cc06269096a38bea (diff)
parent728e53fef429a0f3c9dda3587c3ccc57ad268b70 (diff)
Merge branch 'tip-x86-fpu' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp into x86/fpu
Pull FPU updates from Borislav Petkov: "A round of updates to the FPU maze from Oleg and Rik. It should make the code a bit more understandable/readable/streamlined and a preparation for more cleanups and improvements in that area." Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/fpu-internal.h82
-rw-r--r--arch/x86/kernel/i387.c13
-rw-r--r--arch/x86/kernel/process.c2
-rw-r--r--arch/x86/kernel/traps.c2
4 files changed, 49 insertions, 50 deletions
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index 0dbc08282291..61609b963eab 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -67,6 +67,34 @@ extern void finit_soft_fpu(struct i387_soft_struct *soft);
67static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} 67static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
68#endif 68#endif
69 69
70/*
71 * Must be run with preemption disabled: this clears the fpu_owner_task,
72 * on this CPU.
73 *
74 * This will disable any lazy FPU state restore of the current FPU state,
75 * but if the current thread owns the FPU, it will still be saved by.
76 */
77static inline void __cpu_disable_lazy_restore(unsigned int cpu)
78{
79 per_cpu(fpu_owner_task, cpu) = NULL;
80}
81
82/*
83 * Used to indicate that the FPU state in memory is newer than the FPU
84 * state in registers, and the FPU state should be reloaded next time the
85 * task is run. Only safe on the current task, or non-running tasks.
86 */
87static inline void task_disable_lazy_fpu_restore(struct task_struct *tsk)
88{
89 tsk->thread.fpu.last_cpu = ~0;
90}
91
92static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
93{
94 return new == this_cpu_read_stable(fpu_owner_task) &&
95 cpu == new->thread.fpu.last_cpu;
96}
97
70static inline int is_ia32_compat_frame(void) 98static inline int is_ia32_compat_frame(void)
71{ 99{
72 return config_enabled(CONFIG_IA32_EMULATION) && 100 return config_enabled(CONFIG_IA32_EMULATION) &&
@@ -400,24 +428,6 @@ static inline void drop_init_fpu(struct task_struct *tsk)
400 */ 428 */
401typedef struct { int preload; } fpu_switch_t; 429typedef struct { int preload; } fpu_switch_t;
402 430
403/*
404 * Must be run with preemption disabled: this clears the fpu_owner_task,
405 * on this CPU.
406 *
407 * This will disable any lazy FPU state restore of the current FPU state,
408 * but if the current thread owns the FPU, it will still be saved by.
409 */
410static inline void __cpu_disable_lazy_restore(unsigned int cpu)
411{
412 per_cpu(fpu_owner_task, cpu) = NULL;
413}
414
415static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
416{
417 return new == this_cpu_read_stable(fpu_owner_task) &&
418 cpu == new->thread.fpu.last_cpu;
419}
420
421static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu) 431static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu)
422{ 432{
423 fpu_switch_t fpu; 433 fpu_switch_t fpu;
@@ -426,13 +436,17 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
426 * If the task has used the math, pre-load the FPU on xsave processors 436 * If the task has used the math, pre-load the FPU on xsave processors
427 * or if the past 5 consecutive context-switches used math. 437 * or if the past 5 consecutive context-switches used math.
428 */ 438 */
429 fpu.preload = tsk_used_math(new) && (use_eager_fpu() || 439 fpu.preload = tsk_used_math(new) &&
430 new->thread.fpu_counter > 5); 440 (use_eager_fpu() || new->thread.fpu_counter > 5);
441
431 if (__thread_has_fpu(old)) { 442 if (__thread_has_fpu(old)) {
432 if (!__save_init_fpu(old)) 443 if (!__save_init_fpu(old))
433 cpu = ~0; 444 task_disable_lazy_fpu_restore(old);
434 old->thread.fpu.last_cpu = cpu; 445 else
435 old->thread.fpu.has_fpu = 0; /* But leave fpu_owner_task! */ 446 old->thread.fpu.last_cpu = cpu;
447
448 /* But leave fpu_owner_task! */
449 old->thread.fpu.has_fpu = 0;
436 450
437 /* Don't change CR0.TS if we just switch! */ 451 /* Don't change CR0.TS if we just switch! */
438 if (fpu.preload) { 452 if (fpu.preload) {
@@ -443,10 +457,10 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
443 stts(); 457 stts();
444 } else { 458 } else {
445 old->thread.fpu_counter = 0; 459 old->thread.fpu_counter = 0;
446 old->thread.fpu.last_cpu = ~0; 460 task_disable_lazy_fpu_restore(old);
447 if (fpu.preload) { 461 if (fpu.preload) {
448 new->thread.fpu_counter++; 462 new->thread.fpu_counter++;
449 if (!use_eager_fpu() && fpu_lazy_restore(new, cpu)) 463 if (fpu_lazy_restore(new, cpu))
450 fpu.preload = 0; 464 fpu.preload = 0;
451 else 465 else
452 prefetch(new->thread.fpu.state); 466 prefetch(new->thread.fpu.state);
@@ -520,24 +534,6 @@ static inline void __save_fpu(struct task_struct *tsk)
520} 534}
521 535
522/* 536/*
523 * These disable preemption on their own and are safe
524 */
525static inline void save_init_fpu(struct task_struct *tsk)
526{
527 WARN_ON_ONCE(!__thread_has_fpu(tsk));
528
529 if (use_eager_fpu()) {
530 __save_fpu(tsk);
531 return;
532 }
533
534 preempt_disable();
535 __save_init_fpu(tsk);
536 __thread_fpu_end(tsk);
537 preempt_enable();
538}
539
540/*
541 * i387 state interaction 537 * i387 state interaction
542 */ 538 */
543static inline unsigned short get_fpu_cwd(struct task_struct *tsk) 539static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 81049ffab2d6..f59d80622e60 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -119,10 +119,13 @@ void unlazy_fpu(struct task_struct *tsk)
119{ 119{
120 preempt_disable(); 120 preempt_disable();
121 if (__thread_has_fpu(tsk)) { 121 if (__thread_has_fpu(tsk)) {
122 __save_init_fpu(tsk); 122 if (use_eager_fpu()) {
123 __thread_fpu_end(tsk); 123 __save_fpu(tsk);
124 } else 124 } else {
125 tsk->thread.fpu_counter = 0; 125 __save_init_fpu(tsk);
126 __thread_fpu_end(tsk);
127 }
128 }
126 preempt_enable(); 129 preempt_enable();
127} 130}
128EXPORT_SYMBOL(unlazy_fpu); 131EXPORT_SYMBOL(unlazy_fpu);
@@ -246,7 +249,7 @@ int init_fpu(struct task_struct *tsk)
246 if (tsk_used_math(tsk)) { 249 if (tsk_used_math(tsk)) {
247 if (cpu_has_fpu && tsk == current) 250 if (cpu_has_fpu && tsk == current)
248 unlazy_fpu(tsk); 251 unlazy_fpu(tsk);
249 tsk->thread.fpu.last_cpu = ~0; 252 task_disable_lazy_fpu_restore(tsk);
250 return 0; 253 return 0;
251 } 254 }
252 255
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e127ddaa2d5a..ce8b10351e28 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -68,8 +68,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
68 68
69 dst->thread.fpu_counter = 0; 69 dst->thread.fpu_counter = 0;
70 dst->thread.fpu.has_fpu = 0; 70 dst->thread.fpu.has_fpu = 0;
71 dst->thread.fpu.last_cpu = ~0;
72 dst->thread.fpu.state = NULL; 71 dst->thread.fpu.state = NULL;
72 task_disable_lazy_fpu_restore(dst);
73 if (tsk_used_math(src)) { 73 if (tsk_used_math(src)) {
74 int err = fpu_alloc(&dst->thread.fpu); 74 int err = fpu_alloc(&dst->thread.fpu);
75 if (err) 75 if (err)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 9d2073e2ecc9..92b83e299ed3 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -734,7 +734,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
734 /* 734 /*
735 * Save the info for the exception handler and clear the error. 735 * Save the info for the exception handler and clear the error.
736 */ 736 */
737 save_init_fpu(task); 737 unlazy_fpu(task);
738 task->thread.trap_nr = trapnr; 738 task->thread.trap_nr = trapnr;
739 task->thread.error_code = error_code; 739 task->thread.error_code = error_code;
740 info.si_signo = SIGFPE; 740 info.si_signo = SIGFPE;