diff mbox series

[v1,08/38] arm64/sve: Track vector lengths for tasks in an array

Message ID 20210930181144.10029-9-broonie@kernel.org
State Accepted
Commit 5838a155798479e3fe7e1482a31f0db657d5bbdd
Headers show
Series arm64/sme: Initial support for the Scalable Matrix Extension | expand

Commit Message

Mark Brown Sept. 30, 2021, 6:11 p.m. UTC
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: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/processor.h   | 44 +++++++++++--
 arch/arm64/include/asm/thread_info.h |  2 +-
 arch/arm64/kernel/fpsimd.c           | 97 ++++++++++++++++------------
 3 files changed, 95 insertions(+), 48 deletions(-)

-- 
2.20.1

Comments

Jonathan Cameron Oct. 11, 2021, 10:20 a.m. UTC | #1
On Thu, 30 Sep 2021 19:11:14 +0100
Mark Brown <broonie@kernel.org> wrote:

> 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: Mark Brown <broonie@kernel.org>


I'm clearly having a trivial comment day.  Given reduction in indenting
it would be nice perhaps to reformat comments to take that into account.

I'm also unconvinced the trivial wrappers are worthwhile.  (maybe you drop
those later?)

Jonathan

> ---

>  arch/arm64/include/asm/processor.h   | 44 +++++++++++--

>  arch/arm64/include/asm/thread_info.h |  2 +-

>  arch/arm64/kernel/fpsimd.c           | 97 ++++++++++++++++------------

>  3 files changed, 95 insertions(+), 48 deletions(-)

> 

> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h

> index fb0608fe9ded..9b854e8196df 100644

> --- a/arch/arm64/include/asm/processor.h

> +++ b/arch/arm64/include/asm/processor.h

> @@ -152,8 +152,8 @@ struct thread_struct {

>  

>  	unsigned int		fpsimd_cpu;

>  	void			*sve_state;	/* SVE registers, if any */

> -	unsigned int		sve_vl;		/* SVE vector length */

> -	unsigned int		sve_vl_onexec;	/* SVE vl after next exec */

> +	unsigned int		vl[ARM64_VEC_MAX];	/* vector length */

> +	unsigned int		vl_onexec[ARM64_VEC_MAX]; /* vl after next exec */

>  	unsigned long		fault_address;	/* fault info */

>  	unsigned long		fault_code;	/* ESR_EL1 value */

>  	struct debug_info	debug;		/* debugging */

> @@ -169,15 +169,45 @@ struct thread_struct {

>  	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)

>  {

> -	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);

> -void task_set_sve_vl(struct task_struct *task, unsigned long vl);

> -unsigned int task_get_sve_vl_onexec(const struct task_struct *task);

> -void task_set_sve_vl_onexec(struct task_struct *task, unsigned long vl);

> +static inline void task_set_sve_vl(struct task_struct *task, unsigned long vl)

> +{

> +	task_set_vl(task, ARM64_VEC_SVE, vl);


Are these really worth having?  They make the refactor simpler perhaps, but
don't add any meaning in of themselves over just having the calls inline.

> +}

> +

> +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                                                        \

>  	(SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA | SCTLR_ELx_ENDB |   \

> diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h

> index 6623c99f0984..d5c8ac81ce11 100644

> --- a/arch/arm64/include/asm/thread_info.h

> +++ b/arch/arm64/include/asm/thread_info.h

> @@ -78,7 +78,7 @@ int arch_dup_task_struct(struct task_struct *dst,

>  #define TIF_SINGLESTEP		21

>  #define TIF_32BIT		22	/* 32bit process */

>  #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_TAGGED_ADDR		26	/* Allow tagged user addresses */

>  

> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c

> index 44bb3203c9d1..814080209093 100644

> --- a/arch/arm64/kernel/fpsimd.c

> +++ b/arch/arm64/kernel/fpsimd.c

> @@ -133,6 +133,17 @@ __ro_after_init struct vl_info vl_info[ARM64_VEC_MAX] = {

>  #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 {

>  	int __default_vl;		/* Default VL for tasks */

>  };

> @@ -239,24 +250,27 @@ static void sve_free(struct task_struct *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)

>  	__put_cpu_fpsimd_context();

>  }

>  

> -void fpsimd_flush_thread(void)

> +static void fpsimd_flush_thread_vl(enum vec_type type)

>  {

>  	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


Nice to rewrap this to 80 chars whilst you are here?

> +	 * 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())

>  		return;

>  

> @@ -1090,37 +1137,7 @@ void fpsimd_flush_thread(void)

>  	if (system_supports_sve()) {

>  		clear_thread_flag(TIF_SVE);

>  		sve_free(current);

> -

> -		/*

> -		 * 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);

> +		fpsimd_flush_thread_vl(ARM64_VEC_SVE);

>  	}

>  

>  	put_cpu_fpsimd_context();
Mark Brown Oct. 11, 2021, 1:14 p.m. UTC | #2
On Mon, Oct 11, 2021 at 11:20:57AM +0100, Jonathan Cameron wrote:
> Mark Brown <broonie@kernel.org> wrote:


> > 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.


> I'm clearly having a trivial comment day.  Given reduction in indenting

> it would be nice perhaps to reformat comments to take that into account.


Again I'll have done this to make it clearer that things are just being
moved about - as a reviewer I do find things like that very helpful.

> I'm also unconvinced the trivial wrappers are worthwhile.  (maybe you drop

> those later?)


They do hide what we're doing from the rest of the series which makes
the whole thing a lot easier to work with, especially if we change what
data structures we use or there's some debate as to the names of the
constants.  A bunch of them directly map onto existing trivial wrappers
too, there's been some stylistic preference for that.

If people want to remove the wrappers I'd propose leaving them for now
then adding a patch afterwards which removes them, or at least waiting
until we've got very firm agreement from Catalin and Will on the data
structures and constants.
Jonathan Cameron Oct. 11, 2021, 1:18 p.m. UTC | #3
On Mon, 11 Oct 2021 14:14:16 +0100
Mark Brown <broonie@kernel.org> wrote:

> On Mon, Oct 11, 2021 at 11:20:57AM +0100, Jonathan Cameron wrote:

> > Mark Brown <broonie@kernel.org> wrote:  

> 

> > > 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.  

> 

> > I'm clearly having a trivial comment day.  Given reduction in indenting

> > it would be nice perhaps to reformat comments to take that into account.  

> 

> Again I'll have done this to make it clearer that things are just being

> moved about - as a reviewer I do find things like that very helpful.

> 

> > I'm also unconvinced the trivial wrappers are worthwhile.  (maybe you drop

> > those later?)  

> 

> They do hide what we're doing from the rest of the series which makes

> the whole thing a lot easier to work with, especially if we change what

> data structures we use or there's some debate as to the names of the

> constants.  A bunch of them directly map onto existing trivial wrappers

> too, there's been some stylistic preference for that.

> 

> If people want to remove the wrappers I'd propose leaving them for now

> then adding a patch afterwards which removes them, or at least waiting

> until we've got very firm agreement from Catalin and Will on the data

> structures and constants.

> 


Makes sense.

J
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index fb0608fe9ded..9b854e8196df 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -152,8 +152,8 @@  struct thread_struct {
 
 	unsigned int		fpsimd_cpu;
 	void			*sve_state;	/* SVE registers, if any */
-	unsigned int		sve_vl;		/* SVE vector length */
-	unsigned int		sve_vl_onexec;	/* SVE vl after next exec */
+	unsigned int		vl[ARM64_VEC_MAX];	/* vector length */
+	unsigned int		vl_onexec[ARM64_VEC_MAX]; /* vl after next exec */
 	unsigned long		fault_address;	/* fault info */
 	unsigned long		fault_code;	/* ESR_EL1 value */
 	struct debug_info	debug;		/* debugging */
@@ -169,15 +169,45 @@  struct thread_struct {
 	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)
 {
-	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);
-void task_set_sve_vl(struct task_struct *task, unsigned long vl);
-unsigned int task_get_sve_vl_onexec(const struct task_struct *task);
-void task_set_sve_vl_onexec(struct task_struct *task, unsigned long vl);
+static inline void task_set_sve_vl(struct task_struct *task, unsigned long vl)
+{
+	task_set_vl(task, ARM64_VEC_SVE, 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                                                        \
 	(SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA | SCTLR_ELx_ENDB |   \
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 6623c99f0984..d5c8ac81ce11 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -78,7 +78,7 @@  int arch_dup_task_struct(struct task_struct *dst,
 #define TIF_SINGLESTEP		21
 #define TIF_32BIT		22	/* 32bit process */
 #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_TAGGED_ADDR		26	/* Allow tagged user addresses */
 
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 44bb3203c9d1..814080209093 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -133,6 +133,17 @@  __ro_after_init struct vl_info vl_info[ARM64_VEC_MAX] = {
 #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 {
 	int __default_vl;		/* Default VL for tasks */
 };
@@ -239,24 +250,27 @@  static void sve_free(struct task_struct *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)
 	__put_cpu_fpsimd_context();
 }
 
-void fpsimd_flush_thread(void)
+static void fpsimd_flush_thread_vl(enum vec_type type)
 {
 	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())
 		return;
 
@@ -1090,37 +1137,7 @@  void fpsimd_flush_thread(void)
 	if (system_supports_sve()) {
 		clear_thread_flag(TIF_SVE);
 		sve_free(current);
-
-		/*
-		 * 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);
+		fpsimd_flush_thread_vl(ARM64_VEC_SVE);
 	}
 
 	put_cpu_fpsimd_context();