All of lore.kernel.org
 help / color / mirror / Atom feed
From: Conor Dooley <conor@kernel.org>
To: Andy Chiu <tchiu@tenstorrent.com>
Cc: Jonathan Corbet <corbet@lwn.net>,
	Shuah Khan <skhan@linuxfoundation.org>,
	Randy Dunlap <rdunlap@infradead.org>,
	Paul Walmsley <pjw@kernel.org>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Alexandre Ghiti <alex@ghiti.fr>,
	linux-doc@vger.kernel.org, linux-riscv@lists.infradead.org,
	andybnac@gmail.com, dfustini@oss.tenstorrent.com,
	greentime.hu@sifive.com,
	"Mike Rapoport (Microsoft)" <rppt@kernel.org>,
	Arnd Bergmann <arnd@arndb.de>,
	Karl Mehltretter <kmehltretter@gmail.com>,
	"Borislav Petkov (AMD)" <bp@alien8.de>,
	Dapeng Mi <dapeng1.mi@linux.intel.com>,
	Marco Elver <elver@google.com>,
	Ethan Nelson-Moore <enelsonmoore@gmail.com>,
	Jeff Layton <jlayton@kernel.org>,
	Jisheng Zhang <jszhang@kernel.org>,
	Conor Dooley <conor.dooley@microchip.com>,
	Yong-Xuan Wang <yongxuan.wang@sifive.com>,
	Anup Patel <anup@brainfault.org>,
	Aurelien Jarno <aurelien@aurel32.net>,
	daichengrong <daichengrong@iscas.ac.cn>,
	Troy Mitchell <troy.mitchell@linux.dev>,
	Guobin Zhang <guobin.zhang@intel.com>,
	Guodong Xu <docular.xu@gmail.com>,
	Andrew Jones <andrew.jones@linux.dev>,
	Charlie Jenkins <thecharlesjenkins@gmail.com>,
	Atish Patra <atishp@rivosinc.com>,
	Deepak Gupta <debug@rivosinc.com>,
	Hui Wang <hui.wang@canonical.com>,
	Pincheng Wang <pincheng.plct@isrc.iscas.ac.cn>,
	Zong Li <zong.li@sifive.com>,
	Vivian Wang <wangruikang@iscas.ac.cn>,
	Rui Qi <qirui.001@bytedance.com>,
	Yunhui Cui <cuiyunhui@bytedance.com>,
	Samuel Holland <samuel.holland@sifive.com>,
	Zishun Yi <vulab@iscas.ac.cn>,
	Sergey Matyukevich <geomatsi@gmail.com>
Subject: Re: [PATCH v7 5/6] riscv: vector: optimize vstate operations
Date: Wed, 11 Nov 2026 23:00:13 +0000	[thread overview]
Message-ID: <20261111-perplexed-encircle-af05cda3dc9c@spud> (raw)
In-Reply-To: <20261111184359.1239821-6-tchiu@tenstorrent.com>

[-- Attachment #1: Type: text/plain, Size: 14393 bytes --]

On Wed, Nov 11, 2026 at 12:43:27PM -0600, Andy Chiu wrote:
> Introduce the riscv_novstateopt to control the optimization of vector
> state operations in the kernel space.
> 
> The optimization enables vector in kernel mode and bypasses vector
> register nulling for user space on the syscall fast path when the boot
> argument "riscv_novstateopt" is not set
> 
> Enabling this optimization yields the following performance benefits:
>  - Cut 80 cycles latency for getpid on Ascalon.
>  - 1.1% ~ 4.09% request throughput improvment on nginx workload with web
>    serving size under 4KB
> 
> Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
> ---
> Changelog v6:
>  - upgrade it to use alternative and change default to enable the
>    optimization

Why? Argument for the default being like this needs to be in the commit
message.

> Changelog v5:
>  - new patch since v5
> ---
>  .../admin-guide/kernel-parameters.txt          | 13 +++++++++++++
>  arch/riscv/include/asm/alternative-macros.h    |  6 ++++++
>  arch/riscv/include/asm/alternative.h           |  3 ---
>  arch/riscv/include/asm/cpufeature-macros.h     |  6 ++++--
>  arch/riscv/include/asm/vector.h                | 16 +++++++++++++++-
>  arch/riscv/kernel/cpufeature.c                 | 18 ++++++++++++++++++
>  arch/riscv/kernel/entry.S                      | 15 +++++++++++++--
>  arch/riscv/kernel/process.c                    |  3 +++
>  arch/riscv/kernel/vector.c                     | 17 +++++++++++++++--
>  9 files changed, 87 insertions(+), 10 deletions(-)
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 0b3c140babd9..e1146ee6ab1e 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -6722,6 +6722,19 @@ Kernel parameters
>  		fcfi	Disable user forward CFI ABI to userspace even if the
>  			landing pad extension is available.
>  
> +	riscv_novstateopt [RISCV,EARLY]
> +			Disable the vector state optimization. By default the
> +			kernel keeps Vector enabled while running in kernel
> +			space, rather than toggling sstatus.VS on every use of
> +			the kernel-mode vector, and skips nulling the vector
> +			registers for user space. Pass this option to restore the
> +			conservative behavior, which catches illegal use of
> +			Vector in kernel code. The optimization roughly cuts
> +			30 ns of getpid() latency on a Blackhole x280 and gives
> +			a 4.09% request throughput improvement for an nginx
> +			workload serving a 2KB web page on a four-core
> +			Ascalon-S.
> +
>  	ro		[KNL] Mount root device read-only on boot
>  
>  	rodata=		[KNL,EARLY]
> diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h
> index 629d884578da..45d9ae1e0aa8 100644
> --- a/arch/riscv/include/asm/alternative-macros.h
> +++ b/arch/riscv/include/asm/alternative-macros.h
> @@ -2,6 +2,12 @@
>  #ifndef __ASM_ALTERNATIVE_MACROS_H
>  #define __ASM_ALTERNATIVE_MACROS_H
>  
> +#include <linux/wordpart.h>
> +#define PATCH_ID_CPUFEATURE_ID(p)		lower_16_bits(p)
> +#define PATCH_ID_CPUFEATURE_VALUE(p)		upper_16_bits(p)
> +
> +#define RISCV_CPUFEAT_VSTATEOPT	0x1

This isn't a cpu feature at all though, so it should not be named like that.

> +
>  #ifdef __ASSEMBLER__
>  
>  .macro ALT_ENTRY oldptr newptr vendor_id patch_id new_len
> diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
> index 6be7b2b6ade9..bc2ecaa9125a 100644
> --- a/arch/riscv/include/asm/alternative.h
> +++ b/arch/riscv/include/asm/alternative.h
> @@ -16,9 +16,6 @@
>  #include <linux/stddef.h>
>  #include <asm/hwcap.h>
>  
> -#define PATCH_ID_CPUFEATURE_ID(p)		lower_16_bits(p)
> -#define PATCH_ID_CPUFEATURE_VALUE(p)		upper_16_bits(p)
> -
>  #define RISCV_ALTERNATIVES_BOOT		0 /* alternatives applied during regular boot */
>  #define RISCV_ALTERNATIVES_MODULE	1 /* alternatives applied during module-init */
>  #define RISCV_ALTERNATIVES_EARLY_BOOT	2 /* alternatives applied before mmu start */
> diff --git a/arch/riscv/include/asm/cpufeature-macros.h b/arch/riscv/include/asm/cpufeature-macros.h
> index adaf9e3fb25c..7bd900899bb0 100644
> --- a/arch/riscv/include/asm/cpufeature-macros.h
> +++ b/arch/riscv/include/asm/cpufeature-macros.h
> @@ -45,14 +45,16 @@ static __always_inline bool __riscv_has_extension_unlikely(const unsigned long v
>  
>  static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
> +	int realext = PATCH_ID_CPUFEATURE_ID(ext);
> +	compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
>  
>  	return __riscv_has_extension_unlikely(STANDARD_EXT, ext);
>  }

Please don't abuse riscv_has_extension_*() for things that are not
extensions. I don't mind if you do something that wraps
__riscv_has_extension_*() to make use of the underlying infrastructure
but I am against muddying the standard extension space with linux internal
stuff - particularly in this manner because this:
> +static __always_inline bool has_vstate_opt(void)
> +{
> +	return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
> +}
is incredibly confusing and error prone.

Recently enough I talked about something very very similar with Jisheng,
in the context of using an alternative for misaligned access, and I
said:
| ...I'd rather see __riscv_has_extension_*() get renamed
| to __riscv_has_cap*(), so that things like unaligned access speed get a
| different namespace to standard and vendor extensions. IOW you'd end up
| with
| 
| static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
| {
| 	compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
| 
| 	return __riscv_has_cap_unlikely(STANDARD_EXT, ext);
| }
| 
| static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor,
| 								const unsigned long ext)
| {
| 	if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
| 		return false;
| 
| 	return __riscv_has_cap_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
| }
| 
| static __always_inline bool riscv_has_cap_unlikely(const unsigned long cap)
| {
| 	return __riscv_has_cap_unlikely(LINUX_CAP, cap);
| }
| 
| Currently standard extensions use 0 as the vendor, perhaps we could then
| use -1 (the value is an unsigned long) for non extension related caps?

What's here, with this realext business definitely looks like a hack.
Doing what I suggest above allows you to have a real key that you can
set, just like the vendor extensions do. You can call a function from
riscv_fill_hwcap() to populate the bitmap and modify
_apply_alternatives() to additionally patch this sort of thing.

Cheers,
Conor.

pw-bot: changes-requested

