[PATCH v2 3/3] testsuite/switchtest: Add support for Dovetail >= 6.19
Florian Bezdeka <[email protected]>
| Newsgroups | dev.linux.lists.xenomai |
|---|---|
| Message-ID | <[email protected]> |
The background for this reworking is a recent change to Linux in 6.19:
commit 4fa617cc6851 ("arm64/fpsimd: Allocate kernel mode FP/SIMD
buffers on the stack")
expects all (non-preemtable) users to provide a buffer that is used
in case the calling task is scheduled out. NULL is only allowed when
preemption is disabled.
preempt_disable() has no impact on OOB tasks, so when an OOB task is
scheduled out the fpsimd code tries to save the FPU regs to NULL, which
(obviously) triggered a fault.
To be able to provide a struct user_fpsimd_state located on the stack
the complete FPU usage has to move into one function, now called
arch_cobalt_in_kernel_fpu_usage() and implemented by all architectures.
arm64 needs two implementations to stay compatible with older kernels.
Signed-off-by: Florian Bezdeka <[email protected]>
---
.../cobalt/arch/arm/include/asm/xenomai/fptest.h | 26 ++++---------
.../cobalt/arch/arm64/include/asm/xenomai/fptest.h | 43 ++++++++++++++++++----
.../cobalt/arch/x86/include/asm/xenomai/fptest.h | 41 ++++++++++++---------
kernel/drivers/testing/switchtest.c | 19 +++-------
4 files changed, 70 insertions(+), 59 deletions(-)
diff --git a/kernel/cobalt/arch/arm/include/asm/xenomai/fptest.h b/kernel/cobalt/arch/arm/include/asm/xenomai/fptest.h
index fc177fcb53bd259011a4a65f889c236f7c8e115e..f9f61109db07351283612f6e3a69a179c0a51e34 100644
--- a/kernel/cobalt/arch/arm/include/asm/xenomai/fptest.h
+++ b/kernel/cobalt/arch/arm/include/asm/xenomai/fptest.h
@@ -19,29 +19,17 @@
#ifndef _COBALT_ARM_FPTEST_H
#define _COBALT_ARM_FPTEST_H
-#include <linux/errno.h>
-#include <asm/hwcap.h>
-
-#ifdef CONFIG_VFP
-#define have_vfp (elf_hwcap & HWCAP_VFP)
-#else /* !CONFIG_VFP */
-#define have_vfp 0
-#endif /* !CONFIG_VFP */
-
-#include <asm/xenomai/uapi/fptest.h>
-
-static inline int fp_linux_begin(void)
-{
- return -ENOSYS;
-}
-
-static inline void fp_linux_end(void)
+static inline int cobalt_arch_fp_detect(void)
{
+ /* armhf: in-kernel-fpu-usage does not support preemption */
+ return 0;
}
-static inline int fp_detect(void)
+static inline unsigned int
+cobalt_arch_in_kernel_fpu_usage(unsigned int expected, rtdm_event_t *rt_synch,
+ int (*report)(const char *fmt, ...))
{
- return have_vfp ? __COBALT_HAVE_VFP : 0;
+ return 0;
}
#endif /* _COBALT_ARM_FPTEST_H */
diff --git a/kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h b/kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h
index 520cd38519db66ad25baecedd183d56f92895539..e7f12a9c065a8d239488d90937dac4739c17bdeb 100644
--- a/kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h
+++ b/kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h
@@ -13,21 +13,48 @@
#define have_fp (ELF_HWCAP & HWCAP_FP)
-static inline int fp_linux_begin(void)
+static inline int cobalt_arch_fp_detect(void)
{
- kernel_neon_begin();
-
- return 0;
+ return have_fp ? __COBALT_HAVE_FPU : 0;
}
-static inline void fp_linux_end(void)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(6,19,0)
+static inline unsigned int
+cobalt_arch_in_kernel_fpu_usage(unsigned int expected, rtdm_event_t *rt_synch,
+ int (*report)(const char *fmt, ...))
{
+ int features = cobalt_arch_fp_detect();
+ unsigned int fp_val;
+
+ kernel_neon_begin();
+
+ fp_regs_set(features, expected);
+ rtdm_event_signal(rt_synch);
+ fp_val = fp_regs_check(features, expected, report);
+
kernel_neon_end();
-}
-static inline int fp_detect(void)
+ return fp_val;
+}
+# else
+static inline unsigned int
+cobalt_arch_in_kernel_fpu_usage(unsigned int expected, rtdm_event_t *rt_synch,
+ int (*report)(const char *fmt, ...))
{
- return have_fp ? __COBALT_HAVE_FPU : 0;
+ int features = cobalt_arch_fp_detect();
+ struct user_fpsimd_state fpu_state;
+ unsigned int fp_val;
+
+ kernel_neon_begin(&fpu_state);
+
+ fp_regs_set(features, expected);
+ rtdm_event_signal(rt_synch);
+ fp_val = fp_regs_check(features, expected, report);
+
+ kernel_neon_end(&fpu_state);
+
+ return fp_val;
}
+#endif
#endif /* !_COBALT_ARM64_FPTEST_H */
diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h b/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
index 55818f853c2407eef40f3d1d9a1336bfa7605512..bbb7f3e5f3f9d09ebaf78499a07cc4e48c6dea0f 100644
--- a/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
+++ b/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
@@ -19,13 +19,30 @@
#ifndef _COBALT_X86_ASM_FPTEST_H
#define _COBALT_X86_ASM_FPTEST_H
-#include <linux/errno.h>
#include <asm/processor.h>
#include <asm/xenomai/wrappers.h>
#include <asm/xenomai/uapi/fptest.h>
-static inline int fp_linux_begin(void)
+static inline int cobalt_arch_fp_detect(void)
{
+ int features = 0;
+
+ if (boot_cpu_has(X86_FEATURE_XMM2))
+ features |= __COBALT_HAVE_SSE2;
+
+ if (boot_cpu_has(X86_FEATURE_AVX))
+ features |= __COBALT_HAVE_AVX;
+
+ return features;
+}
+
+static inline unsigned int
+cobalt_arch_in_kernel_fpu_usage(unsigned int expected, rtdm_event_t *rt_synch,
+ int (*report)(const char *fmt, ...))
+{
+ int features = cobalt_arch_fp_detect();
+ unsigned int fp_val;
+
kernel_fpu_begin();
/*
* We need a clean context for testing the sanity of the FPU
@@ -35,25 +52,13 @@ static inline int fp_linux_begin(void)
*/
asm volatile("fninit");
- return true;
-}
+ fp_regs_set(features, expected);
+ rtdm_event_signal(rt_synch);
+ fp_val = fp_regs_check(features, expected, report);
-static inline void fp_linux_end(void)
-{
kernel_fpu_end();
-}
-static inline int fp_detect(void)
-{
- int features = 0;
-
- if (boot_cpu_has(X86_FEATURE_XMM2))
- features |= __COBALT_HAVE_SSE2;
-
- if (boot_cpu_has(X86_FEATURE_AVX))
- features |= __COBALT_HAVE_AVX;
-
- return features;
+ return fp_val;
}
#endif /* _COBALT_X86_ASM_FPTEST_H */
diff --git a/kernel/drivers/testing/switchtest.c b/kernel/drivers/testing/switchtest.c
index f8f6c892076bba729d5d4b536288574df431e344..4a5d2bee7fe4f7ef265e2932e202ef4d8949496a 100644
--- a/kernel/drivers/testing/switchtest.c
+++ b/kernel/drivers/testing/switchtest.c
@@ -62,8 +62,6 @@ struct rtswitch_context {
rtdm_nrtsig_t wake_utask;
};
-static int fp_features;
-
static int report(const char *fmt, ...)
{
va_list ap;
@@ -276,7 +274,7 @@ static int rtswitch_to_nrt(struct rtswitch_context *ctx,
case RTSWITCH_RT:
- if (!fp_check || fp_linux_begin() < 0) {
+ if (!fp_check || !cobalt_arch_fp_detect()) {
fp_check = 0;
goto signal_nofp;
}
@@ -284,10 +282,8 @@ static int rtswitch_to_nrt(struct rtswitch_context *ctx,
expected = from_idx + 500 +
(ctx->switches_count % 4000000) * 1000;
- fp_regs_set(fp_features, expected);
- rtdm_event_signal(&to->rt_synch);
- fp_val = fp_regs_check(fp_features, expected, report);
- fp_linux_end();
+ fp_val = cobalt_arch_in_kernel_fpu_usage(
+ expected, &to->rt_synch, report);
if(down_interruptible(&from->nrt_synch))
return -EINTR;
@@ -308,11 +304,8 @@ static int rtswitch_to_nrt(struct rtswitch_context *ctx,
(ctx->switches_count % 4000000) * 1000;
barrier();
- fp_linux_begin();
- fp_regs_set(fp_features, expected);
- rtdm_event_signal(&to->rt_synch);
- fp_val = fp_regs_check(fp_features, expected, report);
- fp_linux_end();
+ fp_val = cobalt_arch_in_kernel_fpu_usage(
+ expected, &to->rt_synch, report);
if (down_interruptible(&from->nrt_synch))
return -EINTR;
@@ -725,8 +718,6 @@ static struct rtdm_device device = {
static int __init __switchtest_init(void)
{
- fp_features = fp_detect();
-
return rtdm_dev_register(&device);
}
--
2.53.0