提交 30c43e73 编写于 作者: M Mark Brown 提交者: Catalin Marinas

arm64/sve: Generalise vector length configuration prctl() for SME

In preparation for adding SME support update the bulk of the implementation
for the vector length configuration prctl() calls to be independent of
vector type.
Signed-off-by: NMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20211210184133.320748-3-broonie@kernel.orgSigned-off-by: NCatalin Marinas <catalin.marinas@arm.com>
上级 97bcbee4
...@@ -51,8 +51,8 @@ extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state, ...@@ -51,8 +51,8 @@ extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state,
extern void fpsimd_flush_task_state(struct task_struct *target); extern void fpsimd_flush_task_state(struct task_struct *target);
extern void fpsimd_save_and_flush_cpu_state(void); extern void fpsimd_save_and_flush_cpu_state(void);
/* Maximum VL that SVE VL-agnostic software can transparently support */ /* Maximum VL that SVE/SME VL-agnostic software can transparently support */
#define SVE_VL_ARCH_MAX 0x100 #define VL_ARCH_MAX 0x100
/* Offset of FFR in the SVE register dump */ /* Offset of FFR in the SVE register dump */
static inline size_t sve_ffr_offset(int vl) static inline size_t sve_ffr_offset(int vl)
...@@ -122,7 +122,7 @@ extern void fpsimd_sync_to_sve(struct task_struct *task); ...@@ -122,7 +122,7 @@ extern void fpsimd_sync_to_sve(struct task_struct *task);
extern void sve_sync_to_fpsimd(struct task_struct *task); extern void sve_sync_to_fpsimd(struct task_struct *task);
extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task); extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
extern int sve_set_vector_length(struct task_struct *task, extern int vec_set_vector_length(struct task_struct *task, enum vec_type type,
unsigned long vl, unsigned long flags); unsigned long vl, unsigned long flags);
extern int sve_set_current_vl(unsigned long arg); extern int sve_set_current_vl(unsigned long arg);
......
...@@ -632,7 +632,7 @@ void sve_sync_from_fpsimd_zeropad(struct task_struct *task) ...@@ -632,7 +632,7 @@ void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
__fpsimd_to_sve(sst, fst, vq); __fpsimd_to_sve(sst, fst, vq);
} }
int sve_set_vector_length(struct task_struct *task, int vec_set_vector_length(struct task_struct *task, enum vec_type type,
unsigned long vl, unsigned long flags) unsigned long vl, unsigned long flags)
{ {
if (flags & ~(unsigned long)(PR_SVE_VL_INHERIT | if (flags & ~(unsigned long)(PR_SVE_VL_INHERIT |
...@@ -643,33 +643,35 @@ int sve_set_vector_length(struct task_struct *task, ...@@ -643,33 +643,35 @@ int sve_set_vector_length(struct task_struct *task,
return -EINVAL; return -EINVAL;
/* /*
* Clamp to the maximum vector length that VL-agnostic SVE code can * Clamp to the maximum vector length that VL-agnostic code
* work with. A flag may be assigned in the future to allow setting * can work with. A flag may be assigned in the future to
* of larger vector lengths without confusing older software. * allow setting of larger vector lengths without confusing
* older software.
*/ */
if (vl > SVE_VL_ARCH_MAX) if (vl > VL_ARCH_MAX)
vl = SVE_VL_ARCH_MAX; vl = VL_ARCH_MAX;
vl = find_supported_vector_length(ARM64_VEC_SVE, vl); vl = find_supported_vector_length(type, vl);
if (flags & (PR_SVE_VL_INHERIT | if (flags & (PR_SVE_VL_INHERIT |
PR_SVE_SET_VL_ONEXEC)) PR_SVE_SET_VL_ONEXEC))
task_set_sve_vl_onexec(task, vl); task_set_vl_onexec(task, type, vl);
else else
/* Reset VL to system default on next exec: */ /* Reset VL to system default on next exec: */
task_set_sve_vl_onexec(task, 0); task_set_vl_onexec(task, type, 0);
/* Only actually set the VL if not deferred: */ /* Only actually set the VL if not deferred: */
if (flags & PR_SVE_SET_VL_ONEXEC) if (flags & PR_SVE_SET_VL_ONEXEC)
goto out; goto out;
if (vl == task_get_sve_vl(task)) if (vl == task_get_vl(task, type))
goto out; goto out;
/* /*
* To ensure the FPSIMD bits of the SVE vector registers are preserved, * To ensure the FPSIMD bits of the SVE vector registers are preserved,
* write any live register state back to task_struct, and convert to a * write any live register state back to task_struct, and convert to a
* non-SVE thread. * regular FPSIMD thread. Since the vector length can only be changed
* with a syscall we can't be in streaming mode while reconfiguring.
*/ */
if (task == current) { if (task == current) {
get_cpu_fpsimd_context(); get_cpu_fpsimd_context();
...@@ -690,10 +692,10 @@ int sve_set_vector_length(struct task_struct *task, ...@@ -690,10 +692,10 @@ int sve_set_vector_length(struct task_struct *task,
*/ */
sve_free(task); sve_free(task);
task_set_sve_vl(task, vl); task_set_vl(task, type, vl);
out: out:
update_tsk_thread_flag(task, TIF_SVE_VL_INHERIT, update_tsk_thread_flag(task, vec_vl_inherit_flag(type),
flags & PR_SVE_VL_INHERIT); flags & PR_SVE_VL_INHERIT);
return 0; return 0;
...@@ -701,20 +703,21 @@ int sve_set_vector_length(struct task_struct *task, ...@@ -701,20 +703,21 @@ int sve_set_vector_length(struct task_struct *task,
/* /*
* Encode the current vector length and flags for return. * Encode the current vector length and flags for return.
* This is only required for prctl(): ptrace has separate fields * This is only required for prctl(): ptrace has separate fields.
* SVE and SME use the same bits for _ONEXEC and _INHERIT.
* *
* flags are as for sve_set_vector_length(). * flags are as for vec_set_vector_length().
*/ */
static int sve_prctl_status(unsigned long flags) static int vec_prctl_status(enum vec_type type, unsigned long flags)
{ {
int ret; int ret;
if (flags & PR_SVE_SET_VL_ONEXEC) if (flags & PR_SVE_SET_VL_ONEXEC)
ret = task_get_sve_vl_onexec(current); ret = task_get_vl_onexec(current, type);
else else
ret = task_get_sve_vl(current); ret = task_get_vl(current, type);
if (test_thread_flag(TIF_SVE_VL_INHERIT)) if (test_thread_flag(vec_vl_inherit_flag(type)))
ret |= PR_SVE_VL_INHERIT; ret |= PR_SVE_VL_INHERIT;
return ret; return ret;
...@@ -732,11 +735,11 @@ int sve_set_current_vl(unsigned long arg) ...@@ -732,11 +735,11 @@ int sve_set_current_vl(unsigned long arg)
if (!system_supports_sve() || is_compat_task()) if (!system_supports_sve() || is_compat_task())
return -EINVAL; return -EINVAL;
ret = sve_set_vector_length(current, vl, flags); ret = vec_set_vector_length(current, ARM64_VEC_SVE, vl, flags);
if (ret) if (ret)
return ret; return ret;
return sve_prctl_status(flags); return vec_prctl_status(ARM64_VEC_SVE, flags);
} }
/* PR_SVE_GET_VL */ /* PR_SVE_GET_VL */
...@@ -745,7 +748,7 @@ int sve_get_current_vl(void) ...@@ -745,7 +748,7 @@ int sve_get_current_vl(void)
if (!system_supports_sve() || is_compat_task()) if (!system_supports_sve() || is_compat_task())
return -EINVAL; return -EINVAL;
return sve_prctl_status(0); return vec_prctl_status(ARM64_VEC_SVE, 0);
} }
static void vec_probe_vqs(struct vl_info *info, static void vec_probe_vqs(struct vl_info *info,
......
...@@ -812,9 +812,9 @@ static int sve_set(struct task_struct *target, ...@@ -812,9 +812,9 @@ static int sve_set(struct task_struct *target,
/* /*
* Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by
* sve_set_vector_length(), which will also validate them for us: * vec_set_vector_length(), which will also validate them for us:
*/ */
ret = sve_set_vector_length(target, header.vl, ret = vec_set_vector_length(target, ARM64_VEC_SVE, header.vl,
((unsigned long)header.flags & ~SVE_PT_REGS_MASK) << 16); ((unsigned long)header.flags & ~SVE_PT_REGS_MASK) << 16);
if (ret) if (ret)
goto out; goto out;
......
...@@ -52,10 +52,10 @@ int kvm_arm_init_sve(void) ...@@ -52,10 +52,10 @@ int kvm_arm_init_sve(void)
* The get_sve_reg()/set_sve_reg() ioctl interface will need * The get_sve_reg()/set_sve_reg() ioctl interface will need
* to be extended with multiple register slice support in * to be extended with multiple register slice support in
* order to support vector lengths greater than * order to support vector lengths greater than
* SVE_VL_ARCH_MAX: * VL_ARCH_MAX:
*/ */
if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX)) if (WARN_ON(kvm_sve_max_vl > VL_ARCH_MAX))
kvm_sve_max_vl = SVE_VL_ARCH_MAX; kvm_sve_max_vl = VL_ARCH_MAX;
/* /*
* Don't even try to make use of vector lengths that * Don't even try to make use of vector lengths that
...@@ -103,7 +103,7 @@ static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu) ...@@ -103,7 +103,7 @@ static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
* set_sve_vls(). Double-check here just to be sure: * set_sve_vls(). Double-check here just to be sure:
*/ */
if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl() || if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl() ||
vl > SVE_VL_ARCH_MAX)) vl > VL_ARCH_MAX))
return -EIO; return -EIO;
buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL_ACCOUNT); buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL_ACCOUNT);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册