Commit 5838a155 authored by Mark Brown's avatar Mark Brown Committed by Will Deacon

arm64/sve: Track vector lengths for tasks in an array

As for SVE we will track a per task SME vector length for tasks. Convert
the existing storage for the vector length into an array and update
fpsimd_flush_task() to initialise this in a function.
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20211019172247.3045838-10-broonie@kernel.orgSigned-off-by: default avatarWill Deacon <will@kernel.org>
parent ddc806b5
...@@ -152,8 +152,8 @@ struct thread_struct { ...@@ -152,8 +152,8 @@ struct thread_struct {
unsigned int fpsimd_cpu; unsigned int fpsimd_cpu;
void *sve_state; /* SVE registers, if any */ void *sve_state; /* SVE registers, if any */
unsigned int sve_vl; /* SVE vector length */ unsigned int vl[ARM64_VEC_MAX]; /* vector length */
unsigned int sve_vl_onexec; /* SVE vl after next exec */ unsigned int vl_onexec[ARM64_VEC_MAX]; /* vl after next exec */
unsigned long fault_address; /* fault info */ unsigned long fault_address; /* fault info */
unsigned long fault_code; /* ESR_EL1 value */ unsigned long fault_code; /* ESR_EL1 value */
struct debug_info debug; /* debugging */ struct debug_info debug; /* debugging */
...@@ -169,15 +169,45 @@ struct thread_struct { ...@@ -169,15 +169,45 @@ struct thread_struct {
u64 sctlr_user; u64 sctlr_user;
}; };
static inline unsigned int thread_get_vl(struct thread_struct *thread,
enum vec_type type)
{
return thread->vl[type];
}
static inline unsigned int thread_get_sve_vl(struct thread_struct *thread) static inline unsigned int thread_get_sve_vl(struct thread_struct *thread)
{ {
return thread->sve_vl; return thread_get_vl(thread, ARM64_VEC_SVE);
}
unsigned int task_get_vl(const struct task_struct *task, enum vec_type type);
void task_set_vl(struct task_struct *task, enum vec_type type,
unsigned long vl);
void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
unsigned long vl);
unsigned int task_get_vl_onexec(const struct task_struct *task,
enum vec_type type);
static inline unsigned int task_get_sve_vl(const struct task_struct *task)
{
return task_get_vl(task, ARM64_VEC_SVE);
} }
unsigned int task_get_sve_vl(const struct task_struct *task); static inline void task_set_sve_vl(struct task_struct *task, unsigned long vl)
void task_set_sve_vl(struct task_struct *task, unsigned long vl); {
unsigned int task_get_sve_vl_onexec(const struct task_struct *task); task_set_vl(task, ARM64_VEC_SVE, vl);
void task_set_sve_vl_onexec(struct task_struct *task, unsigned long vl); }
static inline unsigned int task_get_sve_vl_onexec(const struct task_struct *task)
{
return task_get_vl_onexec(task, ARM64_VEC_SVE);
}
static inline void task_set_sve_vl_onexec(struct task_struct *task,
unsigned long vl)
{
task_set_vl_onexec(task, ARM64_VEC_SVE, vl);
}
#define SCTLR_USER_MASK \ #define SCTLR_USER_MASK \
(SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA | SCTLR_ELx_ENDB | \ (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA | SCTLR_ELx_ENDB | \
......
...@@ -78,7 +78,7 @@ int arch_dup_task_struct(struct task_struct *dst, ...@@ -78,7 +78,7 @@ int arch_dup_task_struct(struct task_struct *dst,
#define TIF_SINGLESTEP 21 #define TIF_SINGLESTEP 21
#define TIF_32BIT 22 /* 32bit process */ #define TIF_32BIT 22 /* 32bit process */
#define TIF_SVE 23 /* Scalable Vector Extension in use */ #define TIF_SVE 23 /* Scalable Vector Extension in use */
#define TIF_SVE_VL_INHERIT 24 /* Inherit sve_vl_onexec across exec */ #define TIF_SVE_VL_INHERIT 24 /* Inherit SVE vl_onexec across exec */
#define TIF_SSBD 25 /* Wants SSB mitigation */ #define TIF_SSBD 25 /* Wants SSB mitigation */
#define TIF_TAGGED_ADDR 26 /* Allow tagged user addresses */ #define TIF_TAGGED_ADDR 26 /* Allow tagged user addresses */
......
...@@ -133,6 +133,17 @@ __ro_after_init struct vl_info vl_info[ARM64_VEC_MAX] = { ...@@ -133,6 +133,17 @@ __ro_after_init struct vl_info vl_info[ARM64_VEC_MAX] = {
#endif #endif
}; };
static unsigned int vec_vl_inherit_flag(enum vec_type type)
{
switch (type) {
case ARM64_VEC_SVE:
return TIF_SVE_VL_INHERIT;
default:
WARN_ON_ONCE(1);
return 0;
}
}
struct vl_config { struct vl_config {
int __default_vl; /* Default VL for tasks */ int __default_vl; /* Default VL for tasks */
}; };
...@@ -239,24 +250,27 @@ static void sve_free(struct task_struct *task) ...@@ -239,24 +250,27 @@ static void sve_free(struct task_struct *task)
__sve_free(task); __sve_free(task);
} }
unsigned int task_get_sve_vl(const struct task_struct *task) unsigned int task_get_vl(const struct task_struct *task, enum vec_type type)
{ {
return task->thread.sve_vl; return task->thread.vl[type];
} }
void task_set_sve_vl(struct task_struct *task, unsigned long vl) void task_set_vl(struct task_struct *task, enum vec_type type,
unsigned long vl)
{ {
task->thread.sve_vl = vl; task->thread.vl[type] = vl;
} }
unsigned int task_get_sve_vl_onexec(const struct task_struct *task) unsigned int task_get_vl_onexec(const struct task_struct *task,
enum vec_type type)
{ {
return task->thread.sve_vl_onexec; return task->thread.vl_onexec[type];
} }
void task_set_sve_vl_onexec(struct task_struct *task, unsigned long vl) void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
unsigned long vl)
{ {
task->thread.sve_vl_onexec = vl; task->thread.vl_onexec[type] = vl;
} }
/* /*
...@@ -1074,10 +1088,43 @@ void fpsimd_thread_switch(struct task_struct *next) ...@@ -1074,10 +1088,43 @@ void fpsimd_thread_switch(struct task_struct *next)
__put_cpu_fpsimd_context(); __put_cpu_fpsimd_context();
} }
void fpsimd_flush_thread(void) static void fpsimd_flush_thread_vl(enum vec_type type)
{ {
int vl, supported_vl; int vl, supported_vl;
/*
* Reset the task vector length as required. This is where we
* ensure that all user tasks have a valid vector length
* configured: no kernel task can become a user task without
* an exec and hence a call to this function. By the time the
* first call to this function is made, all early hardware
* probing is complete, so __sve_default_vl should be valid.
* If a bug causes this to go wrong, we make some noise and
* try to fudge thread.sve_vl to a safe value here.
*/
vl = task_get_vl_onexec(current, type);
if (!vl)
vl = get_default_vl(type);
if (WARN_ON(!sve_vl_valid(vl)))
vl = SVE_VL_MIN;
supported_vl = find_supported_vector_length(type, vl);
if (WARN_ON(supported_vl != vl))
vl = supported_vl;
task_set_vl(current, type, vl);
/*
* If the task is not set to inherit, ensure that the vector
* length will be reset by a subsequent exec:
*/
if (!test_thread_flag(vec_vl_inherit_flag(type)))
task_set_vl_onexec(current, type, 0);
}
void fpsimd_flush_thread(void)
{
if (!system_supports_fpsimd()) if (!system_supports_fpsimd())
return; return;
...@@ -1090,37 +1137,7 @@ void fpsimd_flush_thread(void) ...@@ -1090,37 +1137,7 @@ void fpsimd_flush_thread(void)
if (system_supports_sve()) { if (system_supports_sve()) {
clear_thread_flag(TIF_SVE); clear_thread_flag(TIF_SVE);
sve_free(current); sve_free(current);
fpsimd_flush_thread_vl(ARM64_VEC_SVE);
/*
* Reset the task vector length as required.
* This is where we ensure that all user tasks have a valid
* vector length configured: no kernel task can become a user
* task without an exec and hence a call to this function.
* By the time the first call to this function is made, all
* early hardware probing is complete, so __sve_default_vl
* should be valid.
* If a bug causes this to go wrong, we make some noise and
* try to fudge thread.sve_vl to a safe value here.
*/
vl = task_get_sve_vl_onexec(current);
if (!vl)
vl = get_sve_default_vl();
if (WARN_ON(!sve_vl_valid(vl)))
vl = SVE_VL_MIN;
supported_vl = find_supported_vector_length(ARM64_VEC_SVE, vl);
if (WARN_ON(supported_vl != vl))
vl = supported_vl;
task_set_sve_vl(current, vl);
/*
* If the task is not set to inherit, ensure that the vector
* length will be reset by a subsequent exec:
*/
if (!test_thread_flag(TIF_SVE_VL_INHERIT))
task_set_sve_vl_onexec(current, 0);
} }
put_cpu_fpsimd_context(); put_cpu_fpsimd_context();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment