[RFC PATCH v2 23/41] arm64/sve: Move ZEN handling to the common task_fpsimd_load() path
Dave Martin
Dave.Martin at arm.com
Wed Mar 22 07:50:53 PDT 2017
Currently, ZEN is handled only in fpsimd_restore_current_state(),
which is not sufficient since it applies only in certain
situations.
Since all the relevant paths call task_fpsimd_load(), this patch
moves the ZEN handling there.
Signed-off-by: Dave Martin <Dave.Martin at arm.com>
---
arch/arm64/include/asm/thread_info.h | 1 +
arch/arm64/kernel/fpsimd.c | 50 ++++++++++++++++++++----------------
2 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 272c32d..a0f5498 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -107,6 +107,7 @@ struct thread_info {
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
+#define _TIF_SVE (1 << TIF_SVE)
#define _TIF_UPROBE (1 << TIF_UPROBE)
#define _TIF_32BIT (1 << TIF_32BIT)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 260438d..5fb5585 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -37,6 +37,9 @@
#define FPEXC_IXF (1 << 4)
#define FPEXC_IDF (1 << 7)
+/* Forward declarations for local functions used by both SVE and FPSIMD */
+static void task_fpsimd_load(struct task_struct *task);
+
/*
* In order to reduce the number of times the FPSIMD state is needlessly saved
* and restored, we need to keep track of two things:
@@ -151,18 +154,20 @@ static void sve_to_fpsimd(struct task_struct *task)
void do_sve_acc(unsigned int esr, struct pt_regs *regs)
{
- unsigned long tmp;
+ if (test_and_set_thread_flag(TIF_SVE)) {
+ unsigned long tmp;
- if (test_and_set_thread_flag(TIF_SVE))
+ asm ("mrs %0, cpacr_el1" : "=r" (tmp));
+
+ printk(KERN_INFO "%s: Strange, ZEN=%u\n",
+ __func__, (unsigned int)((tmp >> 16) & 3));
BUG();
+ }
BUG_ON(is_compat_task());
fpsimd_to_sve(current);
-
- asm ("mrs %0, cpacr_el1" : "=r" (tmp));
- asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));
- /* Serialised by exception return to user */
+ task_fpsimd_load(current);
}
#else /* ! CONFIG_ARM64_SVE */
@@ -220,6 +225,23 @@ static void task_fpsimd_load(struct task_struct *task)
&task->thread.fpsimd_state.fpsr);
else
fpsimd_load_state(&task->thread.fpsimd_state);
+
+ /*
+ * Flip SVE enable for userspace if it doesn't match the
+ * current_task.
+ */
+ if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
+ unsigned int tmp, flags;
+
+ asm ("mrs %0, cpacr_el1" : "=r" (tmp));
+ flags = task_thread_info(task)->flags;
+ BUILD_BUG_ON(_TIF_SVE != CPACR_EL1_ZEN_EL0EN);
+ if ((tmp ^ (unsigned long)flags) & _TIF_SVE) {
+ tmp ^= _TIF_SVE;
+ asm volatile ("msr cpacr_el1, %0" :: "r" (tmp));
+ /* Serialised by exception return to user */
+ }
+ }
}
static void task_fpsimd_save(struct task_struct *task)
@@ -323,27 +345,11 @@ void fpsimd_restore_current_state(void)
return;
preempt_disable();
if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
- unsigned long tmp;
- unsigned long flags;
-
struct fpsimd_state *st = ¤t->thread.fpsimd_state;
task_fpsimd_load(current);
this_cpu_write(fpsimd_last_state, st);
st->cpu = smp_processor_id();
-
- if (IS_ENABLED(CONFIG_ARM64_SVE)) {
- /*
- * Flip SVE enable for userspace if it doesn't
- * match the current_task.
- */
- asm ("mrs %0, cpacr_el1" : "=r" (tmp));
- flags = current_thread_info()->flags;
- if ((tmp ^ (unsigned long)flags) & (1 << 17)) {
- tmp ^= 1 << 17;
- asm volatile ("msr cpacr_el1, %0" :: "r" (tmp));
- }
- }
}
preempt_enable();
}
--
2.1.4
More information about the linux-arm-kernel
mailing list