diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-02-19 05:17:42 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-02-19 05:19:05 -0500 |
commit | f353e612304ba752d6b613dc02eae8116cd3e27b (patch) | |
tree | a43ba46e221d91e5b958f9e30a23139166947f78 | |
parent | e07e0d4cb0c4bfe822ec8491cc06269096a38bea (diff) | |
parent | 728e53fef429a0f3c9dda3587c3ccc57ad268b70 (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.h | 82 | ||||
-rw-r--r-- | arch/x86/kernel/i387.c | 13 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 2 |
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); | |||
67 | static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} | 67 | static 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 | */ | ||
77 | static 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 | */ | ||
87 | static inline void task_disable_lazy_fpu_restore(struct task_struct *tsk) | ||
88 | { | ||
89 | tsk->thread.fpu.last_cpu = ~0; | ||
90 | } | ||
91 | |||
92 | static 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 | |||
70 | static inline int is_ia32_compat_frame(void) | 98 | static 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 | */ |
401 | typedef struct { int preload; } fpu_switch_t; | 429 | typedef 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 | */ | ||
410 | static inline void __cpu_disable_lazy_restore(unsigned int cpu) | ||
411 | { | ||
412 | per_cpu(fpu_owner_task, cpu) = NULL; | ||
413 | } | ||
414 | |||
415 | static 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 | |||
421 | static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu) | 431 | static 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 | */ | ||
525 | static 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 | */ |
543 | static inline unsigned short get_fpu_cwd(struct task_struct *tsk) | 539 | static 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 | } |
128 | EXPORT_SYMBOL(unlazy_fpu); | 131 | EXPORT_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; |