Module: xenomai-2.6
Branch: master
Commit: 32d6f5d240fe53bb169514ebb1dd1d1eae4b2edc
URL:    
http://git.xenomai.org/?p=xenomai-2.6.git;a=commit;h=32d6f5d240fe53bb169514ebb1dd1d1eae4b2edc

Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>
Date:   Sun Jan 18 12:24:47 2015 +0100

hal/arm: simplify fpu handling

Currently, when returning to root domain while fpu context has not been
altered by real-time domain, fpu is unconditionnaly re-enabled on UP
systems. This causes a problem starting with kernel 3.16 which handles
FPU faults with irqs on: if the fpu is reenabled on this path, Linux
assumes that the fault can not be caused by the fpu not being enabled
resulting in a fallback to the "undefined instruction" handler.

To avoid this, test whether fpu is enabled when leaving the root domain
and restore the fpu context exactly as it was before the preemption by
the real-time domain.

---

 include/asm-arm/bits/pod.h |   42 +++++++++++-------------------------------
 include/asm-arm/hal.h      |    1 +
 include/asm-arm/system.h   |    3 ++-
 3 files changed, 14 insertions(+), 32 deletions(-)

diff --git a/include/asm-arm/bits/pod.h b/include/asm-arm/bits/pod.h
index 53a692e..349bd9e 100644
--- a/include/asm-arm/bits/pod.h
+++ b/include/asm-arm/bits/pod.h
@@ -49,6 +49,7 @@ static inline void xnarch_leave_root(xnarchtcb_t * rootcb)
 #ifdef CONFIG_XENO_HW_FPU
 #ifdef CONFIG_VFP
        rootcb->fpup = rthal_get_fpu_owner();
+       rootcb->root_fpu_en = rthal_fpu_enabled_p();
 #else /* !CONFIG_VFP */
        rootcb->user_fpu_owner = rthal_get_fpu_owner(rootcb->user_task);
        /* So that xnarch_save_fpu() will operate on the right FPU area. */
@@ -144,33 +145,11 @@ static inline void xnarch_enable_fpu(xnarchtcb_t *tcb)
                /* No exception should be pending, since it should have caused
                   a trap earlier.
                */
-       } else if (tcb->fpup && tcb->fpup == rthal_task_fpenv(tcb->user_task)) {
-               unsigned fpexc = rthal_enable_fpu();
-               unsigned cpu;
-#ifndef CONFIG_SMP
-               if (likely(!(fpexc & RTHAL_VFP_ANY_EXC)
-                          && !(rthal_vfp_fmrx(FPSCR) & FPSCR_IXE)))
-                       return;
-               /*
-                  If current process has pending exceptions it is
-                  illegal to restore the FPEXC register with them, we must
-                  save the fpu state and disable them, to get linux
-                  fpu fault handler take care of them correctly.
-               */
-#endif
-               /*
-                  On SMP systems, if we are restoring the root
-                  thread, running the task holding the FPU context at
-                  the time when we switched to real-time domain,
-                  forcibly save the FPU context. It seems to fix SMP
-                  systems for still unknown reasons.
-               */
-               rthal_save_fpu(tcb->fpup, fpexc);
-
-               cpu = rthal_processor_id();
-               vfp_current_hw_state[cpu] = NULL;
-               rthal_disable_fpu();
+               return;
        }
+
+       if (tcb->root_fpu_en)
+               rthal_enable_fpu();
 #else /* !CONFIG_VFP */
        if (!tcb->user_task)
                rthal_enable_fpu();
@@ -218,7 +197,9 @@ static inline void xnarch_restore_fpu(xnarchtcb_t * tcb)
        if (likely(!tcb->is_root)) {
                rthal_enable_fpu();
                rthal_restore_fpu(tcb->fpup);
-       } else {
+               return;
+       }
+
        /* We are restoring the Linux current thread which does not own the FPU
           context, so the FPU must be disabled, so that a fault will occur if
           the newly switched thread uses the FPU, to allow the kernel handler
@@ -229,10 +210,9 @@ static inline void xnarch_restore_fpu(xnarchtcb_t * tcb)
           task, into the FPU area of the last non RT task which used the FPU
           before the preemption by Xenomai.
        */
-               unsigned cpu = rthal_processor_id();
-               vfp_current_hw_state[cpu] = NULL;
-               rthal_disable_fpu();
-       }
+       unsigned cpu = rthal_processor_id();
+       vfp_current_hw_state[cpu] = NULL;
+       rthal_disable_fpu();
 #else /* !CONFIG_VFP */
        if (tcb->fpup) {
                rthal_restore_fpu(tcb->fpup);
diff --git a/include/asm-arm/hal.h b/include/asm-arm/hal.h
index f23b2b6..25d3f5d 100644
--- a/include/asm-arm/hal.h
+++ b/include/asm-arm/hal.h
@@ -334,6 +334,7 @@ static inline rthal_fpenv_t *rthal_get_fpu_owner(void)
        _fpexc;                                                 \
     })
 
+#define rthal_fpu_enabled_p() !!(rthal_vfp_fmrx(FPEXC) & FPEXC_EN)
 
 #else /* !CONFIG_VFP */
 static inline void rthal_save_fpu(rthal_fpenv_t *fpuenv)
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index 7b47ce6..a49d931 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -53,7 +53,8 @@ typedef struct xnarchtcb {  /* Per-thread arch-dependent 
block */
           - last_task_used_math for Linux US threads (only current or NULL 
when MP)
           - current for RT US threads.
        */
-       unsigned is_root;
+       unsigned is_root : 1;
+       unsigned root_fpu_en : 1;
 #define xnarch_fpu_ptr(tcb)    ((tcb)->fpup)
 #else /* !CONFIG_XENO_HW_FPU */
 #define xnarch_fpu_ptr(tcb)    NULL


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

Reply via email to