>  
>  static __always_inline bool riscv_has_extension_likely(const unsigned long ext)
>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
> +	int realext = PATCH_ID_CPUFEATURE_ID(ext);
> +	compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
>  
>  	return __riscv_has_extension_likely(STANDARD_EXT, ext);
>  }
> diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
> index e83f9e0046a9..745ac3ca67b7 100644
> --- a/arch/riscv/include/asm/vector.h
> +++ b/arch/riscv/include/asm/vector.h
> @@ -49,6 +49,7 @@
>  	_res;								\
>  })
>  
> +extern bool riscv_v_vstate_opt;
>  extern unsigned long riscv_v_vsize;
>  int riscv_v_setup_vsize(void);
>  bool insn_is_vector(u32 insn_buf);
> @@ -78,6 +79,11 @@ static __always_inline bool has_vector(void)
>  	return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZVE32X);
>  }
>  
> +static __always_inline bool has_vstate_opt(void)
> +{
> +	return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
> +}
> +
>  static __always_inline bool has_xtheadvector_no_alternatives(void)
>  {
>  	if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
> @@ -122,6 +128,9 @@ static inline bool riscv_v_vstate_query(struct pt_regs *regs)
>  
>  static __always_inline void riscv_v_enable(void)
>  {
> +	if (has_vstate_opt())
> +		return;
> +
>  	if (has_xtheadvector())
>  		csr_set(CSR_SSTATUS, SR_VS_THEAD);
>  	else
> @@ -130,6 +139,9 @@ static __always_inline void riscv_v_enable(void)
>  
>  static __always_inline void riscv_v_disable(void)
>  {
> +	if (has_vstate_opt())
> +		return;
> +
>  	if (has_xtheadvector())
>  		csr_clear(CSR_SSTATUS, SR_VS_THEAD);
>  	else
> @@ -336,7 +348,8 @@ static inline void riscv_v_vstate_set_restore(struct task_struct *task,
>  static inline void riscv_v_vstate_discard(struct pt_regs *regs)
>  {
>  	if (__riscv_v_vstate_check_gt(regs->status, INITIAL)) {
> -		riscv_v_vstate_set_restore(current, regs);
> +		if (!has_vstate_opt())
> +			riscv_v_vstate_set_restore(current, regs);
>  		riscv_v_vstate_init(regs);
>  	}
>  }
> @@ -422,6 +435,7 @@ struct pt_regs;
>  
>  static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
>  static __always_inline bool has_vector(void) { return false; }
> +static __always_inline bool has_vstate_opt(void) { return false; }
>  static __always_inline bool insn_is_vector(u32 insn_buf) { return false; }
>  static __always_inline bool has_xtheadvector_no_alternatives(void) { return false; }
>  static __always_inline bool has_xtheadvector(void) { return false; }
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 72bce616491f..041f6a35fba3 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -1294,6 +1294,19 @@ void riscv_clear_hypervisor_csr(void)
>  	csr_clear(CSR_HSTATUS, HSTATUS_HU);
>  }
>  
> +/*
> + * Leaving Vector enabled while in the kernel relies on the vstate alternatives
> + * being patched in. It can be turned off on the command line to catch illegal
> + * use of Vector in kernel code.
> + */
> +bool riscv_v_vstate_opt = true;
> +static int __init riscv_novstateopt_setup(char *__unused)
> +{
> +	riscv_v_vstate_opt = false;
> +	return 0;
> +}
> +early_param("riscv_novstateopt", riscv_novstateopt_setup);
> +
>  /*
>   * Alternative patch sites consider 48 bits when determining when to patch
>   * the old instruction sequence with the new. These bits are broken into a
> @@ -1322,6 +1335,11 @@ static bool riscv_cpufeature_patch_check(u16 id, u16 value)
>  		 * then the alternative cannot be applied.
>  		 */
>  		return riscv_cboz_block_size <= (1U << value);
> +	case RISCV_ISA_EXT_ZVE32X:
> +		if (value == RISCV_CPUFEAT_VSTATEOPT)
> +			return riscv_v_vstate_opt;
> +
> +		return true;
>  	}
>  
>  	return false;
> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
> index 628b85e3915a..bb4787711f2c 100644
> --- a/arch/riscv/kernel/entry.S
> +++ b/arch/riscv/kernel/entry.S
> @@ -6,6 +6,7 @@
>  
>  #include <linux/init.h>
>  #include <linux/linkage.h>
> +#include <linux/stringify.h>
>  
>  #include <asm/alternative-macros.h>
>  #include <asm/asm.h>
> @@ -175,10 +176,13 @@ SYM_CODE_START(handle_exception)
>  	 * Disable user-mode memory access as it should only be set in the
>  	 * actual user copy routines.
>  	 *
> -	 * Disable the FPU/Vector to detect illegal usage of floating point
> +	 * Disable the FPU to detect illegal usage of floating point
>  	 * or vector in kernel space.
>  	 */
> -	li t0, SR_SUM | SR_FS_VS
> +	li t0, SR_SUM | SR_FS
> +	ALTERNATIVE(__stringify(ori t0, t0, SR_VS), "nop", 0,
> +		    (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
> +		    CONFIG_RISCV_ISA_V)
>  #ifdef CONFIG_64BIT
>  	li t1, SR_ELP
>  	or t0, t0, t1
> @@ -186,6 +190,13 @@ SYM_CODE_START(handle_exception)
>  
>  	REG_L s0, TASK_TI_USER_SP(tp)
>  	csrrc s1, CSR_STATUS, t0
> +	ALTERNATIVE("j .Lskip_v_enable", __stringify(andi t0, s1, SR_VS), 0,
> +		    (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
> +		    CONFIG_RISCV_ISA_V)
> +	bnez t0, .Lskip_v_enable
> +	li a0, SR_VS_INITIAL
> +	csrs CSR_STATUS, a0
> +.Lskip_v_enable:
>  	save_userssp s2, s1
>  	csrr s2, CSR_EPC
>  	csrr s3, CSR_TVAL
> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> index 34c1d498d1ca..27146b3fa738 100644
> --- a/arch/riscv/kernel/process.c
> +++ b/arch/riscv/kernel/process.c
> @@ -258,6 +258,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
>  		/* Supervisor/Machine, irqs on: */
>  		childregs->status = SR_PP | SR_PIE;
>  
> +		if (has_vstate_opt())
> +			riscv_v_vstate_init(childregs);
> +
>  		p->thread.s[0] = (unsigned long)args->fn;
>  		p->thread.s[1] = (unsigned long)args->fn_arg;
>  		p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
> diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
> index 6fd541f5d5cb..eec9deff8da7 100644
> --- a/arch/riscv/kernel/vector.c
> +++ b/arch/riscv/kernel/vector.c
> @@ -12,6 +12,7 @@
>  #include <linux/prctl.h>
>  
>  #include <asm/thread_info.h>
> +#include <asm/cpufeature.h>
>  #include <asm/processor.h>
>  #include <asm/insn.h>
>  #include <asm/vector.h>
> @@ -69,6 +70,16 @@ void riscv_v_ucontext_save(struct task_struct *tsk)
>  int riscv_v_setup_vsize(void)
>  {
>  	unsigned long this_vsize;
> +	bool v_always_on = false;
> +
> +	/*
> +	 * has_vstate_opt() cannot be used here if called from riscv_fill_hwcap(), before
> +	 * apply_boot_alternatives(),
> +	 */
> +	if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X) && riscv_v_vstate_opt) {
> +		v_always_on = true;
> +		csr_set(CSR_SSTATUS, SR_VS_INITIAL);
> +	}
>  
>  	/*
>  	 * There are 32 vector registers with vlenb length.
> @@ -81,9 +92,11 @@ int riscv_v_setup_vsize(void)
>  		return 0;
>  	}
>  
> -	riscv_v_enable();
> +	if (!v_always_on)
> +		riscv_v_enable();
>  	this_vsize = csr_read(CSR_VLENB) * 32;
> -	riscv_v_disable();
> +	if (!v_always_on)
> +		riscv_v_disable();
>  
>  	if (!riscv_v_vsize) {
>  		riscv_v_vsize = this_vsize;
> -- 
> 2.43.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

WARNING: multiple messages have this Message-ID (diff)
From: Conor Dooley <conor@kernel.org>
To: Andy Chiu <tchiu@tenstorrent.com>
Cc: Jonathan Corbet <corbet@lwn.net>,
	Shuah Khan <skhan@linuxfoundation.org>,
	Randy Dunlap <rdunlap@infradead.org>,
	Paul Walmsley <pjw@kernel.org>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Alexandre Ghiti <alex@ghiti.fr>,
	linux-doc@vger.kernel.org, linux-riscv@lists.infradead.org,
	andybnac@gmail.com, dfustini@oss.tenstorrent.com,
	greentime.hu@sifive.com,
	"Mike Rapoport (Microsoft)" <rppt@kernel.org>,
	Arnd Bergmann <arnd@arndb.de>,
	Karl Mehltretter <kmehltretter@gmail.com>,
	"Borislav Petkov (AMD)" <bp@alien8.de>,
	Dapeng Mi <dapeng1.mi@linux.intel.com>,
	Marco Elver <elver@google.com>,
	Ethan Nelson-Moore <enelsonmoore@gmail.com>,
	Jeff Layton <jlayton@kernel.org>,
	Jisheng Zhang <jszhang@kernel.org>,
	Conor Dooley <conor.dooley@microchip.com>,
	Yong-Xuan Wang <yongxuan.wang@sifive.com>,
	Anup Patel <anup@brainfault.org>,
	Aurelien Jarno <aurelien@aurel32.net>,
	daichengrong <daichengrong@iscas.ac.cn>,
	Troy Mitchell <troy.mitchell@linux.dev>,
	Guobin Zhang <guobin.zhang@intel.com>,
	Guodong Xu <docular.xu@gmail.com>,
	Andrew Jones <andrew.jones@linux.dev>,
	Charlie Jenkins <thecharlesjenkins@gmail.com>,
	Atish Patra <atishp@rivosinc.com>,
	Deepak Gupta <debug@rivosinc.com>,
	Hui Wang <hui.wang@canonical.com>,
	Pincheng Wang <pincheng.plct@isrc.iscas.ac.cn>,
	Zong Li <zong.li@sifive.com>,
	Vivian Wang <wangruikang@iscas.ac.cn>,
	Rui Qi <qirui.001@bytedance.com>,
	Yunhui Cui <cuiyunhui@bytedance.com>,
	Samuel Holland <samuel.holland@sifive.com>,
	Zishun Yi <vulab@iscas.ac.cn>,
	Sergey Matyukevich <geomatsi@gmail.com>
Subject: Re: [PATCH v7 5/6] riscv: vector: optimize vstate operations
Date: Wed, 11 Nov 2026 23:00:13 +0000	[thread overview]
Message-ID: <20261111-perplexed-encircle-af05cda3dc9c@spud> (raw)
In-Reply-To: <20261111184359.1239821-6-tchiu@tenstorrent.com>


[-- Attachment #1.1: Type: text/plain, Size: 14393 bytes --]

On Wed, Nov 11, 2026 at 12:43:27PM -0600, Andy Chiu wrote:
> Introduce the riscv_novstateopt to control the optimization of vector
> state operations in the kernel space.
> 
> The optimization enables vector in kernel mode and bypasses vector
> register nulling for user space on the syscall fast path when the boot
> argument "riscv_novstateopt" is not set
> 
> Enabling this optimization yields the following performance benefits:
>  - Cut 80 cycles latency for getpid on Ascalon.
>  - 1.1% ~ 4.09% request throughput improvment on nginx workload with web
>    serving size under 4KB
> 
> Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
> ---
> Changelog v6:
>  - upgrade it to use alternative and change default to enable the
>    optimization

Why? Argument for the default being like this needs to be in the commit
message.

> Changelog v5:
>  - new patch since v5
> ---
>  .../admin-guide/kernel-parameters.txt          | 13 +++++++++++++
>  arch/riscv/include/asm/alternative-macros.h    |  6 ++++++
>  arch/riscv/include/asm/alternative.h           |  3 ---
>  arch/riscv/include/asm/cpufeature-macros.h     |  6 ++++--
>  arch/riscv/include/asm/vector.h                | 16 +++++++++++++++-
>  arch/riscv/kernel/cpufeature.c                 | 18 ++++++++++++++++++
>  arch/riscv/kernel/entry.S                      | 15 +++++++++++++--
>  arch/riscv/kernel/process.c                    |  3 +++
>  arch/riscv/kernel/vector.c                     | 17 +++++++++++++++--
>  9 files changed, 87 insertions(+), 10 deletions(-)
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 0b3c140babd9..e1146ee6ab1e 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -6722,6 +6722,19 @@ Kernel parameters
>  		fcfi	Disable user forward CFI ABI to userspace even if the
>  			landing pad extension is available.
>  
> +	riscv_novstateopt [RISCV,EARLY]
> +			Disable the vector state optimization. By default the
> +			kernel keeps Vector enabled while running in kernel
> +			space, rather than toggling sstatus.VS on every use of
> +			the kernel-mode vector, and skips nulling the vector
> +			registers for user space. Pass this option to restore the
> +			conservative behavior, which catches illegal use of
> +			Vector in kernel code. The optimization roughly cuts
> +			30 ns of getpid() latency on a Blackhole x280 and gives
> +			a 4.09% request throughput improvement for an nginx
> +			workload serving a 2KB web page on a four-core
> +			Ascalon-S.
> +
>  	ro		[KNL] Mount root device read-only on boot
>  
>  	rodata=		[KNL,EARLY]
> diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h
> index 629d884578da..45d9ae1e0aa8 100644
> --- a/arch/riscv/include/asm/alternative-macros.h
> +++ b/arch/riscv/include/asm/alternative-macros.h
> @@ -2,6 +2,12 @@
>  #ifndef __ASM_ALTERNATIVE_MACROS_H
>  #define __ASM_ALTERNATIVE_MACROS_H
>  
> +#include <linux/wordpart.h>
> +#define PATCH_ID_CPUFEATURE_ID(p)		lower_16_bits(p)
> +#define PATCH_ID_CPUFEATURE_VALUE(p)		upper_16_bits(p)
> +
> +#define RISCV_CPUFEAT_VSTATEOPT	0x1

This isn't a cpu feature at all though, so it should not be named like that.

> +
>  #ifdef __ASSEMBLER__
>  
>  .macro ALT_ENTRY oldptr newptr vendor_id patch_id new_len
> diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
> index 6be7b2b6ade9..bc2ecaa9125a 100644
> --- a/arch/riscv/include/asm/alternative.h
> +++ b/arch/riscv/include/asm/alternative.h
> @@ -16,9 +16,6 @@
>  #include <linux/stddef.h>
>  #include <asm/hwcap.h>
>  
> -#define PATCH_ID_CPUFEATURE_ID(p)		lower_16_bits(p)
> -#define PATCH_ID_CPUFEATURE_VALUE(p)		upper_16_bits(p)
> -
>  #define RISCV_ALTERNATIVES_BOOT		0 /* alternatives applied during regular boot */
>  #define RISCV_ALTERNATIVES_MODULE	1 /* alternatives applied during module-init */
>  #define RISCV_ALTERNATIVES_EARLY_BOOT	2 /* alternatives applied before mmu start */
> diff --git a/arch/riscv/include/asm/cpufeature-macros.h b/arch/riscv/include/asm/cpufeature-macros.h
> index adaf9e3fb25c..7bd900899bb0 100644
> --- a/arch/riscv/include/asm/cpufeature-macros.h
> +++ b/arch/riscv/include/asm/cpufeature-macros.h
> @@ -45,14 +45,16 @@ static __always_inline bool __riscv_has_extension_unlikely(const unsigned long v
>  
>  static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
> +	int realext = PATCH_ID_CPUFEATURE_ID(ext);
> +	compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
>  
>  	return __riscv_has_extension_unlikely(STANDARD_EXT, ext);
>  }

Please don't abuse riscv_has_extension_*() for things that are not
extensions. I don't mind if you do something that wraps
__riscv_has_extension_*() to make use of the underlying infrastructure
but I am against muddying the standard extension space with linux internal
stuff - particularly in this manner because this:
> +static __always_inline bool has_vstate_opt(void)
> +{
> +	return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
> +}
is incredibly confusing and error prone.

Recently enough I talked about something very very similar with Jisheng,
in the context of using an alternative for misaligned access, and I
said:
| ...I'd rather see __riscv_has_extension_*() get renamed
| to __riscv_has_cap*(), so that things like unaligned access speed get a
| different namespace to standard and vendor extensions. IOW you'd end up
| with
| 
| static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
| {
| 	compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
| 
| 	return __riscv_has_cap_unlikely(STANDARD_EXT, ext);
| }
| 
| static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor,
| 								const unsigned long ext)
| {
| 	if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
| 		return false;
| 
| 	return __riscv_has_cap_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
| }
| 
| static __always_inline bool riscv_has_cap_unlikely(const unsigned long cap)
| {
| 	return __riscv_has_cap_unlikely(LINUX_CAP, cap);
| }
| 
| Currently standard extensions use 0 as the vendor, perhaps we could then
| use -1 (the value is an unsigned long) for non extension related caps?

What's here, with this realext business definitely looks like a hack.
Doing what I suggest above allows you to have a real key that you can
set, just like the vendor extensions do. You can call a function from
riscv_fill_hwcap() to populate the bitmap and modify
_apply_alternatives() to additionally patch this sort of thing.

Cheers,
Conor.

pw-bot: changes-requested

>  
>  static __always_inline bool riscv_has_extension_likely(const unsigned long ext)
>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
> +	int realext = PATCH_ID_CPUFEATURE_ID(ext);
> +	compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
>  
>  	return __riscv_has_extension_likely(STANDARD_EXT, ext);
>  }
> diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
> index e83f9e0046a9..745ac3ca67b7 100644
> --- a/arch/riscv/include/asm/vector.h
> +++ b/arch/riscv/include/asm/vector.h
> @@ -49,6 +49,7 @@
>  	_res;								\
>  })
>  
> +extern bool riscv_v_vstate_opt;
>  extern unsigned long riscv_v_vsize;
>  int riscv_v_setup_vsize(void);
>  bool insn_is_vector(u32 insn_buf);
> @@ -78,6 +79,11 @@ static __always_inline bool has_vector(void)
>  	return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZVE32X);
>  }
>  
> +static __always_inline bool has_vstate_opt(void)
> +{
> +	return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
> +}
> +
>  static __always_inline bool has_xtheadvector_no_alternatives(void)
>  {
>  	if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
> @@ -122,6 +128,9 @@ static inline bool riscv_v_vstate_query(struct pt_regs *regs)
>  
>  static __always_inline void riscv_v_enable(void)
>  {
> +	if (has_vstate_opt())
> +		return;
> +
>  	if (has_xtheadvector())
>  		csr_set(CSR_SSTATUS, SR_VS_THEAD);
>  	else
> @@ -130,6 +139,9 @@ static __always_inline void riscv_v_enable(void)
>  
>  static __always_inline void riscv_v_disable(void)
>  {
> +	if (has_vstate_opt())
> +		return;
> +
>  	if (has_xtheadvector())
>  		csr_clear(CSR_SSTATUS, SR_VS_THEAD);
>  	else
> @@ -336,7 +348,8 @@ static inline void riscv_v_vstate_set_restore(struct task_struct *task,
>  static inline void riscv_v_vstate_discard(struct pt_regs *regs)
>  {
>  	if (__riscv_v_vstate_check_gt(regs->status, INITIAL)) {
> -		riscv_v_vstate_set_restore(current, regs);
> +		if (!has_vstate_opt())
> +			riscv_v_vstate_set_restore(current, regs);
>  		riscv_v_vstate_init(regs);
>  	}
>  }
> @@ -422,6 +435,7 @@ struct pt_regs;
>  
>  static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
>  static __always_inline bool has_vector(void) { return false; }
> +static __always_inline bool has_vstate_opt(void) { return false; }
>  static __always_inline bool insn_is_vector(u32 insn_buf) { return false; }
>  static __always_inline bool has_xtheadvector_no_alternatives(void) { return false; }
>  static __always_inline bool has_xtheadvector(void) { return false; }
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 72bce616491f..041f6a35fba3 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -1294,6 +1294,19 @@ void riscv_clear_hypervisor_csr(void)
>  	csr_clear(CSR_HSTATUS, HSTATUS_HU);
>  }
>  
> +/*
> + * Leaving Vector enabled while in the kernel relies on the vstate alternatives
> + * being patched in. It can be turned off on the command line to catch illegal
> + * use of Vector in kernel code.
> + */
> +bool riscv_v_vstate_opt = true;
> +static int __init riscv_novstateopt_setup(char *__unused)
> +{
> +	riscv_v_vstate_opt = false;
> +	return 0;
> +}
> +early_param("riscv_novstateopt", riscv_novstateopt_setup);
> +
>  /*
>   * Alternative patch sites consider 48 bits when determining when to patch
>   * the old instruction sequence with the new. These bits are broken into a
> @@ -1322,6 +1335,11 @@ static bool riscv_cpufeature_patch_check(u16 id, u16 value)
>  		 * then the alternative cannot be applied.
>  		 */
>  		return riscv_cboz_block_size <= (1U << value);
> +	case RISCV_ISA_EXT_ZVE32X:
> +		if (value == RISCV_CPUFEAT_VSTATEOPT)
> +			return riscv_v_vstate_opt;
> +
> +		return true;
>  	}
>  
>  	return false;
> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
> index 628b85e3915a..bb4787711f2c 100644
> --- a/arch/riscv/kernel/entry.S
> +++ b/arch/riscv/kernel/entry.S
> @@ -6,6 +6,7 @@
>  
>  #include <linux/init.h>
>  #include <linux/linkage.h>
> +#include <linux/stringify.h>
>  
>  #include <asm/alternative-macros.h>
>  #include <asm/asm.h>
> @@ -175,10 +176,13 @@ SYM_CODE_START(handle_exception)
>  	 * Disable user-mode memory access as it should only be set in the
>  	 * actual user copy routines.
>  	 *
> -	 * Disable the FPU/Vector to detect illegal usage of floating point
> +	 * Disable the FPU to detect illegal usage of floating point
>  	 * or vector in kernel space.
>  	 */
> -	li t0, SR_SUM | SR_FS_VS
> +	li t0, SR_SUM | SR_FS
> +	ALTERNATIVE(__stringify(ori t0, t0, SR_VS), "nop", 0,
> +		    (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
> +		    CONFIG_RISCV_ISA_V)
>  #ifdef CONFIG_64BIT
>  	li t1, SR_ELP
>  	or t0, t0, t1
> @@ -186,6 +190,13 @@ SYM_CODE_START(handle_exception)
>  
>  	REG_L s0, TASK_TI_USER_SP(tp)
>  	csrrc s1, CSR_STATUS, t0
> +	ALTERNATIVE("j .Lskip_v_enable", __stringify(andi t0, s1, SR_VS), 0,
> +		    (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
> +		    CONFIG_RISCV_ISA_V)
> +	bnez t0, .Lskip_v_enable
> +	li a0, SR_VS_INITIAL
> +	csrs CSR_STATUS, a0
> +.Lskip_v_enable:
>  	save_userssp s2, s1
>  	csrr s2, CSR_EPC
>  	csrr s3, CSR_TVAL
> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> index 34c1d498d1ca..27146b3fa738 100644
> --- a/arch/riscv/kernel/process.c
> +++ b/arch/riscv/kernel/process.c
> @@ -258,6 +258,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
>  		/* Supervisor/Machine, irqs on: */
>  		childregs->status = SR_PP | SR_PIE;
>  
> +		if (has_vstate_opt())
> +			riscv_v_vstate_init(childregs);
> +
>  		p->thread.s[0] = (unsigned long)args->fn;
>  		p->thread.s[1] = (unsigned long)args->fn_arg;
>  		p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
> diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
> index 6fd541f5d5cb..eec9deff8da7 100644
> --- a/arch/riscv/kernel/vector.c
> +++ b/arch/riscv/kernel/vector.c
> @@ -12,6 +12,7 @@
>  #include <linux/prctl.h>
>  
>  #include <asm/thread_info.h>
> +#include <asm/cpufeature.h>
>  #include <asm/processor.h>
>  #include <asm/insn.h>
>  #include <asm/vector.h>
> @@ -69,6 +70,16 @@ void riscv_v_ucontext_save(struct task_struct *tsk)
>  int riscv_v_setup_vsize(void)
>  {
>  	unsigned long this_vsize;
> +	bool v_always_on = false;
> +
> +	/*
> +	 * has_vstate_opt() cannot be used here if called from riscv_fill_hwcap(), before
> +	 * apply_boot_alternatives(),
> +	 */
> +	if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X) && riscv_v_vstate_opt) {
> +		v_always_on = true;
> +		csr_set(CSR_SSTATUS, SR_VS_INITIAL);
> +	}
>  
>  	/*
>  	 * There are 32 vector registers with vlenb length.
> @@ -81,9 +92,11 @@ int riscv_v_setup_vsize(void)
>  		return 0;
>  	}
>  
> -	riscv_v_enable();
> +	if (!v_always_on)
> +		riscv_v_enable();
>  	this_vsize = csr_read(CSR_VLENB) * 32;
> -	riscv_v_disable();
> +	if (!v_always_on)
> +		riscv_v_disable();
>  
>  	if (!riscv_v_vsize) {
>  		riscv_v_vsize = this_vsize;
> -- 
> 2.43.0
> 

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 161 bytes --]

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

  reply	other threads:[~2026-11-11 23:00 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-11 18:43 [PATCH v7 0/6] riscv: optimize mode switch latency for Vector Andy Chiu
2026-11-11 18:43 ` Andy Chiu
2026-11-11 18:43 ` [PATCH v7 1/6] riscv: vector: refactor vector context operations Andy Chiu
2026-11-11 18:43   ` Andy Chiu
2026-11-11 18:43   ` Andy Chiu
2026-11-11 19:30   ` sashiko-bot
2026-11-11 18:43 ` [PATCH v7 2/6] riscv: introduce riscv_v_ucontext_save() for signal and ptrace Andy Chiu
2026-11-11 18:43 ` [PATCH v7 3/6] riscv: clarify vector state semantics on syscall and context switch Andy Chiu
2026-11-12 12:12   ` kernel test robot
2026-11-12 12:12     ` kernel test robot
2026-11-11 18:43 ` [PATCH v7 4/6] selftests: riscv: Extend vector tests for sigreturn and ptrace Andy Chiu
2026-11-11 18:43   ` Andy Chiu
2026-11-11 18:43 ` [PATCH v7 5/6] riscv: vector: optimize vstate operations Andy Chiu
2026-11-11 18:43   ` Andy Chiu
2026-11-11 23:00   ` Conor Dooley [this message]
2026-11-11 23:00     ` Conor Dooley
2026-11-11 18:43 ` [PATCH v7 6/6] riscv: KVM: do not save host vector context for vcpu Andy Chiu
2026-11-11 18:43   ` Andy Chiu
2026-11-11 18:43   ` Andy Chiu
2026-11-11 20:03   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261111-perplexed-encircle-af05cda3dc9c@spud \
    --to=conor@kernel.org \
    --cc=alex@ghiti.fr \
    --cc=andrew.jones@linux.dev \
    --cc=andybnac@gmail.com \
    --cc=anup@brainfault.org \
    --cc=aou@eecs.berkeley.edu \
    --cc=arnd@arndb.de \
    --cc=atishp@rivosinc.com \
    --cc=aurelien@aurel32.net \
    --cc=bp@alien8.de \
    --cc=conor.dooley@microchip.com \
    --cc=corbet@lwn.net \
    --cc=cuiyunhui@bytedance.com \
    --cc=daichengrong@iscas.ac.cn \
    --cc=dapeng1.mi@linux.intel.com \
    --cc=debug@rivosinc.com \
    --cc=dfustini@oss.tenstorrent.com \
    --cc=docular.xu@gmail.com \
    --cc=elver@google.com \
    --cc=enelsonmoore@gmail.com \
    --cc=geomatsi@gmail.com \
    --cc=greentime.hu@sifive.com \
    --cc=guobin.zhang@intel.com \
    --cc=hui.wang@canonical.com \
    --cc=jlayton@kernel.org \
    --cc=jszhang@kernel.org \
    --cc=kmehltretter@gmail.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=palmer@dabbelt.com \
    --cc=pincheng.plct@isrc.iscas.ac.cn \
    --cc=pjw@kernel.org \
    --cc=qirui.001@bytedance.com \
    --cc=rdunlap@infradead.org \
    --cc=rppt@kernel.org \
    --cc=samuel.holland@sifive.com \
    --cc=skhan@linuxfoundation.org \
    --cc=tchiu@tenstorrent.com \
    --cc=thecharlesjenkins@gmail.com \
    --cc=troy.mitchell@linux.dev \
    --cc=vulab@iscas.ac.cn \
    --cc=wangruikang@iscas.ac.cn \
    --cc=yongxuan.wang@sifive.com \
    --cc=zong.li@sifive.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.