[PATCH v3 5/5] 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 signature of fp_linux_begin() on all architectures has
been updated.
There is a new arch dependent struct now: cobalt_arch_fp_state.
Arm64 will wrap the FPU state (struct user_fpsimd_state) there,
all remaining archs will implement an empty (and unused) type.
Signed-off-by: Florian Bezdeka <[email protected]>
---
kernel/cobalt/arch/arm/include/asm/xenomai/fptest.h | 6 ++++--
kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h | 16 +++++++++++-----
kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h | 9 ++++++---
kernel/cobalt/include/asm-generic/xenomai/wrappers.h | 7 +++++++
kernel/drivers/testing/switchtest.c | 18 +++++++++++++-----
5 files changed, 41 insertions(+), 15 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..3b80fa8461d44e3cf224dcba3d0bd7255d302732 100644
--- a/kernel/cobalt/arch/arm/include/asm/xenomai/fptest.h
+++ b/kernel/cobalt/arch/arm/include/asm/xenomai/fptest.h
@@ -30,12 +30,14 @@
#include <asm/xenomai/uapi/fptest.h>
-static inline int fp_linux_begin(void)
+struct cobalt_arch_fp_state {};
+
+static inline int fp_linux_begin(struct cobalt_arch_fp_state *state)
{
return -ENOSYS;
}
-static inline void fp_linux_end(void)
+static inline void fp_linux_end(struct cobalt_arch_fp_state *state)
{
}
diff --git a/kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h b/kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h
index 520cd38519db66ad25baecedd183d56f92895539..e1ff046e1c9a99990cc93bcb7f3aa600186bfb36 100644
--- a/kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h
+++ b/kernel/cobalt/arch/arm64/include/asm/xenomai/fptest.h
@@ -7,22 +7,28 @@
#ifndef _COBALT_ARM64_FPTEST_H
#define _COBALT_ARM64_FPTEST_H
-#include <asm/xenomai/uapi/fptest.h>
#include <asm/hwcap.h>
#include <asm/neon.h>
+#include <asm/xenomai/uapi/fptest.h>
+#include <asm-generic/xenomai/wrappers.h>
+
#define have_fp (ELF_HWCAP & HWCAP_FP)
-static inline int fp_linux_begin(void)
+struct cobalt_arch_fp_state {
+ struct user_fpsimd_state state;
+};
+
+static inline int fp_linux_begin(struct cobalt_arch_fp_state *state)
{
- kernel_neon_begin();
+ kernel_neon_begin(&state->state);
return 0;
}
-static inline void fp_linux_end(void)
+static inline void fp_linux_end(struct cobalt_arch_fp_state *state)
{
- kernel_neon_end();
+ kernel_neon_end(&state->state);
}
static inline int fp_detect(void)
diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h b/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
index 55818f853c2407eef40f3d1d9a1336bfa7605512..de6a931077fc7ff6aca6f8a27423e31d64bace0d 100644
--- a/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
+++ b/kernel/cobalt/arch/x86/include/asm/xenomai/fptest.h
@@ -19,12 +19,15 @@
#ifndef _COBALT_X86_ASM_FPTEST_H
#define _COBALT_X86_ASM_FPTEST_H
-#include <linux/errno.h>
+#include <asm/fpu/api.h>
+
#include <asm/processor.h>
#include <asm/xenomai/wrappers.h>
#include <asm/xenomai/uapi/fptest.h>
-static inline int fp_linux_begin(void)
+struct cobalt_arch_fp_state {};
+
+static inline int fp_linux_begin(struct cobalt_arch_fp_state *state)
{
kernel_fpu_begin();
/*
@@ -38,7 +41,7 @@ static inline int fp_linux_begin(void)
return true;
}
-static inline void fp_linux_end(void)
+static inline void fp_linux_end(struct cobalt_arch_fp_state *state)
{
kernel_fpu_end();
}
diff --git a/kernel/cobalt/include/asm-generic/xenomai/wrappers.h b/kernel/cobalt/include/asm-generic/xenomai/wrappers.h
index baf54dcfe7bb5071a1abea48bd87f471eb938297..27e641fa7f9178229e0616e4de64b0e267910915 100644
--- a/kernel/cobalt/include/asm-generic/xenomai/wrappers.h
+++ b/kernel/cobalt/include/asm-generic/xenomai/wrappers.h
@@ -84,4 +84,11 @@
})
#endif
+#ifdef CONFIG_ARM64
+#if LINUX_VERSION_CODE < KERNEL_VERSION(6,19,0)
+#define kernel_neon_begin(fpu_preempt_buffer) kernel_neon_begin()
+#define kernel_neon_end(fpu_preempt_buffer) kernel_neon_end()
+#endif
+#endif
+
#endif /* _COBALT_ASM_GENERIC_WRAPPERS_H */
diff --git a/kernel/drivers/testing/switchtest.c b/kernel/drivers/testing/switchtest.c
index f8f6c892076bba729d5d4b536288574df431e344..bb9c3dcae36f412562b78713bb10260d764dfd40 100644
--- a/kernel/drivers/testing/switchtest.c
+++ b/kernel/drivers/testing/switchtest.c
@@ -15,16 +15,23 @@
* along with Xenomai; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/semaphore.h>
+
+/*
+ * Needs to be the first non-Linux include, wrappers.h for older kernels
+ * involved on arm64 and further Linux headers included at the top of fptest.h
+ */
+#include <asm/xenomai/fptest.h>
+
#include <cobalt/kernel/sched.h>
#include <cobalt/kernel/synch.h>
#include <cobalt/kernel/thread.h>
#include <cobalt/kernel/trace.h>
#include <rtdm/testing.h>
#include <rtdm/driver.h>
-#include <asm/xenomai/fptest.h>
MODULE_DESCRIPTION("Cobalt context switch test helper");
MODULE_AUTHOR("Gilles Chanteperdrix <[email protected]>");
@@ -236,6 +243,7 @@ static int rtswitch_to_nrt(struct rtswitch_context *ctx,
unsigned int from_idx,
unsigned int to_idx)
{
+ struct cobalt_arch_fp_state state;
struct rtswitch_task *from, *to;
unsigned int expected, fp_val;
int fp_check;
@@ -276,7 +284,7 @@ static int rtswitch_to_nrt(struct rtswitch_context *ctx,
case RTSWITCH_RT:
- if (!fp_check || fp_linux_begin() < 0) {
+ if (!fp_check || fp_linux_begin(&state) < 0) {
fp_check = 0;
goto signal_nofp;
}
@@ -287,7 +295,7 @@ static int rtswitch_to_nrt(struct rtswitch_context *ctx,
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_linux_end(&state);
if(down_interruptible(&from->nrt_synch))
return -EINTR;
@@ -308,11 +316,11 @@ static int rtswitch_to_nrt(struct rtswitch_context *ctx,
(ctx->switches_count % 4000000) * 1000;
barrier();
- fp_linux_begin();
+ fp_linux_begin(&state);
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_linux_end(&state);
if (down_interruptible(&from->nrt_synch))
return -EINTR;
--
2.53.0