Module: xenomai-forge
Branch: next
Commit: 2ea6a9cd6861880b6f039e8e8c746a22ddc60a32
URL:    
http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=2ea6a9cd6861880b6f039e8e8c746a22ddc60a32

Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>
Date:   Sun Sep 29 22:43:03 2013 +0200

x86: handle preemption in kernel_fpu_begin/kernel_fpu_end section

---

 .../cobalt/arch/x86/include/asm/xenomai/fptest.h   |    1 -
 .../cobalt/arch/x86/include/asm/xenomai/thread.h   |    2 +
 kernel/cobalt/arch/x86/thread.c                    |   44 +++++++++++++------
 3 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h 
b/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
index 5932297..a05d54e 100644
--- a/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
+++ b/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
@@ -44,7 +44,6 @@ static inline int fp_linux_begin(void)
        }
        return -EBUSY;
 #endif /* 3DNow or RAID 456 */
-       return -EBUSY;
        kernel_fpu_begin();
        /* kernel_fpu_begin() does no re-initialize the fpu context, but
           fp_regs_set() implicitely expects an initialized fpu context, so
diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h 
b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
index 3e0e8be..5d4c7ca 100644
--- a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
+++ b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
@@ -36,6 +36,8 @@ struct xnarchtcb {
        unsigned long *ipp;
        x86_fpustate *fpup;
        unsigned int is_root: 1;
+       unsigned int root_kfpu: 1;
+       unsigned int root_used_math: 1;
        struct {
                unsigned long ip;
                unsigned long ax;
diff --git a/kernel/cobalt/arch/x86/thread.c b/kernel/cobalt/arch/x86/thread.c
index dc7e5fa..24363df 100644
--- a/kernel/cobalt/arch/x86/thread.c
+++ b/kernel/cobalt/arch/x86/thread.c
@@ -83,17 +83,6 @@ static inline void do_switch_threads(struct xnarchtcb 
*out_tcb,
 
 #endif /* CONFIG_X86_64 */
 
-void xnarch_leave_root(struct xnarchtcb *rootcb)
-{
-       struct task_struct *p = current;
-
-#ifdef CONFIG_X86_64
-       rootcb->spp = &p->thread.sp;
-       rootcb->ipp = &p->thread.rip;
-#endif
-       rootcb->fpup = x86_fpustate_ptr(&p->thread);
-}
-
 void xnarch_switch_to(struct xnarchtcb *out_tcb, struct xnarchtcb *in_tcb)
 {
        unsigned long __maybe_unused fs, gs;
@@ -255,6 +244,25 @@ int xnarch_handle_fpu_fault(struct xnarchtcb *tcb)
        return 1;
 }
 
+void xnarch_leave_root(struct xnarchtcb *rootcb)
+{
+       struct task_struct *p = current;
+
+#ifdef CONFIG_X86_64
+       rootcb->spp = &p->thread.sp;
+       rootcb->ipp = &p->thread.rip;
+#endif
+       rootcb->fpup = x86_fpustate_ptr(&p->thread);
+       rootcb->root_kfpu = 
+               (read_cr0() & 8) == 0 && wrap_test_fpu_used(p) == 0;
+       if (rootcb->root_kfpu) {
+               rootcb->root_used_math = tsk_used_math(p) != 0;
+               x86_fpustate_ptr(&p->thread) = &rootcb->i387;
+               wrap_set_fpu_used(p);
+               set_stopped_child_used_math(p);
+       }
+}
+
 void xnarch_save_fpu(struct xnarchtcb *tcb)
 {
        /* Already saved by __switch_to */
@@ -264,7 +272,7 @@ void xnarch_restore_fpu(struct xnarchtcb *tcb)
 {
        struct task_struct *p = tcb->core.host_task;
 
-       if (tcb->is_root || tsk_used_math(p) == 0)
+       if (tcb->root_kfpu == 0 && (tsk_used_math(p) == 0 || tcb->is_root))
                /* Restore lazy mode */
                return;
 
@@ -274,8 +282,14 @@ void xnarch_restore_fpu(struct xnarchtcb *tcb)
         */
        clts();
 
-       __do_restore_i387(tcb->fpup);
-       wrap_set_fpu_used(p);
+       __do_restore_i387(x86_fpustate_ptr(&p->thread));
+       if (tcb->root_kfpu) {
+               x86_fpustate_ptr(&p->thread) = tcb->fpup;
+               wrap_clear_fpu_used(p);
+               if (tcb->root_used_math == 0)
+                       clear_stopped_child_used_math(p);
+       } else
+               wrap_set_fpu_used(p);
 }
 
 void xnarch_enable_fpu(struct xnarchtcb *tcb)
@@ -292,6 +306,7 @@ void xnarch_init_root_tcb(struct xnarchtcb *tcb)
        tcb->ipp = &tcb->ip;
        tcb->is_root = 1;
        tcb->fpup = NULL;
+       tcb->root_kfpu = 0;
 }
 
 void xnarch_init_shadow_tcb(struct xnarchtcb *tcb)
@@ -306,6 +321,7 @@ void xnarch_init_shadow_tcb(struct xnarchtcb *tcb)
        tcb->ipp = &p->thread.rip; /* <!> raw naming intended. */
 #endif
        tcb->fpup = x86_fpustate_ptr(&p->thread);
+       tcb->root_kfpu = 0;
 }
 
 int xnarch_escalate(void)


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to