lkml.org 
[lkml]   [2012]   [Feb]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    SubjectRe: [PATCH v2 3/3] i387: support lazy restore of FPU state
    On Mon, Feb 20, 2012 at 6:14 PM, H. Peter Anvin <hpa@zytor.com> wrote:
    > On 02/20/2012 06:10 PM, Linus Torvalds wrote:
    >>
    >> Although I do wonder if we should just make kernel_fpu_begin() be a
    >> real function instead of inlining it. I'm not sure it makes sense to
    >> inline that thing, and it might be better to export that one instead.
    >> Comments?
    >
    > I would agree with that.

    So I have a patch that does that, but it's noticeably bigger.

    It uninlines a fair amount of i387.h, and moves it into i387.c. I do
    think it's probably the right thing to do, though.

    I did a "make allmodconfig" with this on x86-64, but it's quite
    possible that x86-32 does additional cases. Does this patch work for
    people?

    (This is *on*top*of* the quick "let's just get it to work" patch that
    just exports the new percpu variable. I already committed that and
    pushed it out, since I wanted a quick fix so that people wouldn't be
    held up by this)

    IOW, if you can try this on top of current -git, that would be lovely.

    Linus
    arch/x86/include/asm/i387.h | 78 ++--------------------------------------
    arch/x86/kernel/cpu/common.c | 2 -
    arch/x86/kernel/i387.c | 80 ++++++++++++++++++++++++++++++++++++++++++
    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)
    }
    }

    -/*
    - * Were we in an interrupt that interrupted kernel mode?
    - *
    - * We can do a kernel_fpu_begin/end() pair *ONLY* if that
    - * pair does nothing at all: the thread must not have fpu (so
    - * that we don't try to save the FPU state), and TS must
    - * be set (so that the clts/stts pair does nothing that is
    - * visible in the interrupted kernel thread).
    - */
    -static inline bool interrupted_kernel_fpu_idle(void)
    -{
    - return !__thread_has_fpu(current) &&
    - (read_cr0() & X86_CR0_TS);
    -}
    -
    -/*
    - * Were we in user mode (or vm86 mode) when we were
    - * interrupted?
    - *
    - * Doing kernel_fpu_begin/end() is ok if we are running
    - * in an interrupt context from user mode - we'll just
    - * save the FPU state as required.
    - */
    -static inline bool interrupted_user_mode(void)
    -{
    - struct pt_regs *regs = get_irq_regs();
    - return regs && user_mode_vm(regs);
    -}
    -
    -/*
    - * Can we use the FPU in kernel mode with the
    - * whole "kernel_fpu_begin/end()" sequence?
    - *
    - * It's always ok in process context (ie "not interrupt")
    - * but it is sometimes ok even from an irq.
    - */
    -static inline bool irq_fpu_usable(void)
    -{
    - return !in_interrupt() ||
    - interrupted_user_mode() ||
    - interrupted_kernel_fpu_idle();
    -}
    -
    -static inline void kernel_fpu_begin(void)
    -{
    - struct task_struct *me = current;
    -
    - WARN_ON_ONCE(!irq_fpu_usable());
    - preempt_disable();
    - if (__thread_has_fpu(me)) {
    - __save_init_fpu(me);
    - __thread_clear_has_fpu(me);
    - /* We do 'stts()' in kernel_fpu_end() */
    - } else {
    - percpu_write(fpu_owner_task, NULL);
    - clts();
    - }
    -}
    -
    -static inline void kernel_fpu_end(void)
    -{
    - stts();
    - preempt_enable();
    -}
    +extern bool irq_fpu_usable(void);
    +extern void kernel_fpu_begin(void);
    +extern void kernel_fpu_end(void);

    /*
    * Some instructions like VIA's padlock instructions generate a spurious
    @@ -566,16 +505,7 @@ static inline void save_init_fpu(struct task_struct *tsk)
    preempt_enable();
    }

    -static inline void unlazy_fpu(struct task_struct *tsk)
    -{
    - preempt_disable();
    - if (__thread_has_fpu(tsk)) {
    - __save_init_fpu(tsk);
    - __thread_fpu_end(tsk);
    - } else
    - tsk->fpu_counter = 0;
    - preempt_enable();
    -}
    +extern void unlazy_fpu(struct task_struct *tsk);

    static inline void clear_fpu(struct task_struct *tsk)
    {
    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) =
    DEFINE_PER_CPU(unsigned int, irq_count) = -1;

    DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
    -EXPORT_PER_CPU_SYMBOL(fpu_owner_task);

    /*
    * Special IST stacks which the CPU switches to when it calls
    @@ -1115,7 +1114,6 @@ void debug_stack_reset(void)
    DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
    EXPORT_PER_CPU_SYMBOL(current_task);
    DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
    -EXPORT_PER_CPU_SYMBOL(fpu_owner_task);

    #ifdef CONFIG_CC_STACKPROTECTOR
    DEFINE_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 @@
    # define user32_fxsr_struct user_fxsr_struct
    #endif

    +/*
    + * Were we in an interrupt that interrupted kernel mode?
    + *
    + * We can do a kernel_fpu_begin/end() pair *ONLY* if that
    + * pair does nothing at all: the thread must not have fpu (so
    + * that we don't try to save the FPU state), and TS must
    + * be set (so that the clts/stts pair does nothing that is
    + * visible in the interrupted kernel thread).
    + */
    +static inline bool interrupted_kernel_fpu_idle(void)
    +{
    + return !__thread_has_fpu(current) &&
    + (read_cr0() & X86_CR0_TS);
    +}
    +
    +/*
    + * Were we in user mode (or vm86 mode) when we were
    + * interrupted?
    + *
    + * Doing kernel_fpu_begin/end() is ok if we are running
    + * in an interrupt context from user mode - we'll just
    + * save the FPU state as required.
    + */
    +static inline bool interrupted_user_mode(void)
    +{
    + struct pt_regs *regs = get_irq_regs();
    + return regs && user_mode_vm(regs);
    +}
    +
    +/*
    + * Can we use the FPU in kernel mode with the
    + * whole "kernel_fpu_begin/end()" sequence?
    + *
    + * It's always ok in process context (ie "not interrupt")
    + * but it is sometimes ok even from an irq.
    + */
    +bool irq_fpu_usable(void)
    +{
    + return !in_interrupt() ||
    + interrupted_user_mode() ||
    + interrupted_kernel_fpu_idle();
    +}
    +EXPORT_SYMBOL(irq_fpu_usable);
    +
    +void kernel_fpu_begin(void)
    +{
    + struct task_struct *me = current;
    +
    + WARN_ON_ONCE(!irq_fpu_usable());
    + preempt_disable();
    + if (__thread_has_fpu(me)) {
    + __save_init_fpu(me);
    + __thread_clear_has_fpu(me);
    + /* We do 'stts()' in kernel_fpu_end() */
    + } else {
    + percpu_write(fpu_owner_task, NULL);
    + clts();
    + }
    +}
    +EXPORT_SYMBOL(kernel_fpu_begin);
    +
    +void kernel_fpu_end(void)
    +{
    + stts();
    + preempt_enable();
    +}
    +EXPORT_SYMBOL(kernel_fpu_end);
    +
    +void unlazy_fpu(struct task_struct *tsk)
    +{
    + preempt_disable();
    + if (__thread_has_fpu(tsk)) {
    + __save_init_fpu(tsk);
    + __thread_fpu_end(tsk);
    + } else
    + tsk->fpu_counter = 0;
    + preempt_enable();
    +}
    +EXPORT_SYMBOL(unlazy_fpu);
    +
    #ifdef CONFIG_MATH_EMULATION
    # define HAVE_HWFP (boot_cpu_data.hard_math)
    #else
    \
     
     \ /
      Last update: 2012-02-21 06:31    [W:0.036 / U:60.088 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site