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 --]
prev parent reply other threads:[~2026-11-11 23:00 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20261111184359.1239821-1-tchiu@tenstorrent.com>
2026-11-11 18:43 ` [PATCH v7 5/6] riscv: vector: optimize vstate operations Andy Chiu
2026-11-11 23:00 ` Conor Dooley [this message]
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox