[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.