Skip to contentSkip to conversation

riscv: Add vector ISA support

RFC PATCH Superseded Greentime Hu 10 participants 56 messages Sep 8, 2021 – Nov 9, 2021

Subsystems (3)

v8 of 10 Superseded Latest is v10 →

lore
Share & tools
lore
#0 lore raw

v8 cover riscv: Add vector ISA support

This patchset is implemented based on vector 1.0-rc1 spec to add vector support in riscv Linux kernel. To make this happen, we defined a new structure __riscv_v_state to save the vector related registers. It is used for both kernel space and user space.

- In kernel space, the datap pointer in __riscv_v_state will be allocated dynamically to save vector registers.
- In user space,
- In signal handler of user space, datap will point to the address of the __riscv_v_state data structure to save vector registers in stack. We also create a __reserved[] array for future extensions.
- In ptrace, the data will be put in ubuf in which we use riscv_vr_get()/riscv_vr_set() to get or set the __riscv_v_state data structure from/to it, datap pointer would be zeroed and vector registers will be copied to the address right after the __riscv_v_state structure in ubuf.

This patchset also adds support for kernel mode vector, kernel XOR implementation with vector ISA and includes several bug fixes and code refinement.

This patchset is rebased to v5.14 and it is tested by running several vector programs simultaneously. It also can get the correct ucontext_t in signal handler and restore correct context after sigreturn. It is also tested with ptrace() syscall to use PTRACE_GETREGSET/PTRACE_SETREGSET to get/set the vector registers. I have tested vlen=128 and vlen=256 cases in qemu-system-riscv64 provided by Frank Chang.

We have sent patches to glibc mailing list for ifunc support and sigcontext changes. We will send patches for vector support to glibc mailing list recently.

[1] https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc

---
Changelog V8
- Rebase to v5.14
- Refine struct __riscv_v_state with struct __riscv_ctx_hdr
- Refine has_vector into a static key
- Defined __reserved space in struct sigcontext for vector and future extensions

Changelog V7
- Add support for kernel mode vector
- Add vector extension XOR implementation
- Optimize task switch codes of vector
- Allocate space for vector registers in start_thread()
- Fix an illegal instruction exception when accessing vlenb
- Optimize vector registers initialization
- Initialize vector registers with proper vsetvli then it can work normally
- Refine ptrace porting due to generic API changed
- Code clean up

Changelog V6
- Replace vle.v/vse.v instructions with vle8.v/vse8.v based on 0.9 spec
- Add comments based on mailinglist feedback
- Fix rv32 build error

Changelog V5
- Using regset_size() correctly in generic ptrace
- Fix the ptrace porting
- Fix compile warning

Changelog V4
- Support dynamic vlen
- Fix bugs: lazy save/resotre, not saving vtype
- Update VS bit offset based on latest vector spec
- Add new vector csr based on latest vector spec
- Code refine and removed unused macros

Changelog V3
- Rebase linux-5.6-rc3 and tested with qemu
- Seperate patches with Anup's advice
- Give out a ABI puzzle with unlimited vlen

Changelog V2
- Fixup typo "vecotr, fstate_save->vstate_save".
- Fixup wrong saved registers' length in vector.S.
- Seperate unrelated patches from this one.

Greentime Hu (15):
riscv: Add new csr defines related to vector extension
riscv: Add has_vector/riscv_vsize to save vector features.
riscv: Add vector struct and assembler definitions
riscv: Add task switch support for vector
riscv: Add ptrace vector support
riscv: Add sigcontext save/restore for vector
riscv: Add support for kernel mode vector
riscv: Use CSR_STATUS to replace sstatus in vector.S
riscv: Add vector extension XOR implementation
riscv: Initialize vector registers with proper vsetvli then it can
work normally
riscv: Optimize vector registers initialization
riscv: Fix an illegal instruction exception when accessing vlenb
without enable vector first
riscv: Allocate space for vector registers in start_thread()
riscv: Optimize task switch codes of vector
riscv: Turn has_vector into a static key if VECTOR=y

Guo Ren (5):
riscv: Separate patch for cflags and aflags
riscv: Rename __switch_to_aux -> fpu
riscv: Extending cpufeature.c to detect V-extension
riscv: Add vector feature to compile
riscv: Reset vector register

Vincent Chen (1):
riscv: signal: Report signal frame size to userspace via auxv

 arch/riscv/Kconfig                       |   9 ++
 arch/riscv/Makefile                      |  19 ++-
 arch/riscv/include/asm/csr.h             |  16 ++-
 arch/riscv/include/asm/elf.h             |  41 +++---
 arch/riscv/include/asm/processor.h       |   3 +
 arch/riscv/include/asm/switch_to.h       |  71 +++++++++-
 arch/riscv/include/asm/vector.h          |  16 +++
 arch/riscv/include/asm/xor.h             |  74 ++++++++++
 arch/riscv/include/uapi/asm/auxvec.h     |   1 +
 arch/riscv/include/uapi/asm/hwcap.h      |   1 +
 arch/riscv/include/uapi/asm/ptrace.h     |  25 ++++
 arch/riscv/include/uapi/asm/sigcontext.h |  24 ++++
 arch/riscv/kernel/Makefile               |   7 +
 arch/riscv/kernel/asm-offsets.c          |   8 ++
 arch/riscv/kernel/cpufeature.c           |  16 +++
 arch/riscv/kernel/entry.S                |   6 +-
 arch/riscv/kernel/head.S                 |  22 ++-
 arch/riscv/kernel/kernel_mode_vector.c   | 158 +++++++++++++++++++++
 arch/riscv/kernel/process.c              |  49 +++++++
 arch/riscv/kernel/ptrace.c               |  71 ++++++++++
 arch/riscv/kernel/setup.c                |   4 +
 arch/riscv/kernel/signal.c               | 172 ++++++++++++++++++++++-
 arch/riscv/kernel/vector.S               |  81 +++++++++++
 arch/riscv/lib/Makefile                  |   1 +
 arch/riscv/lib/xor.S                     |  81 +++++++++++
 include/uapi/linux/elf.h                 |   1 +
 26 files changed, 941 insertions(+), 36 deletions(-)
 create mode 100644 arch/riscv/include/asm/vector.h
 create mode 100644 arch/riscv/include/asm/xor.h
 create mode 100644 arch/riscv/kernel/kernel_mode_vector.c
 create mode 100644 arch/riscv/kernel/vector.S
 create mode 100644 arch/riscv/lib/xor.S
Signature · 1 line
2.31.1
#1 lore raw

RFC PATCH v8 1/21 riscv: Separate patch for cflags and aflags

From: Guo Ren <[email protected]>

Use "subst fd" in Makefile is a hack way and it's not convenient to add new ISA feature. Just separate them into riscv-march-cflags and riscv-march-aflags.

---
 arch/riscv/Makefile | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)
arch/riscv/Makefile +12 -6
index bc74afdbf31e..428bd3bc202f 100644
@@ -48,12 +48,18 @@ endif
 endif
 
 # ISA string setting
-riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32ima
-riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64ima
-riscv-march-$(CONFIG_FPU)		:= $(riscv-march-y)fd
-riscv-march-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-y)c
-KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
-KBUILD_AFLAGS += -march=$(riscv-march-y)
+riscv-march-cflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
+riscv-march-cflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
+riscv-march-$(CONFIG_FPU)			:= $(riscv-march-y)fd
+riscv-march-cflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-cflags-y)c
+
+riscv-march-aflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
+riscv-march-aflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
+riscv-march-aflags-$(CONFIG_FPU)		:= $(riscv-march-aflags-y)fd
+riscv-march-aflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-aflags-y)c
+
+KBUILD_CFLAGS += -march=$(riscv-march-cflags-y)
+KBUILD_AFLAGS += -march=$(riscv-march-aflags-y)
 
 KBUILD_CFLAGS += -mno-save-restore
 KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET)
Signature · 1 line
2.31.1
#2 lore raw

RFC PATCH v8 2/21 riscv: Rename __switch_to_aux -> fpu

In reply to Greentime Hu

From: Guo Ren <[email protected]>

The name of __switch_to_aux is not clear and rename it with the determine function: __switch_to_fpu. Next we could add other regs' switch.

---
 arch/riscv/include/asm/switch_to.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/riscv/include/asm/switch_to.h +3 -3
index 0a3f4f95c555..ec83770b3d98 100644
@@ -45,7 +45,7 @@ static inline void fstate_restore(struct task_struct *task,
 	}
 }
 
-static inline void __switch_to_aux(struct task_struct *prev,
+static inline void __switch_to_fpu(struct task_struct *prev,
 				   struct task_struct *next)
 {
 	struct pt_regs *regs;
@@ -65,7 +65,7 @@ static __always_inline bool has_fpu(void)
 static __always_inline bool has_fpu(void) { return false; }
 #define fstate_save(task, regs) do { } while (0)
 #define fstate_restore(task, regs) do { } while (0)
-#define __switch_to_aux(__prev, __next) do { } while (0)
+#define __switch_to_fpu(__prev, __next) do { } while (0)
 #endif
 
 extern struct task_struct *__switch_to(struct task_struct *,
@@ -76,7 +76,7 @@ do {							\
 	struct task_struct *__prev = (prev);		\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
-		__switch_to_aux(__prev, __next);	\
+		__switch_to_fpu(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
 
Signature · 1 line
2.31.1
#3 lore raw

RFC PATCH v8 3/21 riscv: Extending cpufeature.c to detect V-extension

In reply to Greentime Hu

From: Guo Ren <[email protected]>

Current cpufeature.c doesn't support detecting V-extension, because "rv64" also contain a 'v' letter and we need to skip it.

---
 arch/riscv/include/uapi/asm/hwcap.h | 1 +
 arch/riscv/kernel/cpufeature.c      | 1 +
 2 files changed, 2 insertions(+)
arch/riscv/include/uapi/asm/hwcap.h +1 -0
index 46dc3f5ee99f..c52bb7bbbabe 100644
@@ -21,5 +21,6 @@
 #define COMPAT_HWCAP_ISA_F	(1 << ('F' - 'A'))
 #define COMPAT_HWCAP_ISA_D	(1 << ('D' - 'A'))
 #define COMPAT_HWCAP_ISA_C	(1 << ('C' - 'A'))
+#define COMPAT_HWCAP_ISA_V	(1 << ('V' - 'A'))
 
 #endif /* _UAPI_ASM_RISCV_HWCAP_H */
arch/riscv/kernel/cpufeature.c +1 -0
index d959d207a40d..7069e55335d0 100644
@@ -73,6 +73,7 @@ void __init riscv_fill_hwcap(void)
 	isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
 	isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
 	isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
+	isa2hwcap['v'] = isa2hwcap['V'] = COMPAT_HWCAP_ISA_V;
 
 	elf_hwcap = 0;
 
Signature · 1 line
2.31.1
#4 lore raw

RFC PATCH v8 4/21 riscv: Add new csr defines related to vector extension

In reply to Greentime Hu

Follow the riscv vector spec to add new csr numbers.

---
 arch/riscv/include/asm/csr.h | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
arch/riscv/include/asm/csr.h +14 -2
index 87ac65696871..069743102fac 100644
@@ -24,6 +24,12 @@
 #define SR_FS_CLEAN	_AC(0x00004000, UL)
 #define SR_FS_DIRTY	_AC(0x00006000, UL)
 
+#define SR_VS           _AC(0x00000600, UL) /* Vector Status */
+#define SR_VS_OFF       _AC(0x00000000, UL)
+#define SR_VS_INITIAL   _AC(0x00000200, UL)
+#define SR_VS_CLEAN     _AC(0x00000400, UL)
+#define SR_VS_DIRTY     _AC(0x00000600, UL)
+
 #define SR_XS		_AC(0x00018000, UL) /* Extension Status */
 #define SR_XS_OFF	_AC(0x00000000, UL)
 #define SR_XS_INITIAL	_AC(0x00008000, UL)
@@ -31,9 +37,9 @@
 #define SR_XS_DIRTY	_AC(0x00018000, UL)
 
 #ifndef CONFIG_64BIT
-#define SR_SD		_AC(0x80000000, UL) /* FS/XS dirty */
+#define SR_SD		_AC(0x80000000, UL) /* FS/VS/XS dirty */
 #else
-#define SR_SD		_AC(0x8000000000000000, UL) /* FS/XS dirty */
+#define SR_SD		_AC(0x8000000000000000, UL) /* FS/VS/XS dirty */
 #endif
 
 /* SATP flags */
@@ -120,6 +126,12 @@
 #define CSR_MIMPID		0xf13
 #define CSR_MHARTID		0xf14
 
+#define CSR_VSTART		0x8
+#define CSR_VCSR		0xf
+#define CSR_VL			0xc20
+#define CSR_VTYPE		0xc21
+#define CSR_VLENB		0xc22
+
 #ifdef CONFIG_RISCV_M_MODE
 # define CSR_STATUS	CSR_MSTATUS
 # define CSR_IE		CSR_MIE
Signature · 1 line
2.31.1
#5 lore raw

RFC PATCH v8 5/21 riscv: Add vector feature to compile

In reply to Greentime Hu

From: Guo Ren <[email protected]>

This patch adds a new config option which could enable assembler's vector feature.

---
 arch/riscv/Kconfig  | 9 +++++++++
 arch/riscv/Makefile | 1 +
 2 files changed, 10 insertions(+)
arch/riscv/Kconfig +9 -0
index 4f7b70ae7c31..619cfc370ee5 100644
@@ -380,6 +380,15 @@ config FPU
 
 	  If you don't know what to do here, say Y.
 
+config VECTOR
+	bool "VECTOR support"
+	default n
+	help
+	  Say N here if you want to disable all vector related procedure
+	  in the kernel.
+
+	  If you don't know what to do here, say Y.
+
 endmenu
 
 menu "Kernel features"
arch/riscv/Makefile +1 -0
index 428bd3bc202f..1450bdde5288 100644
@@ -57,6 +57,7 @@ riscv-march-aflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
 riscv-march-aflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
 riscv-march-aflags-$(CONFIG_FPU)		:= $(riscv-march-aflags-y)fd
 riscv-march-aflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-aflags-y)c
+riscv-march-aflags-$(CONFIG_VECTOR)		:= $(riscv-march-aflags-y)v
 
 KBUILD_CFLAGS += -march=$(riscv-march-cflags-y)
 KBUILD_AFLAGS += -march=$(riscv-march-aflags-y)
Signature · 1 line
2.31.1
#6 lore raw

RFC PATCH v8 6/21 riscv: Add has_vector/riscv_vsize to save vector features.

In reply to Greentime Hu

This patch is used to detect vector support status of CPU and use riscv_vsize to save the size of all the vector registers. It assumes all harts has the same capabilities in SMP system.

---
 arch/riscv/kernel/cpufeature.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
arch/riscv/kernel/cpufeature.c +12 -0
index 7069e55335d0..7265d947d981 100644
@@ -21,6 +21,10 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 #ifdef CONFIG_FPU
 __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
+#ifdef CONFIG_VECTOR
+bool has_vector __read_mostly;
+unsigned long riscv_vsize __read_mostly;
+#endif
 
 /**
  * riscv_isa_extension_base() - Get base extension word
@@ -149,4 +153,12 @@ void __init riscv_fill_hwcap(void)
 	if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
 		static_branch_enable(&cpu_hwcap_fpu);
 #endif
+
+#ifdef CONFIG_VECTOR
+	if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
+		has_vector = true;
+		/* There are 32 vector registers with vlenb length. */
+		riscv_vsize = csr_read(CSR_VLENB) * 32;
+	}
+#endif
 }
Signature · 1 line
2.31.1
#7 lore raw

RFC PATCH v8 7/21 riscv: Reset vector register

In reply to Greentime Hu

From: Guo Ren <[email protected]>

Reset vector registers at boot-time and disable vector instructions execution for kernel mode.

---
 arch/riscv/kernel/entry.S |  6 ++---
 arch/riscv/kernel/head.S  | 49 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 50 insertions(+), 5 deletions(-)
arch/riscv/kernel/entry.S +3 -3
index 98f502654edd..ad0fa80ada81 100644
@@ -77,10 +77,10 @@ _save_context:
 	 * Disable user-mode memory access as it should only be set in the
 	 * actual user copy routines.
 	 *
-	 * Disable the FPU to detect illegal usage of floating point in kernel
-	 * space.
+	 * Disable the FPU/Vector to detect illegal usage of floating point
+	 * or vector in kernel space.
 	 */
-	li t0, SR_SUM | SR_FS
+	li t0, SR_SUM | SR_FS | SR_VS
 
 	REG_L s0, TASK_TI_USER_SP(tp)
 	csrrc s1, CSR_STATUS, t0
arch/riscv/kernel/head.S +47 -2

63 lines not on this page · raw message

Signature · 1 line
2.31.1
#8 lore raw

RFC PATCH v8 8/21 riscv: Add vector struct and assembler definitions

In reply to Greentime Hu

Add vector state context struct in struct thread and asm-offsets.c definitions.

The vector registers will be saved in datap pointer of __riscv_v_state. It will be dynamically allocated in kernel space. It will be put right after the __riscv_v_state data structure in user space.

---
 arch/riscv/include/asm/processor.h   |  1 +
 arch/riscv/include/uapi/asm/ptrace.h | 11 +++++++++++
 arch/riscv/kernel/asm-offsets.c      |  6 ++++++
 3 files changed, 18 insertions(+)
arch/riscv/include/asm/processor.h +1 -0
index 021ed64ee608..1b037c69d311 100644
@@ -35,6 +35,7 @@ struct thread_struct {
 	unsigned long s[12];	/* s[0]: frame pointer */
 	struct __riscv_d_ext_state fstate;
 	unsigned long bad_cause;
+	struct __riscv_v_state vstate;
 };
 
 #define INIT_THREAD {					\
arch/riscv/include/uapi/asm/ptrace.h +11 -0
index 882547f6bd5c..bd3b8a710246 100644
@@ -77,6 +77,17 @@ union __riscv_fp_state {
 	struct __riscv_q_ext_state q;
 };
 
+struct __riscv_v_state {
+	unsigned long vstart;
+	unsigned long vl;
+	unsigned long vtype;
+	unsigned long vcsr;
+	void *datap;
+#if __riscv_xlen == 32
+	__u32 __padding;
+#endif
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_ASM_RISCV_PTRACE_H */
arch/riscv/kernel/asm-offsets.c +6 -0
index 90f8ce64fa6f..34f43c84723a 100644
@@ -72,6 +72,12 @@ void asm_offsets(void)
 	OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
 #endif
 
+	OFFSET(RISCV_V_STATE_VSTART, __riscv_v_state, vstart);
+	OFFSET(RISCV_V_STATE_VL, __riscv_v_state, vl);
+	OFFSET(RISCV_V_STATE_VTYPE, __riscv_v_state, vtype);
+	OFFSET(RISCV_V_STATE_VCSR, __riscv_v_state, vcsr);
+	OFFSET(RISCV_V_STATE_DATAP, __riscv_v_state, datap);
+
 	DEFINE(PT_SIZE, sizeof(struct pt_regs));
 	OFFSET(PT_EPC, pt_regs, epc);
 	OFFSET(PT_RA, pt_regs, ra);
Signature · 1 line
2.31.1
#9 lore raw

RFC PATCH v8 9/21 riscv: Add task switch support for vector

In reply to Greentime Hu

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]

---
 arch/riscv/include/asm/switch_to.h | 66 +++++++++++++++++++++++
 arch/riscv/kernel/Makefile         |  1 +
 arch/riscv/kernel/process.c        | 38 ++++++++++++++
 arch/riscv/kernel/vector.S         | 84 ++++++++++++++++++++++++++++++
 4 files changed, 189 insertions(+)
 create mode 100644 arch/riscv/kernel/vector.S
arch/riscv/include/asm/switch_to.h +66 -0
index ec83770b3d98..de0573dad78f 100644
@@ -7,10 +7,12 @@
 #define _ASM_RISCV_SWITCH_TO_H
 
 #include <linux/jump_label.h>
+#include <linux/slab.h>
 #include <linux/sched/task_stack.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
 #ifdef CONFIG_FPU
 extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,68 @@ static __always_inline bool has_fpu(void) { return false; }
 #define __switch_to_fpu(__prev, __next) do { } while (0)
 #endif
 
+#ifdef CONFIG_VECTOR
+extern bool has_vector;
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+	regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+			      struct pt_regs *regs)
+{
+	regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+			       struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+		struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+		__vstate_save(vstate, vstate->datap);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void vstate_restore(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) != SR_VS_OFF) {
+		struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+		/* Allocate space for vector registers. */
+		if (!vstate->datap) {
+			vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
+			vstate->size = riscv_vsize;
+		}
+		__vstate_restore(vstate, vstate->datap);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+				   struct task_struct *next)
+{
+	struct pt_regs *regs;
+
+	regs = task_pt_regs(prev);
+	if (unlikely(regs->status & SR_SD))
+		vstate_save(prev, regs);
+	vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+#define has_vector false
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
 extern struct task_struct *__switch_to(struct task_struct *,
 				       struct task_struct *);
 
@@ -77,6 +141,8 @@ do {							\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
 		__switch_to_fpu(__prev, __next);	\
+	if (has_vector)					\
+		__switch_to_vector(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
 obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o
 obj-$(CONFIG_FPU)		+= fpu.o
+obj-$(CONFIG_VECTOR)		+= vector.o
 obj-$(CONFIG_SMP)		+= smpboot.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SMP)		+= cpu_ops.o
arch/riscv/kernel/process.c +38 -0
index 03ac3aa611f5..0b86e9e531c9 100644
@@ -95,6 +95,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
 		 */
 		fstate_restore(current, regs);
 	}
+
+	if (has_vector) {
+		regs->status |= SR_VS_INITIAL;
+		/*
+		 * Restore the initial value to the vector register
+		 * before starting the user program.
+		 */
+		vstate_restore(current, regs);
+	}
+
 	regs->epc = pc;
 	regs->sp = sp;
 }
@@ -110,15 +120,43 @@ void flush_thread(void)
 	fstate_off(current, task_pt_regs(current));
 	memset(&current->thread.fstate, 0, sizeof(current->thread.fstate));
 #endif
+#ifdef CONFIG_VECTOR
+	/* Reset vector state */
+	vstate_off(current, task_pt_regs(current));
+	memset(&current->thread.vstate, 0, sizeof(current->thread.vstate));
+#endif
 }
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	fstate_save(src, task_pt_regs(src));
+	if (has_vector)
+		/* To make sure every dirty vector context is saved. */
+		vstate_save(src, task_pt_regs(src));
 	*dst = *src;
+	if (has_vector) {
+		/* Copy vector context to the forked task from parent. */
+		if ((task_pt_regs(src)->status & SR_VS) != SR_VS_OFF) {
+			dst->thread.vstate.datap = kzalloc(riscv_vsize, GFP_KERNEL);
+			/* Failed to allocate memory. */
+			if (!dst->thread.vstate.datap)
+				return -ENOMEM;
+			/* Copy the src vector context to dst. */
+			memcpy(dst->thread.vstate.datap,
+			       src->thread.vstate.datap, riscv_vsize);
+		}
+	}
+
 	return 0;
 }
 
+void arch_release_task_struct(struct task_struct *tsk)
+{
+	/* Free the vector context of datap. */
+	if (has_vector)
+		kfree(tsk->thread.vstate.datap);
+}
+
 int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
 		struct task_struct *p, unsigned long tls)
 {
arch/riscv/kernel/vector.S new file +84 -0

84 lines not on this page · raw message

Signature · 1 line
2.31.1
#10 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]

Hi Greentime,

[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on v5.14]
[cannot apply to linus/master linux/master next-20210908] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Greentime-Hu/riscv-Add-vector-ISA-support/20210909-014904
base:    7d2a07b769330c34b4deabeed939325c77a7ec2f
config: riscv-randconfig-r042-20210908 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 9c476172b93367d2cb88d7d3f4b1b5b456fa6020)

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/0day-ci/linux/commit/0ff49e5b8a3d84bd26a64f68bb4161680ab463ef
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Greentime-Hu/riscv-Add-vector-ISA-support/20210909-014904 git checkout 0ff49e5b8a3d84bd26a64f68bb4161680ab463ef
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv

If you fix the issue, kindly add following tag as appropriate

All warnings (new ones prefixed by >>):

arch/riscv/kernel/process.c:140:39: error: use of undeclared identifier 'riscv_vsize'

                           dst->thread.vstate.datap = kzalloc(riscv_vsize, GFP_KERNEL);
                                                              ^
   arch/riscv/kernel/process.c:146:37: error: use of undeclared identifier 'riscv_vsize'
                                  src->thread.vstate.datap, riscv_vsize);
                                                            ^
>> arch/riscv/kernel/process.c:153:6: warning: no previous prototype for function 'arch_release_task_struct' [-Wmissing-prototypes]
   void arch_release_task_struct(struct task_struct *tsk)
        ^

arch/riscv/kernel/process.c:153:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void arch_release_task_struct(struct task_struct *tsk)
^
static
1 warning and 2 errors generated.

vim +/arch_release_task_struct +153 arch/riscv/kernel/process.c

152

 > 153	void arch_release_task_struct(struct task_struct *tsk)

154 {
155 /* Free the vector context of datap. */
156 if (has_vector)
157 kfree(tsk->thread.vstate.datap);
158 }
159

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

#11 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

In reply to Greentime Hu
Quoted 139 lines · Greentime Hu

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]

---
  arch/riscv/include/asm/switch_to.h | 66 +++++++++++++++++++++++
  arch/riscv/kernel/Makefile         |  1 +
  arch/riscv/kernel/process.c        | 38 ++++++++++++++
  arch/riscv/kernel/vector.S         | 84 ++++++++++++++++++++++++++++++
  4 files changed, 189 insertions(+)

create mode 100644 arch/riscv/kernel/vector.S

arch/riscv/include/asm/switch_to.h +66 -0
index ec83770b3d98..de0573dad78f 100644
@@ -7,10 +7,12 @@
  #define _ASM_RISCV_SWITCH_TO_H
 
  #include <linux/jump_label.h>
+#include <linux/slab.h>
  #include <linux/sched/task_stack.h>
  #include <asm/processor.h>
  #include <asm/ptrace.h>
  #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
  #ifdef CONFIG_FPU
  extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,68 @@ static __always_inline bool has_fpu(void) { return false; }
  #define __switch_to_fpu(__prev, __next) do { } while (0)
  #endif
 
+#ifdef CONFIG_VECTOR
+extern bool has_vector;
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+	regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+			      struct pt_regs *regs)
+{
+	regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+			       struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+		struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+		__vstate_save(vstate, vstate->datap);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void vstate_restore(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) != SR_VS_OFF) {
+		struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+		/* Allocate space for vector registers. */
+		if (!vstate->datap) {
+			vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
+			vstate->size = riscv_vsize;
+		}
+		__vstate_restore(vstate, vstate->datap);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+				   struct task_struct *next)
+{
+	struct pt_regs *regs;
+
+	regs = task_pt_regs(prev);
+	if (unlikely(regs->status & SR_SD))
+		vstate_save(prev, regs);
+	vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+#define has_vector false
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
  extern struct task_struct *__switch_to(struct task_struct *,
  				       struct task_struct *);
 
@@ -77,6 +141,8 @@ do {							\
  	struct task_struct *__next = (next);		\
  	if (has_fpu())					\
  		__switch_to_fpu(__prev, __next);	\
+	if (has_vector)					\
+		__switch_to_vector(__prev, __next);	\
  	((last) = __switch_to(__prev, __next));		\
  } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
  obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o
  obj-$(CONFIG_FPU)		+= fpu.o
+obj-$(CONFIG_VECTOR)		+= vector.o
  obj-$(CONFIG_SMP)		+= smpboot.o
  obj-$(CONFIG_SMP)		+= smp.o
  obj-$(CONFIG_SMP)		+= cpu_ops.o
arch/riscv/kernel/process.c +0 -0
index 03ac3aa611f5..0b86e9e531c9 100644
@@ -95,6 +95,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
  		 */
  		fstate_restore(current, regs);
  	}

arch/riscv/kernel/process.c void start_thread(struct pt_regs *regs, unsigned long pc, · line 107

Quoted 10 lines
arch/riscv/kernel/process.c +10 -0
+
+	if (has_vector) {
+		regs->status |= SR_VS_INITIAL;
+		/*
+		 * Restore the initial value to the vector register
+		 * before starting the user program.
+		 */
+		vstate_restore(current, regs);
+	}
+

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 138 lines
arch/riscv/kernel/process.c +28 -0
  	regs->epc = pc;
  	regs->sp = sp;
  }
@@ -110,15 +120,43 @@ void flush_thread(void)
  	fstate_off(current, task_pt_regs(current));
  	memset(&current->thread.fstate, 0, sizeof(current->thread.fstate));
  #endif
+#ifdef CONFIG_VECTOR
+	/* Reset vector state */
+	vstate_off(current, task_pt_regs(current));
+	memset(&current->thread.vstate, 0, sizeof(current->thread.vstate));
+#endif
  }
 
  int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
  {
  	fstate_save(src, task_pt_regs(src));
+	if (has_vector)
+		/* To make sure every dirty vector context is saved. */
+		vstate_save(src, task_pt_regs(src));
  	*dst = *src;
+	if (has_vector) {
+		/* Copy vector context to the forked task from parent. */
+		if ((task_pt_regs(src)->status & SR_VS) != SR_VS_OFF) {
+			dst->thread.vstate.datap = kzalloc(riscv_vsize, GFP_KERNEL);
+			/* Failed to allocate memory. */
+			if (!dst->thread.vstate.datap)
+				return -ENOMEM;
+			/* Copy the src vector context to dst. */
+			memcpy(dst->thread.vstate.datap,
+			       src->thread.vstate.datap, riscv_vsize);
+		}
+	}
+
  	return 0;
  }
 
+void arch_release_task_struct(struct task_struct *tsk)
+{
+	/* Free the vector context of datap. */
+	if (has_vector)
+		kfree(tsk->thread.vstate.datap);
+}
+
  int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
  		struct task_struct *p, unsigned long tls)
  {
arch/riscv/kernel/vector.S new file +84 -0
new file mode 100644
index 000000000000..4c880b1c32aa
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2012 Regents of the University of California
+ * Copyright (C) 2017 SiFive
+ * Copyright (C) 2019 Alibaba Group Holding Limited
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm.h>
+#include <asm/csr.h>
+#include <asm/asm-offsets.h>
+
+#define vstatep  a0
+#define datap    a1
+#define x_vstart t0
+#define x_vtype  t1
+#define x_vl     t2
+#define x_vcsr   t3
+#define incr     t4
+#define m_one    t5
+#define status   t6
+
+ENTRY(__vstate_save)
+	li      status, SR_VS
+	csrs    sstatus, status
+
+	csrr    x_vstart, CSR_VSTART
+	csrr    x_vtype, CSR_VTYPE
+	csrr    x_vl, CSR_VL
+	csrr    x_vcsr, CSR_VCSR
+	li      m_one, -1
+	vsetvli incr, m_one, e8, m8
+	vse8.v   v0, (datap)
+	add     datap, datap, incr
+	vse8.v   v8, (datap)
+	add     datap, datap, incr
+	vse8.v   v16, (datap)
+	add     datap, datap, incr
+	vse8.v   v24, (datap)
+
+	REG_S   x_vstart, RISCV_V_STATE_VSTART(vstatep)
+	REG_S   x_vtype, RISCV_V_STATE_VTYPE(vstatep)
+	REG_S   x_vl, RISCV_V_STATE_VL(vstatep)
+	REG_S   x_vcsr, RISCV_V_STATE_VCSR(vstatep)
+
+	csrc	sstatus, status
+	ret
+ENDPROC(__vstate_save)
+
+ENTRY(__vstate_restore)
+	li      status, SR_VS
+	csrs    sstatus, status
+
+	li      m_one, -1
+	vsetvli incr, m_one, e8, m8
+	vle8.v   v0, (datap)
+	add     datap, datap, incr
+	vle8.v   v8, (datap)
+	add     datap, datap, incr
+	vle8.v   v16, (datap)
+	add     datap, datap, incr
+	vle8.v   v24, (datap)
+
+	REG_L   x_vstart, RISCV_V_STATE_VSTART(vstatep)
+	REG_L   x_vtype, RISCV_V_STATE_VTYPE(vstatep)
+	REG_L   x_vl, RISCV_V_STATE_VL(vstatep)
+	REG_L   x_vcsr, RISCV_V_STATE_VCSR(vstatep)
+	vsetvl  x0, x_vl, x_vtype
+	csrw    CSR_VSTART, x_vstart
+	csrw    CSR_VCSR, x_vcsr
+
+	csrc	sstatus, status
+	ret
+ENDPROC(__vstate_restore)
#12 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 147 lines · Greentime Hu
Quoted 145 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]

---
  arch/riscv/include/asm/switch_to.h | 66 +++++++++++++++++++++++
  arch/riscv/kernel/Makefile         |  1 +
  arch/riscv/kernel/process.c        | 38 ++++++++++++++
  arch/riscv/kernel/vector.S         | 84 ++++++++++++++++++++++++++++++
  4 files changed, 189 insertions(+)

create mode 100644 arch/riscv/kernel/vector.S

arch/riscv/include/asm/switch_to.h +66 -0
index ec83770b3d98..de0573dad78f 100644
@@ -7,10 +7,12 @@
  #define _ASM_RISCV_SWITCH_TO_H
 
  #include <linux/jump_label.h>
+#include <linux/slab.h>
  #include <linux/sched/task_stack.h>
  #include <asm/processor.h>
  #include <asm/ptrace.h>
  #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
  #ifdef CONFIG_FPU
  extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,68 @@ static __always_inline bool has_fpu(void) { return false; }
  #define __switch_to_fpu(__prev, __next) do { } while (0)
  #endif
 
+#ifdef CONFIG_VECTOR
+extern bool has_vector;
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+                           struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+                            struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             __vstate_save(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void vstate_restore(struct task_struct *task,
+                               struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) != SR_VS_OFF) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             /* Allocate space for vector registers. */
+             if (!vstate->datap) {
+                     vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
+                     vstate->size = riscv_vsize;
+             }
+             __vstate_restore(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+                                struct task_struct *next)
+{
+     struct pt_regs *regs;
+
+     regs = task_pt_regs(prev);
+     if (unlikely(regs->status & SR_SD))
+             vstate_save(prev, regs);
+     vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+#define has_vector false
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
  extern struct task_struct *__switch_to(struct task_struct *,
                                     struct task_struct *);
 
@@ -77,6 +141,8 @@ do {                                                       \
      struct task_struct *__next = (next);            \
      if (has_fpu())                                  \
              __switch_to_fpu(__prev, __next);        \
+     if (has_vector)                                 \
+             __switch_to_vector(__prev, __next);     \
      ((last) = __switch_to(__prev, __next));         \
  } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
  obj-$(CONFIG_RISCV_M_MODE)  += traps_misaligned.o
  obj-$(CONFIG_FPU)           += fpu.o
+obj-$(CONFIG_VECTOR)         += vector.o
  obj-$(CONFIG_SMP)           += smpboot.o
  obj-$(CONFIG_SMP)           += smp.o
  obj-$(CONFIG_SMP)           += cpu_ops.o
arch/riscv/kernel/process.c +6 -0
index 03ac3aa611f5..0b86e9e531c9 100644
@@ -95,6 +95,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
               */
              fstate_restore(current, regs);
      }
+
+     if (has_vector) {
+             regs->status |= SR_VS_INITIAL;
+             /*
+              * Restore the initial value to the vector register
+              * before starting the user program.
Quoted 9 lines

arch/riscv/kernel/process.c void start_thread(struct pt_regs *regs, unsigned long pc, · line 107

Quoted 4 lines
arch/riscv/kernel/process.c +4 -0
+              */
+             vstate_restore(current, regs);
+     }
+

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Quoted 15 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

#13 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 160 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 147 lines · Greentime Hu
Quoted 145 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]

---
  arch/riscv/include/asm/switch_to.h | 66 +++++++++++++++++++++++
  arch/riscv/kernel/Makefile         |  1 +
  arch/riscv/kernel/process.c        | 38 ++++++++++++++
  arch/riscv/kernel/vector.S         | 84 ++++++++++++++++++++++++++++++
  4 files changed, 189 insertions(+)

create mode 100644 arch/riscv/kernel/vector.S

arch/riscv/include/asm/switch_to.h +66 -0
index ec83770b3d98..de0573dad78f 100644
@@ -7,10 +7,12 @@
  #define _ASM_RISCV_SWITCH_TO_H
 
  #include <linux/jump_label.h>
+#include <linux/slab.h>
  #include <linux/sched/task_stack.h>
  #include <asm/processor.h>
  #include <asm/ptrace.h>
  #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
  #ifdef CONFIG_FPU
  extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,68 @@ static __always_inline bool has_fpu(void) { return false; }
  #define __switch_to_fpu(__prev, __next) do { } while (0)
  #endif
 
+#ifdef CONFIG_VECTOR
+extern bool has_vector;
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+                           struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+                            struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             __vstate_save(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void vstate_restore(struct task_struct *task,
+                               struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) != SR_VS_OFF) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             /* Allocate space for vector registers. */
+             if (!vstate->datap) {
+                     vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
+                     vstate->size = riscv_vsize;
+             }
+             __vstate_restore(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+                                struct task_struct *next)
+{
+     struct pt_regs *regs;
+
+     regs = task_pt_regs(prev);
+     if (unlikely(regs->status & SR_SD))
+             vstate_save(prev, regs);
+     vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+#define has_vector false
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
  extern struct task_struct *__switch_to(struct task_struct *,
                                     struct task_struct *);
 
@@ -77,6 +141,8 @@ do {                                                       \
      struct task_struct *__next = (next);            \
      if (has_fpu())                                  \
              __switch_to_fpu(__prev, __next);        \
+     if (has_vector)                                 \
+             __switch_to_vector(__prev, __next);     \
      ((last) = __switch_to(__prev, __next));         \
  } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
  obj-$(CONFIG_RISCV_M_MODE)  += traps_misaligned.o
  obj-$(CONFIG_FPU)           += fpu.o
+obj-$(CONFIG_VECTOR)         += vector.o
  obj-$(CONFIG_SMP)           += smpboot.o
  obj-$(CONFIG_SMP)           += smp.o
  obj-$(CONFIG_SMP)           += cpu_ops.o
arch/riscv/kernel/process.c +6 -0
index 03ac3aa611f5..0b86e9e531c9 100644
@@ -95,6 +95,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
               */
              fstate_restore(current, regs);
      }
+
+     if (has_vector) {
+             regs->status |= SR_VS_INITIAL;
+             /*
+              * Restore the initial value to the vector register
+              * before starting the user program.
Quoted 9 lines

arch/riscv/kernel/process.c void start_thread(struct pt_regs *regs, unsigned long pc, · line 107

Quoted 4 lines
arch/riscv/kernel/process.c +4 -0
+              */
+             vstate_restore(current, regs);
+     }
+

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 25 lines
Quoted 16 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 11 lines

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

What makes me think that the vector extension should be treated like AMX is that they both (1) have a significant amount of architectural state, and
(2) likely have a significant power and/or area impact on (non-emulated) designs.

For example, I think it is possible, maybe even likely, that vector implementations will have one or more of the following behaviors:

1. A single vector unit shared among two or more harts,

2. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

3. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

4. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

None of the above constraints apply to more ordinary extensions like compressed or the various bit manipulation extensions.

The discussion I linked to has some well reasoned arguments on why substantial extensions should have a mechanism to request using them by user space. The discussion was in the context of Intel AMX, but applies to further x86 extensions, and I think should also apply to similar extensions on RISC-V, like vector here.

#14 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 233 lines · Darius Rad
Quoted 160 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 147 lines · Greentime Hu
Quoted 145 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]

---
  arch/riscv/include/asm/switch_to.h | 66 +++++++++++++++++++++++
  arch/riscv/kernel/Makefile         |  1 +
  arch/riscv/kernel/process.c        | 38 ++++++++++++++
  arch/riscv/kernel/vector.S         | 84 ++++++++++++++++++++++++++++++
  4 files changed, 189 insertions(+)

create mode 100644 arch/riscv/kernel/vector.S

arch/riscv/include/asm/switch_to.h +66 -0
index ec83770b3d98..de0573dad78f 100644
@@ -7,10 +7,12 @@
  #define _ASM_RISCV_SWITCH_TO_H
 
  #include <linux/jump_label.h>
+#include <linux/slab.h>
  #include <linux/sched/task_stack.h>
  #include <asm/processor.h>
  #include <asm/ptrace.h>
  #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
  #ifdef CONFIG_FPU
  extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,68 @@ static __always_inline bool has_fpu(void) { return false; }
  #define __switch_to_fpu(__prev, __next) do { } while (0)
  #endif
 
+#ifdef CONFIG_VECTOR
+extern bool has_vector;
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+                           struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+                            struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             __vstate_save(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void vstate_restore(struct task_struct *task,
+                               struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) != SR_VS_OFF) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             /* Allocate space for vector registers. */
+             if (!vstate->datap) {
+                     vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
+                     vstate->size = riscv_vsize;
+             }
+             __vstate_restore(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+                                struct task_struct *next)
+{
+     struct pt_regs *regs;
+
+     regs = task_pt_regs(prev);
+     if (unlikely(regs->status & SR_SD))
+             vstate_save(prev, regs);
+     vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+#define has_vector false
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
  extern struct task_struct *__switch_to(struct task_struct *,
                                     struct task_struct *);
 
@@ -77,6 +141,8 @@ do {                                                       \
      struct task_struct *__next = (next);            \
      if (has_fpu())                                  \
              __switch_to_fpu(__prev, __next);        \
+     if (has_vector)                                 \
+             __switch_to_vector(__prev, __next);     \
      ((last) = __switch_to(__prev, __next));         \
  } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
  obj-$(CONFIG_RISCV_M_MODE)  += traps_misaligned.o
  obj-$(CONFIG_FPU)           += fpu.o
+obj-$(CONFIG_VECTOR)         += vector.o
  obj-$(CONFIG_SMP)           += smpboot.o
  obj-$(CONFIG_SMP)           += smp.o
  obj-$(CONFIG_SMP)           += cpu_ops.o
arch/riscv/kernel/process.c +6 -0
index 03ac3aa611f5..0b86e9e531c9 100644
@@ -95,6 +95,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
               */
              fstate_restore(current, regs);
      }
+
+     if (has_vector) {
+             regs->status |= SR_VS_INITIAL;
+             /*
+              * Restore the initial value to the vector register
+              * before starting the user program.
Quoted 9 lines

arch/riscv/kernel/process.c void start_thread(struct pt_regs *regs, unsigned long pc, · line 107

Quoted 4 lines
arch/riscv/kernel/process.c +4 -0
+              */
+             vstate_restore(current, regs);
+     }
+

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 25 lines
Quoted 16 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 11 lines

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

What makes me think that the vector extension should be treated like AMX is that they both (1) have a significant amount of architectural state, and
(2) likely have a significant power and/or area impact on (non-emulated) designs.

For example, I think it is possible, maybe even likely, that vector implementations will have one or more of the following behaviors:

1. A single vector unit shared among two or more harts,

2. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

3. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

4. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

Quoted 9 lines

None of the above constraints apply to more ordinary extensions like compressed or the various bit manipulation extensions.

The discussion I linked to has some well reasoned arguments on why substantial extensions should have a mechanism to request using them by user space. The discussion was in the context of Intel AMX, but applies to further x86 extensions, and I think should also apply to similar extensions on RISC-V, like vector here.

There is possible use case where not all cores support vector extension due to size, area and power.
Perhaps can have the mechanism or flow to determine the application/thread require vector extension or it specifically request the desire to use
vector extensions. Then this app/thread run on cpu with vector extension capability only.

Thanks.

Regards
Ley Foon

#15 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Ley Foon Tan <[email protected]> 於 2021年10月1日 週五 上午10:46寫道:

Quoted 244 lines · Darius Rad
Quoted 233 lines · Greentime Hu
Quoted 160 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 147 lines · Greentime Hu
Quoted 145 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]

---
  arch/riscv/include/asm/switch_to.h | 66 +++++++++++++++++++++++
  arch/riscv/kernel/Makefile         |  1 +
  arch/riscv/kernel/process.c        | 38 ++++++++++++++
  arch/riscv/kernel/vector.S         | 84 ++++++++++++++++++++++++++++++
  4 files changed, 189 insertions(+)

create mode 100644 arch/riscv/kernel/vector.S

arch/riscv/include/asm/switch_to.h +66 -0
index ec83770b3d98..de0573dad78f 100644
@@ -7,10 +7,12 @@
  #define _ASM_RISCV_SWITCH_TO_H
 
  #include <linux/jump_label.h>
+#include <linux/slab.h>
  #include <linux/sched/task_stack.h>
  #include <asm/processor.h>
  #include <asm/ptrace.h>
  #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
  #ifdef CONFIG_FPU
  extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,68 @@ static __always_inline bool has_fpu(void) { return false; }
  #define __switch_to_fpu(__prev, __next) do { } while (0)
  #endif
 
+#ifdef CONFIG_VECTOR
+extern bool has_vector;
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+                           struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+                            struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             __vstate_save(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void vstate_restore(struct task_struct *task,
+                               struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) != SR_VS_OFF) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             /* Allocate space for vector registers. */
+             if (!vstate->datap) {
+                     vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
+                     vstate->size = riscv_vsize;
+             }
+             __vstate_restore(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+                                struct task_struct *next)
+{
+     struct pt_regs *regs;
+
+     regs = task_pt_regs(prev);
+     if (unlikely(regs->status & SR_SD))
+             vstate_save(prev, regs);
+     vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+#define has_vector false
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
  extern struct task_struct *__switch_to(struct task_struct *,
                                     struct task_struct *);
 
@@ -77,6 +141,8 @@ do {                                                       \
      struct task_struct *__next = (next);            \
      if (has_fpu())                                  \
              __switch_to_fpu(__prev, __next);        \
+     if (has_vector)                                 \
+             __switch_to_vector(__prev, __next);     \
      ((last) = __switch_to(__prev, __next));         \
  } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
  obj-$(CONFIG_RISCV_M_MODE)  += traps_misaligned.o
  obj-$(CONFIG_FPU)           += fpu.o
+obj-$(CONFIG_VECTOR)         += vector.o
  obj-$(CONFIG_SMP)           += smpboot.o
  obj-$(CONFIG_SMP)           += smp.o
  obj-$(CONFIG_SMP)           += cpu_ops.o
arch/riscv/kernel/process.c +6 -0
index 03ac3aa611f5..0b86e9e531c9 100644
@@ -95,6 +95,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
               */
              fstate_restore(current, regs);
      }
+
+     if (has_vector) {
+             regs->status |= SR_VS_INITIAL;
+             /*
+              * Restore the initial value to the vector register
+              * before starting the user program.
Quoted 9 lines

arch/riscv/kernel/process.c void start_thread(struct pt_regs *regs, unsigned long pc, · line 107

Quoted 4 lines
arch/riscv/kernel/process.c +4 -0
+              */
+             vstate_restore(current, regs);
+     }
+

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 25 lines
Quoted 16 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 11 lines

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

What makes me think that the vector extension should be treated like AMX is that they both (1) have a significant amount of architectural state, and
(2) likely have a significant power and/or area impact on (non-emulated) designs.

For example, I think it is possible, maybe even likely, that vector implementations will have one or more of the following behaviors:

1. A single vector unit shared among two or more harts,

2. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

3. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

4. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

Quoted 9 lines

None of the above constraints apply to more ordinary extensions like compressed or the various bit manipulation extensions.

The discussion I linked to has some well reasoned arguments on why substantial extensions should have a mechanism to request using them by user space. The discussion was in the context of Intel AMX, but applies to further x86 extensions, and I think should also apply to similar extensions on RISC-V, like vector here.

Quoted 8 lines

There is possible use case where not all cores support vector extension due to size, area and power.
Perhaps can have the mechanism or flow to determine the application/thread require vector extension or it specifically request the desire to use
vector extensions. Then this app/thread run on cpu with vector extension capability only.

IIRC, we assume all harts has the same ability in Linux because of SMP assumption.
If we have more information of hw capability and we may use this information for scheduler to switch the correct process to the correct CPU.
Do you have any idea how to implement it in Linux kernel? Maybe we can list in the TODO list.

#16 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 8 lines · Greentime Hu

Ley Foon Tan <[email protected]> 於 2021年10月1日 週五 上午10:46寫道:

Quoted 6 lines · Darius Rad
Quoted 4 lines · Greentime Hu
Quoted 2 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 1 line

[....]

Quoted 97 lines
Quoted 88 lines
Quoted 79 lines
Quoted 8 lines
Quoted 5 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 25 lines
Quoted 16 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 11 lines

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

What makes me think that the vector extension should be treated like AMX is that they both (1) have a significant amount of architectural state, and
(2) likely have a significant power and/or area impact on (non-emulated) designs.

For example, I think it is possible, maybe even likely, that vector implementations will have one or more of the following behaviors:

1. A single vector unit shared among two or more harts,

2. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

3. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

4. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

Quoted 9 lines

None of the above constraints apply to more ordinary extensions like compressed or the various bit manipulation extensions.

The discussion I linked to has some well reasoned arguments on why substantial extensions should have a mechanism to request using them by user space. The discussion was in the context of Intel AMX, but applies to further x86 extensions, and I think should also apply to similar extensions on RISC-V, like vector here.

Quoted 8 lines

There is possible use case where not all cores support vector extension due to size, area and power.
Perhaps can have the mechanism or flow to determine the application/thread require vector extension or it specifically request the desire to use
vector extensions. Then this app/thread run on cpu with vector extension capability only.

Quoted 7 lines

IIRC, we assume all harts has the same ability in Linux because of SMP assumption.
If we have more information of hw capability and we may use this information for scheduler to switch the correct process to the correct CPU.
Do you have any idea how to implement it in Linux kernel? Maybe we can list in the TODO list.

I think we can refer to other arch implementations as reference:

1. ARM64 supports 32-bit thread on asymmetric AArch32 systems. There is a flag in ELF to check, then start the thread on the core that supports 32-bit execution. This patchset is merged to mainline 5.15.
https://lore.kernel.org/linux-arm-kernel/[email protected]/T/

2. Link shared by Darius, on-demand request implementation on Intel AMX
https://lore.kernel.org/lkml/[email protected]/

glibc support optimized library functions with vector, this is enabled by default if compiler is with vector extension enabled? If yes, then most of the app required vector core.

Regards
Ley Foon

#17 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Ley Foon Tan <[email protected]> 於 2021年10月5日 週二 上午10:12寫道:

Quoted 117 lines · Greentime Hu
Quoted 8 lines

Ley Foon Tan <[email protected]> 於 2021年10月1日 週五 上午10:46寫道:

Quoted 6 lines · Darius Rad
Quoted 4 lines · Greentime Hu
Quoted 2 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 1 line

[....]

Quoted 97 lines
Quoted 88 lines
Quoted 79 lines
Quoted 8 lines
Quoted 5 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 25 lines
Quoted 16 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 11 lines

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

What makes me think that the vector extension should be treated like AMX is that they both (1) have a significant amount of architectural state, and
(2) likely have a significant power and/or area impact on (non-emulated) designs.

For example, I think it is possible, maybe even likely, that vector implementations will have one or more of the following behaviors:

1. A single vector unit shared among two or more harts,

2. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

3. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

4. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

Quoted 9 lines

None of the above constraints apply to more ordinary extensions like compressed or the various bit manipulation extensions.

The discussion I linked to has some well reasoned arguments on why substantial extensions should have a mechanism to request using them by user space. The discussion was in the context of Intel AMX, but applies to further x86 extensions, and I think should also apply to similar extensions on RISC-V, like vector here.

Quoted 8 lines

There is possible use case where not all cores support vector extension due to size, area and power.
Perhaps can have the mechanism or flow to determine the application/thread require vector extension or it specifically request the desire to use
vector extensions. Then this app/thread run on cpu with vector extension capability only.

Quoted 7 lines

IIRC, we assume all harts has the same ability in Linux because of SMP assumption.
If we have more information of hw capability and we may use this information for scheduler to switch the correct process to the correct CPU.
Do you have any idea how to implement it in Linux kernel? Maybe we can list in the TODO list.

Quoted 6 lines

I think we can refer to other arch implementations as reference:

1. ARM64 supports 32-bit thread on asymmetric AArch32 systems. There is a flag in ELF to check, then start the thread on the core that supports 32-bit execution. This patchset is merged to mainline 5.15.
https://lore.kernel.org/linux-arm-kernel/[email protected]/T/

Wow! This is useful for AMP.

Quoted 7 lines

2. Link shared by Darius, on-demand request implementation on Intel AMX
https://lore.kernel.org/lkml/[email protected]/

glibc support optimized library functions with vector, this is enabled by default if compiler is with vector extension enabled? If yes, then most of the app required vector core.

As I mentioned earlier, glibc ifunc will solve this issue. The Linux/glibc can run on platform with vector or without vector and glibc will use the information get from Linux kernel and using ifunc to decide whether it should use the vector version or not. Which means even your toolchain has vector glibc support and your Linux kernel told the glibc this platform doesn't support vector then the ifunc mechanism will choose the non-vector version ones.

#18 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 136 lines · Greentime Hu

Ley Foon Tan <[email protected]> 於 2021年10月5日 週二 上午10:12寫道:

Quoted 117 lines · Greentime Hu
Quoted 8 lines

Ley Foon Tan <[email protected]> 於 2021年10月1日 週五 上午10:46寫道:

Quoted 6 lines · Darius Rad
Quoted 4 lines · Greentime Hu
Quoted 2 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 1 line

[....]

Quoted 97 lines
Quoted 88 lines
Quoted 79 lines
Quoted 8 lines
Quoted 5 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 25 lines
Quoted 16 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 11 lines

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

What makes me think that the vector extension should be treated like AMX is that they both (1) have a significant amount of architectural state, and
(2) likely have a significant power and/or area impact on (non-emulated) designs.

For example, I think it is possible, maybe even likely, that vector implementations will have one or more of the following behaviors:

1. A single vector unit shared among two or more harts,

2. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

3. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

4. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

Quoted 9 lines

None of the above constraints apply to more ordinary extensions like compressed or the various bit manipulation extensions.

The discussion I linked to has some well reasoned arguments on why substantial extensions should have a mechanism to request using them by user space. The discussion was in the context of Intel AMX, but applies to further x86 extensions, and I think should also apply to similar extensions on RISC-V, like vector here.

Quoted 8 lines

There is possible use case where not all cores support vector extension due to size, area and power.
Perhaps can have the mechanism or flow to determine the application/thread require vector extension or it specifically request the desire to use
vector extensions. Then this app/thread run on cpu with vector extension capability only.

Quoted 7 lines

IIRC, we assume all harts has the same ability in Linux because of SMP assumption.
If we have more information of hw capability and we may use this information for scheduler to switch the correct process to the correct CPU.
Do you have any idea how to implement it in Linux kernel? Maybe we can list in the TODO list.

Quoted 6 lines

I think we can refer to other arch implementations as reference:

1. ARM64 supports 32-bit thread on asymmetric AArch32 systems. There is a flag in ELF to check, then start the thread on the core that supports 32-bit execution. This patchset is merged to mainline 5.15.
https://lore.kernel.org/linux-arm-kernel/[email protected]/T/

Wow! This is useful for AMP.

Quoted 7 lines

2. Link shared by Darius, on-demand request implementation on Intel AMX
https://lore.kernel.org/lkml/[email protected]/

glibc support optimized library functions with vector, this is enabled by default if compiler is with vector extension enabled? If yes, then most of the app required vector core.

Quoted 7 lines

As I mentioned earlier, glibc ifunc will solve this issue. The Linux/glibc can run on platform with vector or without vector and glibc will use the information get from Linux kernel and using ifunc to decide whether it should use the vector version or not. Which means even your toolchain has vector glibc support and your Linux kernel told the glibc this platform doesn't support vector then the ifunc mechanism will choose the non-vector version ones.

Okay. Then Linux kernel needs to report vector capability as per core feature, if not all SMP cores support vector.

#19 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

In reply to Darius Rad

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 172 lines · Greentime Hu
Quoted 160 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 147 lines · Greentime Hu
Quoted 145 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]

---
  arch/riscv/include/asm/switch_to.h | 66 +++++++++++++++++++++++
  arch/riscv/kernel/Makefile         |  1 +
  arch/riscv/kernel/process.c        | 38 ++++++++++++++
  arch/riscv/kernel/vector.S         | 84 ++++++++++++++++++++++++++++++
  4 files changed, 189 insertions(+)

create mode 100644 arch/riscv/kernel/vector.S

arch/riscv/include/asm/switch_to.h +66 -0
index ec83770b3d98..de0573dad78f 100644
@@ -7,10 +7,12 @@
  #define _ASM_RISCV_SWITCH_TO_H
 
  #include <linux/jump_label.h>
+#include <linux/slab.h>
  #include <linux/sched/task_stack.h>
  #include <asm/processor.h>
  #include <asm/ptrace.h>
  #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
  #ifdef CONFIG_FPU
  extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,68 @@ static __always_inline bool has_fpu(void) { return false; }
  #define __switch_to_fpu(__prev, __next) do { } while (0)
  #endif
 
+#ifdef CONFIG_VECTOR
+extern bool has_vector;
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+                           struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+                            struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             __vstate_save(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void vstate_restore(struct task_struct *task,
+                               struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) != SR_VS_OFF) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             /* Allocate space for vector registers. */
+             if (!vstate->datap) {
+                     vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
+                     vstate->size = riscv_vsize;
+             }
+             __vstate_restore(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+                                struct task_struct *next)
+{
+     struct pt_regs *regs;
+
+     regs = task_pt_regs(prev);
+     if (unlikely(regs->status & SR_SD))
+             vstate_save(prev, regs);
+     vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+#define has_vector false
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
  extern struct task_struct *__switch_to(struct task_struct *,
                                     struct task_struct *);
 
@@ -77,6 +141,8 @@ do {                                                       \
      struct task_struct *__next = (next);            \
      if (has_fpu())                                  \
              __switch_to_fpu(__prev, __next);        \
+     if (has_vector)                                 \
+             __switch_to_vector(__prev, __next);     \
      ((last) = __switch_to(__prev, __next));         \
  } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
  obj-$(CONFIG_RISCV_M_MODE)  += traps_misaligned.o
  obj-$(CONFIG_FPU)           += fpu.o
+obj-$(CONFIG_VECTOR)         += vector.o
  obj-$(CONFIG_SMP)           += smpboot.o
  obj-$(CONFIG_SMP)           += smp.o
  obj-$(CONFIG_SMP)           += cpu_ops.o
arch/riscv/kernel/process.c +6 -0
index 03ac3aa611f5..0b86e9e531c9 100644
@@ -95,6 +95,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
               */
              fstate_restore(current, regs);
      }
+
+     if (has_vector) {
+             regs->status |= SR_VS_INITIAL;
+             /*
+              * Restore the initial value to the vector register
+              * before starting the user program.
Quoted 9 lines

arch/riscv/kernel/process.c void start_thread(struct pt_regs *regs, unsigned long pc, · line 107

Quoted 4 lines
arch/riscv/kernel/process.c +4 -0
+              */
+             vstate_restore(current, regs);
+     }
+

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Quoted 4 lines

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too.
Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen.
Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 57 lines
Quoted 26 lines
Quoted 17 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 11 lines

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

What makes me think that the vector extension should be treated like AMX is that they both (1) have a significant amount of architectural state, and
(2) likely have a significant power and/or area impact on (non-emulated) designs.

For example, I think it is possible, maybe even likely, that vector implementations will have one or more of the following behaviors:

1. A single vector unit shared among two or more harts,

2. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

3. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

4. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

Quoted 8 lines

None of the above constraints apply to more ordinary extensions like compressed or the various bit manipulation extensions.

The discussion I linked to has some well reasoned arguments on why substantial extensions should have a mechanism to request using them by user space. The discussion was in the context of Intel AMX, but applies to further x86 extensions, and I think should also apply to similar extensions on RISC-V, like vector here.

Have you ever checked the SVE/SVE2 of ARM64 implementation in Linux kernel too? IMHO, the vector of RISCV should be closer to the SVE2 of ARM64.

#20 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 250 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 172 lines · Greentime Hu
Quoted 160 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 147 lines · Greentime Hu
Quoted 145 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]

---
  arch/riscv/include/asm/switch_to.h | 66 +++++++++++++++++++++++
  arch/riscv/kernel/Makefile         |  1 +
  arch/riscv/kernel/process.c        | 38 ++++++++++++++
  arch/riscv/kernel/vector.S         | 84 ++++++++++++++++++++++++++++++
  4 files changed, 189 insertions(+)

create mode 100644 arch/riscv/kernel/vector.S

arch/riscv/include/asm/switch_to.h +66 -0
index ec83770b3d98..de0573dad78f 100644
@@ -7,10 +7,12 @@
  #define _ASM_RISCV_SWITCH_TO_H
 
  #include <linux/jump_label.h>
+#include <linux/slab.h>
  #include <linux/sched/task_stack.h>
  #include <asm/processor.h>
  #include <asm/ptrace.h>
  #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
  #ifdef CONFIG_FPU
  extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,68 @@ static __always_inline bool has_fpu(void) { return false; }
  #define __switch_to_fpu(__prev, __next) do { } while (0)
  #endif
 
+#ifdef CONFIG_VECTOR
+extern bool has_vector;
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+                           struct pt_regs *regs)
+{
+     regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+                            struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             __vstate_save(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void vstate_restore(struct task_struct *task,
+                               struct pt_regs *regs)
+{
+     if ((regs->status & SR_VS) != SR_VS_OFF) {
+             struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+             /* Allocate space for vector registers. */
+             if (!vstate->datap) {
+                     vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
+                     vstate->size = riscv_vsize;
+             }
+             __vstate_restore(vstate, vstate->datap);
+             __vstate_clean(regs);
+     }
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+                                struct task_struct *next)
+{
+     struct pt_regs *regs;
+
+     regs = task_pt_regs(prev);
+     if (unlikely(regs->status & SR_SD))
+             vstate_save(prev, regs);
+     vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+#define has_vector false
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
  extern struct task_struct *__switch_to(struct task_struct *,
                                     struct task_struct *);
 
@@ -77,6 +141,8 @@ do {                                                       \
      struct task_struct *__next = (next);            \
      if (has_fpu())                                  \
              __switch_to_fpu(__prev, __next);        \
+     if (has_vector)                                 \
+             __switch_to_vector(__prev, __next);     \
      ((last) = __switch_to(__prev, __next));         \
  } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
  obj-$(CONFIG_RISCV_M_MODE)  += traps_misaligned.o
  obj-$(CONFIG_FPU)           += fpu.o
+obj-$(CONFIG_VECTOR)         += vector.o
  obj-$(CONFIG_SMP)           += smpboot.o
  obj-$(CONFIG_SMP)           += smp.o
  obj-$(CONFIG_SMP)           += cpu_ops.o
arch/riscv/kernel/process.c +6 -0
index 03ac3aa611f5..0b86e9e531c9 100644
@@ -95,6 +95,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
               */
              fstate_restore(current, regs);
      }
+
+     if (has_vector) {
+             regs->status |= SR_VS_INITIAL;
+             /*
+              * Restore the initial value to the vector register
+              * before starting the user program.
Quoted 9 lines

arch/riscv/kernel/process.c void start_thread(struct pt_regs *regs, unsigned long pc, · line 107

Quoted 4 lines
arch/riscv/kernel/process.c +4 -0
+              */
+             vstate_restore(current, regs);
+     }
+

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Hi Darius,

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Quoted 4 lines

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too.
Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen.
Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 60 lines
Quoted 26 lines
Quoted 17 lines

Given the size of the vector state and potential power and performance implications of enabling the vector engine, it seems like this should treated similarly to Intel AMX on x86. The full discussion of that is here:

https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/

The cover letter for recent Intel AMX patches has a summary of the x86 implementation:

https://lore.kernel.org/lkml/[email protected]/

If RISC-V were to adopt a similar approach, I think the significant points are:

Quoted 8 lines

1. A process (or thread) must specifically request the desire to use
vector extensions (perhaps with some new arch_prctl() API),

2. The kernel is free to deny permission, perhaps based on
administrative rules or for other reasons, and

3. If a process attempts to use vector extensions before doing the
above, the process will die due to an illegal instruction.

Quoted 11 lines

Thank you for sharing this, but I am not sure if we should treat vector like AMX on x86. IMHO, compiler might generate code with vector instructions automatically someday, maybe we should treat vector extensions like other extensions.
If user knows the vector extension is supported in this CPU and he would like to use it, it seems we should let user use it directly just like other extensions.
If user don't know it exists or not, user should use the library API transparently and let glibc or other library deal with it. The glibc ifunc feature or multi-lib should be able to choose the correct implementation.

What makes me think that the vector extension should be treated like AMX is that they both (1) have a significant amount of architectural state, and
(2) likely have a significant power and/or area impact on (non-emulated) designs.

For example, I think it is possible, maybe even likely, that vector implementations will have one or more of the following behaviors:

1. A single vector unit shared among two or more harts,

2. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

3. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

4. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

None of the above constraints apply to more ordinary extensions like compressed or the various bit manipulation extensions.

Quoted 8 lines
Quoted 5 lines

The discussion I linked to has some well reasoned arguments on why substantial extensions should have a mechanism to request using them by user space. The discussion was in the context of Intel AMX, but applies to further x86 extensions, and I think should also apply to similar extensions on RISC-V, like vector here.

Have you ever checked the SVE/SVE2 of ARM64 implementation in Linux kernel too? IMHO, the vector of RISCV should be closer to the SVE2 of ARM64.

For SVE on arm64, memory is only allocated and the extension is only enabled when a process is actively using it, which is not what this patch set does. If the memory allocation for state memory fails, it triggers a BUG(); there is no graceful way to report this to the application.

To do something similar for RISC-V, you will need to write an illegal instruction handler to retrieve the faulting instruction and partially decode it enough to determine it is a vector instruction. That seems needlessly complicated, doesn't provide a way to gracefully report an error if memory allocation fails, and doesn't provide any of the other benefits that a defined API to request use of the vector extension would provide.

Did you read the discussion on Intel AMX support that I previously linked to? There are well reasoned arguments why it is beneficial to require that a process request access to substantial extensions, like RISC-V vector.

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv

#21 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

- Paul

#22 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 45 lines · Paul Walmsley

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that get reported to user space (hint: not well)? According to Greentime, RISC-V vector is similar to ARM SVE, which allocates memory for context state on first use and not unconditionally for all processes.

// darius

#23 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 54 lines · Darius Rad
Quoted 45 lines · Paul Walmsley

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Therefore, I think the memcpy() is widely used in most programs.

Quoted 6 lines

get reported to user space (hint: not well)? According to Greentime, RISC-V vector is similar to ARM SVE, which allocates memory for context state on first use and not unconditionally for all processes.

// darius

#24 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 77 lines · Vincent Chen
Quoted 54 lines · Darius Rad
Quoted 45 lines · Paul Walmsley

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Quoted 2 lines

Therefore, I think the memcpy() is widely used in most programs.

You're missing my point. Not every (any?) program spends a majority of the time doing memcpy(), and even if a program did, all of my points are still valid.

Please read the discussion in the thread I referenced and the questions in my prior message.

Quoted 4 lines
Quoted 4 lines

get reported to user space (hint: not well)? According to Greentime, RISC-V vector is similar to ARM SVE, which allocates memory for context state on first use and not unconditionally for all processes.

#25 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Darius Rad <[email protected]> 於 2021年10月22日 週五 下午6:40寫道:

Quoted 82 lines · Vincent Chen
Quoted 77 lines · Darius Rad
Quoted 54 lines · Paul Walmsley
Quoted 45 lines

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Quoted 2 lines

Therefore, I think the memcpy() is widely used in most programs.

Quoted 7 lines

You're missing my point. Not every (any?) program spends a majority of the time doing memcpy(), and even if a program did, all of my points are still valid.

Please read the discussion in the thread I referenced and the questions in my prior message.

Hi Darius,

As I mentioned before, we want to treat vector ISA like a general ISA instead of a specific IP. User program should be able to use it transparently just like FPU.
It seems that the use case you want is asking user to use vector like a specific IP, user program should ask kernel before they use it and that is not what we want to do in this patchset.

#26 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 91 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年10月22日 週五 下午6:40寫道:

Quoted 82 lines · Vincent Chen
Quoted 77 lines · Darius Rad
Quoted 54 lines · Paul Walmsley
Quoted 45 lines

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Quoted 2 lines

Therefore, I think the memcpy() is widely used in most programs.

Quoted 7 lines

You're missing my point. Not every (any?) program spends a majority of the time doing memcpy(), and even if a program did, all of my points are still valid.

Please read the discussion in the thread I referenced and the questions in my prior message.

Quoted 9 lines

Hi Darius,

As I mentioned before, we want to treat vector ISA like a general ISA instead of a specific IP. User program should be able to use it transparently just like FPU.
It seems that the use case you want is asking user to use vector like a specific IP, user program should ask kernel before they use it and that is not what we want to do in this patchset.

Hi Greentime,

Right.

But beyond what I want to do or what you want to do, is what *should* Linux do? I have attempted to provide evidence to support my position. You have not responded to or addressed the majority of my questions, which is concerning to me.

// darius

#27 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Darius Rad <[email protected]> 於 2021年10月26日 週二 上午12:22寫道:

Quoted 103 lines · Greentime Hu
Quoted 91 lines

Darius Rad <[email protected]> 於 2021年10月22日 週五 下午6:40寫道:

Quoted 82 lines · Vincent Chen
Quoted 77 lines · Darius Rad
Quoted 54 lines · Paul Walmsley
Quoted 45 lines

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Quoted 2 lines

Therefore, I think the memcpy() is widely used in most programs.

Quoted 7 lines

You're missing my point. Not every (any?) program spends a majority of the time doing memcpy(), and even if a program did, all of my points are still valid.

Please read the discussion in the thread I referenced and the questions in my prior message.

Quoted 9 lines

Hi Darius,

As I mentioned before, we want to treat vector ISA like a general ISA instead of a specific IP. User program should be able to use it transparently just like FPU.
It seems that the use case you want is asking user to use vector like a specific IP, user program should ask kernel before they use it and that is not what we want to do in this patchset.

Quoted 8 lines

Hi Greentime,

Right.

But beyond what I want to do or what you want to do, is what *should* Linux do? I have attempted to provide evidence to support my position. You have not responded to or addressed the majority of my questions, which is concerning to me.

Hi Darius,

What is your majority questions?

#28 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 108 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年10月26日 週二 上午12:22寫道:

Quoted 107 lines · Greentime Hu
Quoted 91 lines

Darius Rad <[email protected]> 於 2021年10月22日 週五 下午6:40寫道:

Quoted 82 lines · Vincent Chen
Quoted 77 lines · Darius Rad
Quoted 54 lines · Paul Walmsley
Quoted 45 lines

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy
save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Quoted 2 lines

Therefore, I think the memcpy() is widely used in most programs.

Quoted 7 lines

You're missing my point. Not every (any?) program spends a majority of the time doing memcpy(), and even if a program did, all of my points are still valid.

Please read the discussion in the thread I referenced and the questions in my prior message.

Quoted 9 lines

Hi Darius,

As I mentioned before, we want to treat vector ISA like a general ISA instead of a specific IP. User program should be able to use it transparently just like FPU.
It seems that the use case you want is asking user to use vector like a specific IP, user program should ask kernel before they use it and that is not what we want to do in this patchset.

Hi Greentime,

Right.

Quoted 9 lines
Quoted 4 lines

But beyond what I want to do or what you want to do, is what *should* Linux do? I have attempted to provide evidence to support my position. You have not responded to or addressed the majority of my questions, which is concerning to me.

Hi Darius,

What is your majority questions?

1. How will memory allocation failures for context state memory be reported to user space?

2. How will a system administrator (i.e., the user) be able to effectively manage a system where the vector unit, which could have a considerable area and/or power impact to the system, has one or more of the following properties:

a. A single vector unit shared among two or more harts,

b. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

c. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

d. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

3. You contend that the RISC-V V-extension resembles ARM SVE/SVE2, at least more than Intel AMX. I do not agree, but nevertheless, why then does this patchset not behave similar to SVE? On arm64, SVE is only enabled and memory is only allocated on first use, *not* unconditionally for all tasks.

// darius

#29 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Darius Rad <[email protected]> 於 2021年10月27日 週三 下午8:58寫道:

Quoted 115 lines · Greentime Hu
Quoted 113 lines

Darius Rad <[email protected]> 於 2021年10月26日 週二 上午12:22寫道:

Quoted 111 lines · Greentime Hu
Quoted 91 lines

Darius Rad <[email protected]> 於 2021年10月22日 週五 下午6:40寫道:

Quoted 82 lines · Vincent Chen
Quoted 77 lines · Darius Rad
Quoted 54 lines · Paul Walmsley
Quoted 45 lines

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu

This patch adds task switch support for vector. It supports partial lazy
save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate
memory for vector state, for all processes, regardless of whether vector
instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Quoted 2 lines

Therefore, I think the memcpy() is widely used in most programs.

Quoted 7 lines

You're missing my point. Not every (any?) program spends a majority of the time doing memcpy(), and even if a program did, all of my points are still valid.

Please read the discussion in the thread I referenced and the questions in my prior message.

Quoted 9 lines

Hi Darius,

As I mentioned before, we want to treat vector ISA like a general ISA instead of a specific IP. User program should be able to use it transparently just like FPU.
It seems that the use case you want is asking user to use vector like a specific IP, user program should ask kernel before they use it and that is not what we want to do in this patchset.

Hi Greentime,

Right.

But beyond what I want to do or what you want to do, is what *should* Linux do? I have attempted to provide evidence to support my position. You have not responded to or addressed the majority of my questions, which is concerning to me.

Quoted 7 lines
Quoted 4 lines

Hi Darius,

What is your majority questions?

1. How will memory allocation failures for context state memory be reported to user space?

it will return -ENOMEM for some cases or show the warning messages for some cases.
We know it's not perfect, we should enhance that in the future, but let's take an example: 256 bits vector length system. 256 bits * 32 registers /8 = 1KB.

Quoted 4 lines

2. How will a system administrator (i.e., the user) be able to effectively manage a system where the vector unit, which could have a considerable area and/or power impact to the system, has one or more of the following properties:

As I mentioned before,
We would like to let user use vector transparently just like FPU or other extensions.
If user knows that this system supports vector and user uses intrinsic functions or assembly codes or compiler generating vector codes, user can just use it just like FPU.
If user doesn't know that whether this system support vector or not, user can just use the glibc or ifunc in his own libraries to detect vector support dynamically.

Quoted 10 lines

a. A single vector unit shared among two or more harts,

b. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

c. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

d. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

We also don't support this kind of system(a single vector unit shared among 2 or more harts) in this implementation. I'll add more assumptions in the next version patches.
For the frequency or power issues, I'll also not treat them as a special case since we want to treat vector like an normal extension of ISA instead of a specific IP.

Quoted 4 lines

3. You contend that the RISC-V V-extension resembles ARM SVE/SVE2, at least more than Intel AMX. I do not agree, but nevertheless, why then does this patchset not behave similar to SVE? On arm64, SVE is only enabled and memory is only allocated on first use, *not* unconditionally for all tasks.

As we mentioned before, almost every user space program will use glibc ld.so/libc.so and these libraries will use the vector version optimization porting in a system with vector support. That's why we don't let it trigger the first illegal instruction exception because vector registers will be used at very beginning of the program and the illegal instruction exception handling is also heavier because we need to go to M-mode first than S-mode which means we will need to save context and restore context twice in both M-mode and S-mode. Since the vstate will be allocated eventually, why not save these 2 context save/restore overhead in both M-mode and S-mode for handling this illegal instruction exception. And if the system doesn't support vector, glibc won't use the vector porting and the Linux kernel won't allocate vstate for every process too.

#30 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

Quoted 121 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年10月27日 週三 下午8:58寫道:

Quoted 120 lines · Greentime Hu
Quoted 117 lines

Darius Rad <[email protected]> 於 2021年10月26日 週二 上午12:22寫道:

Quoted 103 lines · Greentime Hu
Quoted 91 lines

Darius Rad <[email protected]> 於 2021年10月22日 週五 下午6:40寫道:

Quoted 82 lines · Vincent Chen
Quoted 77 lines · Darius Rad
Quoted 54 lines · Paul Walmsley
Quoted 45 lines

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

On 9/8/21 1:45 PM, Greentime Hu wrote:
This patch adds task switch support for vector. It supports partial lazy
save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 13 lines

So this will unconditionally enable vector instructions, and allocate
memory for vector state, for all processes, regardless of whether vector
instructions are used?

Yes, it will enable vector if has_vector() is true. The reason that we
choose to enable and allocate memory for user space program is because
we also implement some common functions in the glibc such as memcpy
vector version and it is called very often by every process. So that
we assume if the user program is running in a CPU with vector ISA
would like to use vector by default. If we disable it by default and
make it trigger the illegal instruction, that might be a burden since
almost every process will use vector glibc memcpy or something like
that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Quoted 2 lines

Therefore, I think the memcpy() is widely used in most programs.

Quoted 7 lines

You're missing my point. Not every (any?) program spends a majority of the time doing memcpy(), and even if a program did, all of my points are still valid.

Please read the discussion in the thread I referenced and the questions in my prior message.

Quoted 9 lines

Hi Darius,

As I mentioned before, we want to treat vector ISA like a general ISA instead of a specific IP. User program should be able to use it transparently just like FPU.
It seems that the use case you want is asking user to use vector like a specific IP, user program should ask kernel before they use it and that is not what we want to do in this patchset.

Quoted 8 lines

Hi Greentime,

Right.

But beyond what I want to do or what you want to do, is what *should* Linux do? I have attempted to provide evidence to support my position. You have not responded to or addressed the majority of my questions, which is concerning to me.

Hi Darius,

What is your majority questions?

Quoted 8 lines
Quoted 2 lines

1. How will memory allocation failures for context state memory be reported to user space?

it will return -ENOMEM for some cases or show the warning messages for some cases.
We know it's not perfect, we should enhance that in the future, but let's take an example: 256 bits vector length system. 256 bits * 32 registers /8 = 1KB.

When you say "show the warning message", I assume you mean the kernel will log a message, which is not reported to user space. User space will only see a process unexpectedly die.

As you say, that is not great, and could be done better. I would be interested in knowing how you think that could be improved without needing a user space API, or why it will be acceptable to break the user space API later.

Quoted 27 lines
Quoted 5 lines

2. How will a system administrator (i.e., the user) be able to effectively manage a system where the vector unit, which could have a considerable area and/or power impact to the system, has one or more of the following properties:

As I mentioned before,
We would like to let user use vector transparently just like FPU or other extensions.
If user knows that this system supports vector and user uses intrinsic functions or assembly codes or compiler generating vector codes, user can just use it just like FPU.
If user doesn't know that whether this system support vector or not, user can just use the glibc or ifunc in his own libraries to detect vector support dynamically.

Quoted 10 lines

a. A single vector unit shared among two or more harts,

b. Additional power consumption when the vector unit is enabled and idle
versus not being enabled at all,

c. For a system which supports variable operating frequency, a reduction
in the maximum frequency when the vector unit is enabled, and/or

d. The inability to enter low power states and/or delays to low power
states transitions when the vector unit is enabled.

Quoted 6 lines

We also don't support this kind of system(a single vector unit shared among 2 or more harts) in this implementation. I'll add more assumptions in the next version patches.
For the frequency or power issues, I'll also not treat them as a special case since we want to treat vector like an normal extension of ISA instead of a specific IP.

The problem is that it will likely be impossible to support such systems without changing the user space API.

If you add an API along the lines of what I suggested, even if there is not initially support to completely handle such systems, that support could be added in the future without change to user space.

If such an API is not in place now, that support cannot be added without breaking user space.

Quoted 7 lines
Quoted 5 lines

3. You contend that the RISC-V V-extension resembles ARM SVE/SVE2, at least more than Intel AMX. I do not agree, but nevertheless, why then does this patchset not behave similar to SVE? On arm64, SVE is only enabled and memory is only allocated on first use, *not* unconditionally for all tasks.

As we mentioned before, almost every user space program will use glibc

As I mentioned before, I do not agree that every user space program *will* use vector.

glibc is not the only C library used in Linux.

Whether such support as you are alluding to gets accepted to glibc also remains to be seen.

Quoted 4 lines

ld.so/libc.so and these libraries will use the vector version optimization porting in a system with vector support. That's why we don't let it trigger the first illegal instruction exception because vector registers will be used at very beginning of

Quoted 8 lines

the program and the illegal instruction exception handling is also heavier because we need to go to M-mode first than S-mode which means we will need to save context and restore context twice in both M-mode and S-mode. Since the vstate will be allocated eventually, why not save these 2 context save/restore overhead in both M-mode and S-mode for handling this illegal instruction exception. And if the system doesn't support vector, glibc won't use the vector porting and the Linux kernel won't allocate vstate for every process too.

This is not convincing. You are saying that a single illegal instruction exception, for a process that actively desires to use vector instructions, is more heavy weight than an unconditional allocation of up to 256 kiB per process, even for those processes that do not use vector.

#31 lore raw

Re: [RFC PATCH v8 09/21] riscv: Add task switch support for vector

In reply to Darius Rad

Hi Darius,

Am Freitag, 22. Oktober 2021, 12:40:46 CEST schrieb Darius Rad:

Quoted 81 lines · Vincent Chen
Quoted 77 lines · Darius Rad
Quoted 54 lines · Paul Walmsley
Quoted 45 lines

Hello Darius,

Quoted 9 lines · Darius Rad
Quoted 8 lines · Greentime Hu

Darius Rad <[email protected]> 於 2021年9月29日 週三 下午9:28寫道:

Quoted 7 lines · Greentime Hu
Quoted 5 lines

Darius Rad <[email protected]> 於 2021年9月13日 週一 下午8:21寫道:

Quoted 4 lines · Greentime Hu
Quoted 2 lines

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[ ... ]

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 4 lines
Quoted 3 lines

So this will unconditionally enable vector instructions, and allocate memory for vector state, for all processes, regardless of whether vector instructions are used?

Quoted 9 lines

Yes, it will enable vector if has_vector() is true. The reason that we choose to enable and allocate memory for user space program is because we also implement some common functions in the glibc such as memcpy vector version and it is called very often by every process. So that we assume if the user program is running in a CPU with vector ISA would like to use vector by default. If we disable it by default and make it trigger the illegal instruction, that might be a burden since almost every process will use vector glibc memcpy or something like that.

Do you have any evidence to support the assertion that almost every process would use vector operations? One could easily argue that the converse is
true: no existing software uses the vector extension now, so most likely a process will not be using it.

Quoted 9 lines
Quoted 9 lines

Glibc ustreaming is just starting so you didn't see software using the vector extension now and this patchset is testing based on those optimized glibc too. Vincent Chen is working on the glibc vector support upstreaming and we will also upstream the vector version glibc memcpy, memcmp, memchr, memmove, memset, strcmp, strlen. Then we will see platform with vector support can use vector version mem* and str* functions automatically based on ifunc and platform without vector will use the original one automatically. These could be done to select the correct optimized glibc functions by ifunc mechanism.

Quoted 6 lines

In your reply, I noticed that you didn't address Greentime's response here. But this looks like the key issue. If common library functions are vector-accelerated, wouldn't it make sense that almost every process would wind up using vector instructions? And thus there wouldn't be much point to skipping the vector context memory allocation?

Quoted 5 lines

This issue was addressed in the thread regarding Intel AMX I linked to in a previous message. I don't agree that this is the key issue; it is one of a number of issues. What if I don't want to take the potential power/frequency hit for the vector unit for a workload that, at best, uses it for the occasional memcpy? What if the allocation fails, how will that

Hi Darius,
The memcpy function seems not to be occasionally used in the programs because many functions in Glibc use memcpy() to complete the memory copy. I use the following simple case as an example. test.c

void main(void) {
    return;
}

Then, we compile it by "gcc test.c -o a.out" and execute it. In the execution, the memcpy() has been called unexpectedly. It is because many libc initialized functions will be executed before entering the user-defined main function. One of the example is __libc_setup_tls(), which is called by __libc_start_main(). The __libc_setup_tls() will use memcpy() during the process of creating the Dynamic Thread Vector (DTV).

Quoted 2 lines

Therefore, I think the memcpy() is widely used in most programs.

Quoted 6 lines

You're missing my point. Not every (any?) program spends a majority of the time doing memcpy(), and even if a program did, all of my points are still valid.

Please read the discussion in the thread I referenced and the questions in my prior message.

for people reading along at home, do have a different link by chance?

I.e. the link to
https://lore.kernel.org/lkml/CALCETrW2QHa2TLvnUuVxAAheqcbSZ-5_WRXtDSAGcbG8N+gtdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org/
is not a known message-id on lore.kernel.org it seems.

Thanks
Heiko

Quoted 10 lines
Quoted 4 lines
Quoted 4 lines

get reported to user space (hint: not well)? According to Greentime, RISC-V vector is similar to ARM SVE, which allocates memory for context state on first use and not unconditionally for all processes.

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv

#32 lore raw

RFC PATCH v8 10/21 riscv: Add ptrace vector support

In reply to Greentime Hu

This patch adds ptrace support for riscv vector. The vector registers will be saved in datap pointer of __riscv_v_state. This pointer will be set right after the __riscv_v_state data structure then it will be put in ubuf for ptrace system call to get or set. It will check if the datap got from ubuf is set to the correct address or not when the ptrace system call is trying to set the vector registers.

---
 arch/riscv/include/uapi/asm/ptrace.h | 14 ++++++
 arch/riscv/kernel/ptrace.c           | 71 ++++++++++++++++++++++++++++
 include/uapi/linux/elf.h             |  1 +
 3 files changed, 86 insertions(+)
arch/riscv/include/uapi/asm/ptrace.h +14 -0
index bd3b8a710246..c3760395236c 100644
@@ -83,11 +83,25 @@ struct __riscv_v_state {
 	unsigned long vtype;
 	unsigned long vcsr;
 	void *datap;
+	/*
+	 * In signal handler, datap will be set a correct user stack offset
+	 * and vector registers will be copied to the address of datap
+	 * pointer.
+	 *
+	 * In ptrace syscall, datap will be set to zero and the vector
+	 * registers will be copied to the address right after this
+	 * structure.
+	 */
 #if __riscv_xlen == 32
 	__u32 __padding;
 #endif
 };
 
+/*
+ * To define a practical maximum vlenb for ptrace and it may need to be
+ * extended someday.
+ */
+#define RISCV_MAX_VLENB (16384)
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_ASM_RISCV_PTRACE_H */
arch/riscv/kernel/ptrace.c +71 -0

89 lines not on this page · raw message

include/uapi/linux/elf.h +1 -0
index 61bf4774b8f2..60c5b873a8f6 100644
@@ -432,6 +432,7 @@ typedef struct elf64_shdr {
 #define NT_MIPS_DSP	0x800		/* MIPS DSP ASE registers */
 #define NT_MIPS_FP_MODE	0x801		/* MIPS floating-point mode */
 #define NT_MIPS_MSA	0x802		/* MIPS SIMD registers */
+#define NT_RISCV_VECTOR	0x900		/* RISC-V vector registers */
 
 /* Note types with note name "GNU" */
 #define NT_GNU_PROPERTY_TYPE_0	5
Signature · 1 line
2.31.1
#33 lore raw

RFC PATCH v8 11/21 riscv: Add sigcontext save/restore for vector

In reply to Greentime Hu

This patch adds sigcontext save/restore for vector. The vector registers will be saved in datap pointer. The datap pointer will be allocated dynamically when the task needs in kernel space. The datap pointer will be set right after the __riscv_v_state data structure to save all the vector registers in the signal handler stack.

---
 arch/riscv/include/uapi/asm/sigcontext.h |  24 ++++
 arch/riscv/kernel/asm-offsets.c          |   2 +
 arch/riscv/kernel/setup.c                |   4 +
 arch/riscv/kernel/signal.c               | 164 ++++++++++++++++++++++-
 4 files changed, 190 insertions(+), 4 deletions(-)
arch/riscv/include/uapi/asm/sigcontext.h +24 -0
index 84f2dfcfdbce..b8a0fd7d7cfc 100644
@@ -8,6 +8,23 @@
 
 #include <asm/ptrace.h>
 
+/* The Magic number for signal context frame header. */
+#define RVV_MAGIC	0x53465457
+#define END_MAGIC	0x0
+
+/* The size of END signal context header. */
+#define END_HDR_SIZE	0x0
+
+struct __riscv_ctx_hdr {
+	__u32 magic;
+	__u32 size;
+};
+
+struct __sc_riscv_v_state {
+	struct __riscv_ctx_hdr head;
+	struct __riscv_v_state v_state;
+} __attribute__((aligned(16)));
+
 /*
  * Signal context structure
  *
@@ -17,6 +34,13 @@
 struct sigcontext {
 	struct user_regs_struct sc_regs;
 	union __riscv_fp_state sc_fpregs;
+	/*
+	 * 4K + 128 reserved for vector state and future expansion.
+	 * This space is enough to store the vector context whose VLENB
+	 * is less or equal to 128.
+	 * (The size of the vector context is 4144 byte as VLENB is 128)
+	 */
+	__u8 __reserved[4224] __attribute__((__aligned__(16)));
 };
 
 #endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */
arch/riscv/kernel/asm-offsets.c +2 -0
index 34f43c84723a..62a766d54540 100644
@@ -72,6 +72,8 @@ void asm_offsets(void)
 	OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
 #endif
 
+	OFFSET(RISCV_V_STATE_MAGIC, __riscv_ctx_hdr, magic);
+	OFFSET(RISCV_V_STATE_SIZE, __riscv_ctx_hdr, size);
 	OFFSET(RISCV_V_STATE_VSTART, __riscv_v_state, vstart);
 	OFFSET(RISCV_V_STATE_VL, __riscv_v_state, vl);
 	OFFSET(RISCV_V_STATE_VTYPE, __riscv_v_state, vtype);
arch/riscv/kernel/setup.c +4 -0
index 120b2f6f71bc..6f489f7e6246 100644
@@ -260,6 +260,8 @@ static void __init parse_dtb(void)
 #endif
 }
 
+extern void __init init_rt_signal_env(void);
+
 void __init setup_arch(char **cmdline_p)
 {
 	parse_dtb();
@@ -295,6 +297,8 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
 	riscv_fill_hwcap();
+
+	init_rt_signal_env();
 }
 
 static int __init topology_init(void)
arch/riscv/kernel/signal.c +160 -4

227 lines not on this page · raw message

Signature · 1 line
2.31.1
#34 lore raw

Re: [RFC PATCH v8 11/21] riscv: Add sigcontext save/restore for vector

Quoted 17 lines · Greentime Hu

This patch adds sigcontext save/restore for vector. The vector registers will be saved in datap pointer. The datap pointer will be allocated dynamically when the task needs in kernel space. The datap pointer will be set right after the __riscv_v_state data structure to save all the vector registers in the signal handler stack.

---
 arch/riscv/include/uapi/asm/sigcontext.h |  24 ++++
 arch/riscv/kernel/asm-offsets.c          |   2 +
 arch/riscv/kernel/setup.c                |   4 +
 arch/riscv/kernel/signal.c               | 164 ++++++++++++++++++++++-
 4 files changed, 190 insertions(+), 4 deletions(-)

[....]

Quoted 13 lines
arch/riscv/kernel/signal.c +13 -0
+
+static size_t cal_rt_frame_size(void)
+{
+       struct rt_sigframe __user *frame;
+       static size_t frame_size;
+       size_t total_context_size = 0;
+       size_t sc_reserved_size = sizeof(frame->uc.uc_mcontext.__reserved);
+
+       if (frame_size)
+               goto done;
+
+       frame_size = sizeof(*frame);
+

arch/riscv/kernel/signal.c static long save_fp_state(struct pt_regs *regs, · line 233

Quoted 10 lines
arch/riscv/kernel/signal.c +10 -0
+       if (has_vector)
+               total_context_size += rvv_sc_size;
+       /* Preserved a __riscv_ctx_hdr for END signal context header. */
+       total_context_size += sizeof(struct __riscv_ctx_hdr);
+
+       if (total_context_size > sc_reserved_size)
+               frame_size += (total_context_size - sc_reserved_size);
+
+done:
+       return round_up(frame_size, 16);

Hi Greentime,

frame_size is static variable here, so it will preserve the value for the next calling to cal_rt_frame_size().

I think we need update frame_size before return, example:

frame_size = round_up(frame_size, 16);
return frame_size;

Regards
Ley Foon

#35 lore raw

RFC PATCH v8 12/21 riscv: signal: Report signal frame size to userspace via auxv

In reply to Greentime Hu

From: Vincent Chen <[email protected]>

The vector register belongs to the signal context. They need to be stored and restored as entering and leaving the signal handler. According to the V-extension specification, the maximum length of the vector registers can be 2^(XLEN-1). Hence, if userspace refers to the MINSIGSTKSZ to create a sigframe, it may not be enough. To resolve this problem, this patch refers to the commit 94b07c1f8c39c
("arm64: signal: Report signal frame size to userspace via auxv") to enable userspace to know the minimum required sigframe size through the auxiliary vector and use it to allocate enough memory for signal context.

---
 arch/riscv/include/asm/elf.h         | 41 +++++++++++++++++-----------
 arch/riscv/include/asm/processor.h   |  2 ++
 arch/riscv/include/uapi/asm/auxvec.h |  1 +
 arch/riscv/kernel/signal.c           |  8 ++++++
 4 files changed, 36 insertions(+), 16 deletions(-)
arch/riscv/include/asm/elf.h +25 -16
index f4b490cd0e5d..1102052aa593 100644
@@ -58,22 +58,31 @@ extern unsigned long elf_hwcap;
 #define ELF_PLATFORM	(NULL)
 
 #ifdef CONFIG_MMU
-#define ARCH_DLINFO						\
-do {								\
-	NEW_AUX_ENT(AT_SYSINFO_EHDR,				\
-		(elf_addr_t)current->mm->context.vdso);		\
-	NEW_AUX_ENT(AT_L1I_CACHESIZE,				\
-		get_cache_size(1, CACHE_TYPE_INST));		\
-	NEW_AUX_ENT(AT_L1I_CACHEGEOMETRY,			\
-		get_cache_geometry(1, CACHE_TYPE_INST));	\
-	NEW_AUX_ENT(AT_L1D_CACHESIZE,				\
-		get_cache_size(1, CACHE_TYPE_DATA));		\
-	NEW_AUX_ENT(AT_L1D_CACHEGEOMETRY,			\
-		get_cache_geometry(1, CACHE_TYPE_DATA));	\
-	NEW_AUX_ENT(AT_L2_CACHESIZE,				\
-		get_cache_size(2, CACHE_TYPE_UNIFIED));		\
-	NEW_AUX_ENT(AT_L2_CACHEGEOMETRY,			\
-		get_cache_geometry(2, CACHE_TYPE_UNIFIED));	\
+#define ARCH_DLINFO						 \
+do {								 \
+	NEW_AUX_ENT(AT_SYSINFO_EHDR,				 \
+		(elf_addr_t)current->mm->context.vdso);		 \
+	NEW_AUX_ENT(AT_L1I_CACHESIZE,				 \
+		get_cache_size(1, CACHE_TYPE_INST));		 \
+	NEW_AUX_ENT(AT_L1I_CACHEGEOMETRY,			 \
+		get_cache_geometry(1, CACHE_TYPE_INST));	 \
+	NEW_AUX_ENT(AT_L1D_CACHESIZE,				 \
+		get_cache_size(1, CACHE_TYPE_DATA));		 \
+	NEW_AUX_ENT(AT_L1D_CACHEGEOMETRY,			 \
+		get_cache_geometry(1, CACHE_TYPE_DATA));	 \
+	NEW_AUX_ENT(AT_L2_CACHESIZE,				 \
+		get_cache_size(2, CACHE_TYPE_UNIFIED));		 \
+	NEW_AUX_ENT(AT_L2_CACHEGEOMETRY,			 \
+		get_cache_geometry(2, CACHE_TYPE_UNIFIED));	 \
+	/*							 \
+	 * Should always be nonzero unless there's a kernel bug. \
+	 * If we haven't determined a sensible value to give to	 \
+	 * userspace, omit the entry:				 \
+	 */							 \
+	if (likely(signal_minsigstksz))				 \
+		NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz); \
+	else							 \
+		NEW_AUX_ENT(AT_IGNORE, 0);			 \
 } while (0)
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
arch/riscv/include/asm/processor.h +2 -0
index 1b037c69d311..62c75645c606 100644
@@ -7,6 +7,7 @@
 #define _ASM_RISCV_PROCESSOR_H
 
 #include <linux/const.h>
+#include <linux/cache.h>
 
 #include <vdso/processor.h>
 
@@ -74,6 +75,7 @@ int riscv_of_parent_hartid(struct device_node *node);
 extern void riscv_fill_hwcap(void);
 extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 
+extern unsigned long signal_minsigstksz __ro_after_init;
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_RISCV_PROCESSOR_H */
arch/riscv/include/uapi/asm/auxvec.h +1 -0
index 32c73ba1d531..6610d24e6662 100644
@@ -33,5 +33,6 @@
 
 /* entries in ARCH_DLINFO */
 #define AT_VECTOR_SIZE_ARCH	7
+#define AT_MINSIGSTKSZ 51
 
 #endif /* _UAPI_ASM_RISCV_AUXVEC_H */
arch/riscv/kernel/signal.c +8 -0
index 6938cfa16b45..d30a3b588156 100644
@@ -470,8 +470,16 @@ asmlinkage __visible void do_notify_resume(struct pt_regs *regs,
 		tracehook_notify_resume(regs);
 }
 
+unsigned long __ro_after_init signal_minsigstksz;
+
 void init_rt_signal_env(void);
 void __init init_rt_signal_env(void)
 {
 	rvv_sc_size = sizeof(struct __sc_riscv_v_state) + riscv_vsize;
+	/*
+	 * Determine the stack space required for guaranteed signal delivery.
+	 * The signal_minsigstksz will be populated into the AT_MINSIGSTKSZ entry
+	 * in the auxiliary array at process startup.
+	 */
+	signal_minsigstksz = cal_rt_frame_size();
 }
Signature · 1 line
2.31.1
#36 lore raw

RFC PATCH v8 13/21 riscv: Add support for kernel mode vector

In reply to Greentime Hu

Add <asm/vector.h> containing kernel_rvv_begin()/kernel_rvv_end() function declarations and corresponding definitions in kernel_mode_vector.c

These are needed to wrap uses of vector in kernel mode.

---
 arch/riscv/include/asm/vector.h        |  14 ++
 arch/riscv/kernel/Makefile             |   6 +
 arch/riscv/kernel/kernel_mode_vector.c | 184 +++++++++++++++++++++++++
 3 files changed, 204 insertions(+)
 create mode 100644 arch/riscv/include/asm/vector.h
 create mode 100644 arch/riscv/kernel/kernel_mode_vector.c
arch/riscv/include/asm/vector.h new file +14 -0
new file mode 100644
index 000000000000..5d7f14453f68
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 SiFive
+ */
+
+#ifndef __ASM_RISCV_VECTOR_H
+#define __ASM_RISCV_VECTOR_H
+
+#include <linux/types.h>
+
+void kernel_rvv_begin(void);
+void kernel_rvv_end(void);
+
+#endif /* ! __ASM_RISCV_VECTOR_H */
arch/riscv/kernel/Makefile +6 -0
index 344078080839..a2efd3646cd8 100644
@@ -41,6 +41,12 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o
 obj-$(CONFIG_FPU)		+= fpu.o
 obj-$(CONFIG_VECTOR)		+= vector.o
+obj-$(CONFIG_VECTOR)		+= kernel_mode_vector.o
+riscv-march-cflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
+riscv-march-cflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
+riscv-march-cflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-cflags-y)c
+riscv-march-cflags-$(CONFIG_VECTOR)		:= $(riscv-march-cflags-y)v
+CFLAGS_kernel_mode_vector.o	+= -march=$(riscv-march-cflags-y)
 obj-$(CONFIG_SMP)		+= smpboot.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SMP)		+= cpu_ops.o
arch/riscv/kernel/kernel_mode_vector.c new file +184 -0

184 lines not on this page · raw message

Signature · 1 line
2.31.1
#37 lore raw

Re: [RFC PATCH v8 13/21] riscv: Add support for kernel mode vector

arch/riscv/kernel/Makefile obj-$(CONFIG_MMU) += vdso.o vdso/ · line 49

Quoted 6 lines · Greentime Hu
arch/riscv/kernel/Makefile +6 -0
+obj-$(CONFIG_VECTOR)		+= kernel_mode_vector.o
+riscv-march-cflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
+riscv-march-cflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
+riscv-march-cflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-cflags-y)c
+riscv-march-cflags-$(CONFIG_VECTOR)		:= $(riscv-march-cflags-y)v
+CFLAGS_kernel_mode_vector.o	+= -march=$(riscv-march-cflags-y)

Do we need a helper in arch/riscv/Makefile to define the vector flags instead of open coding them where used? Also I think the variable name should include vector in it.

arch/riscv/kernel/kernel_mode_vector.c line 184

Quoted 3 lines
arch/riscv/kernel/kernel_mode_vector.c new file +2 -0
+EXPORT_SYMBOL(kernel_rvv_begin);
 
+EXPORT_SYMBOL(kernel_rvv_end);

This needs to be EXPORT_SYMBOL_GPL just like x86 kernel_fpu_begin/end

#38 lore raw

RFC PATCH v8 14/21 riscv: Use CSR_STATUS to replace sstatus in vector.S

In reply to Greentime Hu

It should use the same logic here in both m-mode and s-mode.

---
 arch/riscv/kernel/vector.S | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/riscv/kernel/vector.S +4 -4
index 4c880b1c32aa..4f0c5a166e4e 100644
@@ -32,7 +32,7 @@
 
 ENTRY(__vstate_save)
 	li      status, SR_VS
-	csrs    sstatus, status
+	csrs    CSR_STATUS, status
 
 	csrr    x_vstart, CSR_VSTART
 	csrr    x_vtype, CSR_VTYPE
@@ -53,13 +53,13 @@ ENTRY(__vstate_save)
 	REG_S   x_vl, RISCV_V_STATE_VL(vstatep)
 	REG_S   x_vcsr, RISCV_V_STATE_VCSR(vstatep)
 
-	csrc	sstatus, status
+	csrc	CSR_STATUS, status
 	ret
 ENDPROC(__vstate_save)
 
 ENTRY(__vstate_restore)
 	li      status, SR_VS
-	csrs    sstatus, status
+	csrs    CSR_STATUS, status
 
 	li      m_one, -1
 	vsetvli incr, m_one, e8, m8
@@ -79,6 +79,6 @@ ENTRY(__vstate_restore)
 	csrw    CSR_VSTART, x_vstart
 	csrw    CSR_VCSR, x_vcsr
 
-	csrc	sstatus, status
+	csrc	CSR_STATUS, status
 	ret
 ENDPROC(__vstate_restore)
Signature · 1 line
2.31.1
#39 lore raw

RFC PATCH v8 15/21 riscv: Add vector extension XOR implementation

In reply to Greentime Hu

This patch adds support for vector optimized XOR it is tested in spike and qemu.

Logs in spike:

[    0.008365] xor: measuring software checksum speed
[    0.048885]    8regs     :  1719.000 MB/sec
[    0.089080]    32regs    :  1717.000 MB/sec
[    0.129275]    rvv       :  7043.000 MB/sec
[    0.129525] xor: using function: rvv (7043.000 MB/sec)

Logs in qemu:

[    0.098943] xor: measuring software checksum speed
[    0.139391]    8regs     :  2911.000 MB/sec
[    0.181079]    32regs    :  2813.000 MB/sec
[    0.224260]    rvv       :    45.000 MB/sec
[    0.225586] xor: using function: 8regs (2911.000 MB/sec)
---
 arch/riscv/include/asm/xor.h | 74 ++++++++++++++++++++++++++++++++
 arch/riscv/lib/Makefile      |  1 +
 arch/riscv/lib/xor.S         | 81 ++++++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 arch/riscv/include/asm/xor.h
 create mode 100644 arch/riscv/lib/xor.S
arch/riscv/include/asm/xor.h new file +74 -0
new file mode 100644
index 000000000000..60ee0224913d
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 SiFive
+ */
+
+#include <linux/hardirq.h>
+#include <asm-generic/xor.h>
+#ifdef CONFIG_VECTOR
+#include <asm/vector.h>
+
+extern void xor_regs_2_(unsigned long bytes, unsigned long *p1,
+			unsigned long *p2);
+extern void xor_regs_3_(unsigned long bytes, unsigned long *p1,
+			unsigned long *p2, unsigned long *p3);
+extern void xor_regs_4_(unsigned long bytes, unsigned long *p1,
+			unsigned long *p2, unsigned long *p3,
+			unsigned long *p4);
+extern void xor_regs_5_(unsigned long bytes, unsigned long *p1,
+			unsigned long *p2, unsigned long *p3, unsigned long *p4,
+			unsigned long *p5);
+
+static void xor_rvv_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	kernel_rvv_begin();
+	xor_regs_2_(bytes, p1, p2);
+	kernel_rvv_end();
+}
+
+static void
+xor_rvv_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	  unsigned long *p3)
+{
+	kernel_rvv_begin();
+	xor_regs_3_(bytes, p1, p2, p3);
+	kernel_rvv_end();
+}
+
+static void
+xor_rvv_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	  unsigned long *p3, unsigned long *p4)
+{
+	kernel_rvv_begin();
+	xor_regs_4_(bytes, p1, p2, p3, p4);
+	kernel_rvv_end();
+}
+
+static void
+xor_rvv_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	  unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	kernel_rvv_begin();
+	xor_regs_5_(bytes, p1, p2, p3, p4, p5);
+	kernel_rvv_end();
+}
+
+static struct xor_block_template xor_block_rvv = {
+	.name = "rvv",
+	.do_2 = xor_rvv_2,
+	.do_3 = xor_rvv_3,
+	.do_4 = xor_rvv_4,
+	.do_5 = xor_rvv_5
+};
+
+extern bool has_vector;
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES           \
+	do {        \
+		xor_speed(&xor_block_8regs);    \
+		xor_speed(&xor_block_32regs);    \
+		if (has_vector) { \
+			xor_speed(&xor_block_rvv);\
+		} \
+	} while (0)
+#endif
arch/riscv/lib/Makefile +1 -0
index 25d5c9664e57..acd87ac86d24 100644
@@ -7,3 +7,4 @@ lib-$(CONFIG_MMU)	+= uaccess.o
 lib-$(CONFIG_64BIT)	+= tishift.o
 
 obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
+lib-$(CONFIG_VECTOR)	+= xor.o
arch/riscv/lib/xor.S new file +81 -0

81 lines not on this page · raw message

Signature · 1 line
2.31.1
#40 lore raw

Re: [RFC PATCH v8 15/21] riscv: Add vector extension XOR implementation

arch/riscv/include/asm/xor.h line 20

Quoted 10 lines · Greentime Hu
arch/riscv/include/asm/xor.h new file +10 -0
+extern void xor_regs_2_(unsigned long bytes, unsigned long *p1,
+			unsigned long *p2);
+extern void xor_regs_3_(unsigned long bytes, unsigned long *p1,
+			unsigned long *p2, unsigned long *p3);
+extern void xor_regs_4_(unsigned long bytes, unsigned long *p1,
+			unsigned long *p2, unsigned long *p3,
+			unsigned long *p4);
+extern void xor_regs_5_(unsigned long bytes, unsigned long *p1,
+			unsigned long *p2, unsigned long *p3, unsigned long *p4,
+			unsigned long *p5);

There is no need for externs on function declarations ever.

arch/riscv/include/asm/xor.h line 27

Quoted 6 lines
arch/riscv/include/asm/xor.h new file +6 -0
+static void xor_rvv_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	kernel_rvv_begin();
+	xor_regs_2_(bytes, p1, p2);
+	kernel_rvv_end();
+}

This looks strange. Why these wrappers?

#41 lore raw

Re: [RFC PATCH v8 15/21] riscv: Add vector extension XOR implementation

Christoph Hellwig <[email protected]> 於 2021年9月9日 週四 下午2:12寫道:

Quoted 6 lines · Greentime Hu
Quoted 4 lines
arch/riscv/include/asm/xor.h new file +4 -0
+extern void xor_regs_2_(unsigned long bytes, unsigned long *p1,
+                     unsigned long *p2);
+extern void xor_regs_3_(unsigned long bytes, unsigned long *p1,
+                     unsigned long *p2, unsigned long *p3);
Quoted 9 lines

arch/riscv/include/asm/xor.h line 20

Quoted 6 lines
arch/riscv/include/asm/xor.h new file +6 -0
+extern void xor_regs_4_(unsigned long bytes, unsigned long *p1,
+                     unsigned long *p2, unsigned long *p3,
+                     unsigned long *p4);
+extern void xor_regs_5_(unsigned long bytes, unsigned long *p1,
+                     unsigned long *p2, unsigned long *p3, unsigned long *p4,
+                     unsigned long *p5);

There is no need for externs on function declarations ever.

Ok, I'll remove it.

Quoted 8 lines

arch/riscv/include/asm/xor.h line 27

Quoted 6 lines
arch/riscv/include/asm/xor.h new file +6 -0
+static void xor_rvv_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+     kernel_rvv_begin();
+     xor_regs_2_(bytes, p1, p2);
+     kernel_rvv_end();
+}

This looks strange. Why these wrappers?

We don't use rvv in kernel space generally. If we want to use it, we need to save all vector registers first.
Just like arm64/x86 implementation in arch/arm64/include/asm/xor.h
arch/x86/include/asm/xor.h

#42 lore raw

Re: [RFC PATCH v8 15/21] riscv: Add vector extension XOR implementation

In reply to Greentime Hu
Quoted 35 lines · Greentime Hu

This patch adds support for vector optimized XOR it is tested in spike and qemu.

Logs in spike:

[    0.008365] xor: measuring software checksum speed
[    0.048885]    8regs     :  1719.000 MB/sec
[    0.089080]    32regs    :  1717.000 MB/sec
[    0.129275]    rvv       :  7043.000 MB/sec
[    0.129525] xor: using function: rvv (7043.000 MB/sec)

Logs in qemu:

[    0.098943] xor: measuring software checksum speed
[    0.139391]    8regs     :  2911.000 MB/sec
[    0.181079]    32regs    :  2813.000 MB/sec
[    0.224260]    rvv       :    45.000 MB/sec
[    0.225586] xor: using function: 8regs (2911.000 MB/sec)
---
 arch/riscv/include/asm/xor.h | 74 ++++++++++++++++++++++++++++++++
 arch/riscv/lib/Makefile      |  1 +
 arch/riscv/lib/xor.S         | 81 ++++++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 arch/riscv/include/asm/xor.h
 create mode 100644 arch/riscv/lib/xor.S
arch/riscv/include/asm/xor.h new file +0 -0
new file mode 100644
index 000000000000..60ee0224913d
@@ -0,0 +1,74 @@

[...]

arch/riscv/include/asm/xor.h line 74

Quoted 13 lines
arch/riscv/include/asm/xor.h new file +11 -0
+extern bool has_vector;
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES           \
+       do {        \
+               xor_speed(&xor_block_8regs);    \
+               xor_speed(&xor_block_32regs);    \
+               if (has_vector) { \
+                       xor_speed(&xor_block_rvv);\
+               } \
+       } while (0)
+#endif

bool has_vector is changed to has_vector() function now, should this change as well?

Regards
Ley Foon

#43 lore raw

Re: [RFC PATCH v8 15/21] riscv: Add vector extension XOR implementation

Ley Foon Tan <[email protected]> 於 2021年9月14日 週二 下午4:30寫道:

Quoted 42 lines · Greentime Hu
Quoted 35 lines

This patch adds support for vector optimized XOR it is tested in spike and qemu.

Logs in spike:

[    0.008365] xor: measuring software checksum speed
[    0.048885]    8regs     :  1719.000 MB/sec
[    0.089080]    32regs    :  1717.000 MB/sec
[    0.129275]    rvv       :  7043.000 MB/sec
[    0.129525] xor: using function: rvv (7043.000 MB/sec)

Logs in qemu:

[    0.098943] xor: measuring software checksum speed
[    0.139391]    8regs     :  2911.000 MB/sec
[    0.181079]    32regs    :  2813.000 MB/sec
[    0.224260]    rvv       :    45.000 MB/sec
[    0.225586] xor: using function: 8regs (2911.000 MB/sec)
---
 arch/riscv/include/asm/xor.h | 74 ++++++++++++++++++++++++++++++++
 arch/riscv/lib/Makefile      |  1 +
 arch/riscv/lib/xor.S         | 81 ++++++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 arch/riscv/include/asm/xor.h
 create mode 100644 arch/riscv/lib/xor.S
arch/riscv/include/asm/xor.h new file +0 -0
new file mode 100644
index 000000000000..60ee0224913d
@@ -0,0 +1,74 @@

[...]

Quoted 1 line
Quoted 14 lines

arch/riscv/include/asm/xor.h line 74

Quoted 12 lines
arch/riscv/include/asm/xor.h new file +11 -0
+extern bool has_vector;
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES           \
+       do {        \
+               xor_speed(&xor_block_8regs);    \
+               xor_speed(&xor_block_32regs);    \
+               if (has_vector) { \
+                       xor_speed(&xor_block_rvv);\
+               } \
+       } while (0)
+#endif

bool has_vector is changed to has_vector() function now, should this change as well?

That's right. Thank you, LeyFoon.
I'll merge the patch to fix the has_vector() issue in next version patchset.

#44 lore raw

RFC PATCH v8 16/21 riscv: Initialize vector registers with proper vsetvli then it can work normally

In reply to Greentime Hu

It may cause an illegal instruction exception if it doesn't use vsetvli before vmv.v.i v0, 0.

---
 arch/riscv/kernel/head.S | 1 +
 1 file changed, 1 insertion(+)
arch/riscv/kernel/head.S +1 -0
index cf331f138142..42eb3203fa77 100644
@@ -442,6 +442,7 @@ ENTRY(reset_regs)
 
 	li	t1, SR_VS
 	csrs	CSR_STATUS, t1
+	vsetvli t1, x0, e8, m1
 	vmv.v.i v0, 0
 	vmv.v.i v1, 0
 	vmv.v.i v2, 0
Signature · 1 line
2.31.1
#45 lore raw

RFC PATCH v8 17/21 riscv: Optimize vector registers initialization

In reply to Greentime Hu

This patch optimizes the initialization or invalidation of vector registers. It can reduce the code sizes of vector_flush_cpu_state() and reset_regs().

---
 arch/riscv/kernel/head.S               | 30 +-----------------------
 arch/riscv/kernel/kernel_mode_vector.c | 32 ++------------------------
 2 files changed, 3 insertions(+), 59 deletions(-)
arch/riscv/kernel/head.S +1 -29
index 42eb3203fa77..8362d7458c6c 100644
@@ -442,39 +442,11 @@ ENTRY(reset_regs)
 
 	li	t1, SR_VS
 	csrs	CSR_STATUS, t1
-	vsetvli t1, x0, e8, m1
+	vsetvli t1, x0, e8, m8
 	vmv.v.i v0, 0
-	vmv.v.i v1, 0
-	vmv.v.i v2, 0
-	vmv.v.i v3, 0
-	vmv.v.i v4, 0
-	vmv.v.i v5, 0
-	vmv.v.i v6, 0
-	vmv.v.i v7, 0
 	vmv.v.i v8, 0
-	vmv.v.i v9, 0
-	vmv.v.i v10, 0
-	vmv.v.i v11, 0
-	vmv.v.i v12, 0
-	vmv.v.i v13, 0
-	vmv.v.i v14, 0
-	vmv.v.i v15, 0
 	vmv.v.i v16, 0
-	vmv.v.i v17, 0
-	vmv.v.i v18, 0
-	vmv.v.i v19, 0
-	vmv.v.i v20, 0
-	vmv.v.i v21, 0
-	vmv.v.i v22, 0
-	vmv.v.i v23, 0
 	vmv.v.i v24, 0
-	vmv.v.i v25, 0
-	vmv.v.i v26, 0
-	vmv.v.i v27, 0
-	vmv.v.i v28, 0
-	vmv.v.i v29, 0
-	vmv.v.i v30, 0
-	vmv.v.i v31, 0
 	/* note that the caller must clear SR_VS */
 #endif /* CONFIG_VECTOR */
 
arch/riscv/kernel/kernel_mode_vector.c +2 -30
index 108cfafe7496..b84618630edf 100644
@@ -86,39 +86,11 @@ static void vector_flush_cpu_state(void)
 	long tmp;
 
 	__asm__ __volatile__ (
-		"vsetvli %0, x0, e8, m1\n"
+		"vsetvli %0, x0, e8, m8\n"
 		"vmv.v.i v0, 0\n"
-		"vmv.v.i v1, 0\n"
-		"vmv.v.i v2, 0\n"
-		"vmv.v.i v3, 0\n"
-		"vmv.v.i v4, 0\n"
-		"vmv.v.i v5, 0\n"
-		"vmv.v.i v6, 0\n"
-		"vmv.v.i v7, 0\n"
 		"vmv.v.i v8, 0\n"
-		"vmv.v.i v9, 0\n"
-		"vmv.v.i v10, 0\n"
-		"vmv.v.i v11, 0\n"
-		"vmv.v.i v12, 0\n"
-		"vmv.v.i v13, 0\n"
-		"vmv.v.i v14, 0\n"
-		"vmv.v.i v15, 0\n"
 		"vmv.v.i v16, 0\n"
-		"vmv.v.i v17, 0\n"
-		"vmv.v.i v18, 0\n"
-		"vmv.v.i v19, 0\n"
-		"vmv.v.i v20, 0\n"
-		"vmv.v.i v21, 0\n"
-		"vmv.v.i v22, 0\n"
-		"vmv.v.i v23, 0\n"
-		"vmv.v.i v24, 0\n"
-		"vmv.v.i v25, 0\n"
-		"vmv.v.i v26, 0\n"
-		"vmv.v.i v27, 0\n"
-		"vmv.v.i v28, 0\n"
-		"vmv.v.i v29, 0\n"
-		"vmv.v.i v30, 0\n"
-		"vmv.v.i v31, 0\n":"=r"(tmp)::);
+		"vmv.v.i v24, 0\n":"=r"(tmp)::);
 }
 
 /*
Signature · 1 line
2.31.1
#46 lore raw

RFC PATCH v8 18/21 riscv: Fix an illegal instruction exception when accessing vlenb without enable vector first

In reply to Greentime Hu

It triggered an illegal instruction exception when accessing vlenb CSR without enable vector first. To fix this issue, we should enable vector before using it and disable vector after using it.

---
 arch/riscv/include/asm/vector.h        | 2 ++
 arch/riscv/kernel/cpufeature.c         | 3 +++
 arch/riscv/kernel/kernel_mode_vector.c | 6 ++++--
 3 files changed, 9 insertions(+), 2 deletions(-)
arch/riscv/include/asm/vector.h +2 -0
index 5d7f14453f68..ca063c8f47f2 100644
@@ -8,6 +8,8 @@
 
 #include <linux/types.h>
 
+void rvv_enable(void);
+void rvv_disable(void);
 void kernel_rvv_begin(void);
 void kernel_rvv_end(void);
 
arch/riscv/kernel/cpufeature.c +3 -0
index 7265d947d981..af984f875f60 100644
@@ -22,6 +22,7 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
 #ifdef CONFIG_VECTOR
+#include <asm/vector.h>
 bool has_vector __read_mostly;
 unsigned long riscv_vsize __read_mostly;
 #endif
@@ -158,7 +159,9 @@ void __init riscv_fill_hwcap(void)
 	if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
 		has_vector = true;
 		/* There are 32 vector registers with vlenb length. */
+		rvv_enable();
 		riscv_vsize = csr_read(CSR_VLENB) * 32;
+		rvv_disable();
 	}
 #endif
 }
arch/riscv/kernel/kernel_mode_vector.c +4 -2
index b84618630edf..0d990bd8b8dd 100644
@@ -71,15 +71,17 @@ static void put_cpu_vector_context(void)
 	preempt_enable();
 }
 
-static void rvv_enable(void)
+void rvv_enable(void)
 {
 	csr_set(CSR_STATUS, SR_VS);
 }
+EXPORT_SYMBOL(rvv_enable);
 
-static void rvv_disable(void)
+void rvv_disable(void)
 {
 	csr_clear(CSR_STATUS, SR_VS);
 }
+EXPORT_SYMBOL(rvv_disable);
 
 static void vector_flush_cpu_state(void)
 {
Signature · 1 line
2.31.1
#47 lore raw

RFC PATCH v8 19/21 riscv: Allocate space for vector registers in start_thread()

In reply to Greentime Hu

It allocates memory space for vector registers in start_thread() instead of allocating in vstate_restore() in this patch. We can allocate memory here so that it will be more readable.

---
 arch/riscv/include/asm/switch_to.h |  7 +------
 arch/riscv/kernel/process.c        | 15 +++++++++++++--
 2 files changed, 14 insertions(+), 8 deletions(-)
arch/riscv/include/asm/switch_to.h +1 -6
index de0573dad78f..b48c9c974564 100644
@@ -103,12 +103,6 @@ static inline void vstate_restore(struct task_struct *task,
 {
 	if ((regs->status & SR_VS) != SR_VS_OFF) {
 		struct __riscv_v_state *vstate = &(task->thread.vstate);
-
-		/* Allocate space for vector registers. */
-		if (!vstate->datap) {
-			vstate->datap = kzalloc(riscv_vsize, GFP_ATOMIC);
-			vstate->size = riscv_vsize;
-		}
 		__vstate_restore(vstate, vstate->datap);
 		__vstate_clean(regs);
 	}
@@ -127,6 +121,7 @@ static inline void __switch_to_vector(struct task_struct *prev,
 
 #else
 #define has_vector false
+#define riscv_vsize (0)
 #define vstate_save(task, regs) do { } while (0)
 #define vstate_restore(task, regs) do { } while (0)
 #define __switch_to_vector(__prev, __next) do { } while (0)
arch/riscv/kernel/process.c +13 -2
index 0b86e9e531c9..05ff5f934e7e 100644
@@ -97,7 +97,16 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
 	}
 
 	if (has_vector) {
+		struct __riscv_v_state *vstate = &(current->thread.vstate);
+
+		/* Enable vector and allocate memory for vector registers. */
+		if (!vstate->datap) {
+			vstate->datap = kzalloc(riscv_vsize, GFP_KERNEL);
+			if (WARN_ON(!vstate->datap))
+				return;
+		}
 		regs->status |= SR_VS_INITIAL;
+
 		/*
 		 * Restore the initial value to the vector register
 		 * before starting the user program.
@@ -121,9 +130,11 @@ void flush_thread(void)
 	memset(&current->thread.fstate, 0, sizeof(current->thread.fstate));
 #endif
 #ifdef CONFIG_VECTOR
-	/* Reset vector state */
+	/* Reset vector state and keep datap pointer. */
 	vstate_off(current, task_pt_regs(current));
-	memset(&current->thread.vstate, 0, sizeof(current->thread.vstate));
+	memset(&current->thread.vstate, 0, RISCV_V_STATE_DATAP);
+	if (current->thread.vstate.datap)
+		memset(current->thread.vstate.datap, 0, riscv_vsize);
 #endif
 }
 
Signature · 1 line
2.31.1
#48 lore raw

RFC PATCH v8 20/21 riscv: Optimize task switch codes of vector

In reply to Greentime Hu

This patch replacees 2 instructions with 1 instruction to do the same thing . rs1=x0 with rd != x0 is a special form of the instruction that sets vl to MAXVL.

---
 arch/riscv/kernel/vector.S | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
arch/riscv/kernel/vector.S +3 -6
index 4f0c5a166e4e..f7223c81b11a 100644
@@ -27,8 +27,7 @@
 #define x_vl     t2
 #define x_vcsr   t3
 #define incr     t4
-#define m_one    t5
-#define status   t6
+#define status   t5
 
 ENTRY(__vstate_save)
 	li      status, SR_VS
@@ -38,8 +37,7 @@ ENTRY(__vstate_save)
 	csrr    x_vtype, CSR_VTYPE
 	csrr    x_vl, CSR_VL
 	csrr    x_vcsr, CSR_VCSR
-	li      m_one, -1
-	vsetvli incr, m_one, e8, m8
+	vsetvli incr, x0, e8, m8
 	vse8.v   v0, (datap)
 	add     datap, datap, incr
 	vse8.v   v8, (datap)
@@ -61,8 +59,7 @@ ENTRY(__vstate_restore)
 	li      status, SR_VS
 	csrs    CSR_STATUS, status
 
-	li      m_one, -1
-	vsetvli incr, m_one, e8, m8
+	vsetvli incr, x0, e8, m8
 	vle8.v   v0, (datap)
 	add     datap, datap, incr
 	vle8.v   v8, (datap)
Signature · 1 line
2.31.1
#49 lore raw

Re: [RFC PATCH v8 20/21] riscv: Optimize task switch codes of vector

Quoted 3 lines · On Thu, 9 Sep 2021 01:45:32 +0800 Greentime Hu <[email protected]> wrote:

This patch replacees 2 instructions with 1 instruction to do the same thing . rs1=x0 with rd != x0 is a special form of the instruction that sets vl to MAXVL.

Similarly, the vector.S is newly introduced in this patch set, so could this optimization be folded into the __vstate_save and __vstate_restore introduction patch? Or it's better to keep this optimizaion in commit log?

Quoted 43 lines
---
 arch/riscv/kernel/vector.S | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
arch/riscv/kernel/vector.S +3 -6
index 4f0c5a166e4e..f7223c81b11a 100644
@@ -27,8 +27,7 @@
 #define x_vl     t2
 #define x_vcsr   t3
 #define incr     t4
-#define m_one    t5
-#define status   t6
+#define status   t5
 
 ENTRY(__vstate_save)
 	li      status, SR_VS
@@ -38,8 +37,7 @@ ENTRY(__vstate_save)
 	csrr    x_vtype, CSR_VTYPE
 	csrr    x_vl, CSR_VL
 	csrr    x_vcsr, CSR_VCSR
-	li      m_one, -1
-	vsetvli incr, m_one, e8, m8
+	vsetvli incr, x0, e8, m8
 	vse8.v   v0, (datap)
 	add     datap, datap, incr
 	vse8.v   v8, (datap)
@@ -61,8 +59,7 @@ ENTRY(__vstate_restore)
 	li      status, SR_VS
 	csrs    CSR_STATUS, status
 
-	li      m_one, -1
-	vsetvli incr, m_one, e8, m8
+	vsetvli incr, x0, e8, m8
 	vle8.v   v0, (datap)
 	add     datap, datap, incr
 	vle8.v   v8, (datap)
#50 lore raw

Re: [RFC PATCH v8 20/21] riscv: Optimize task switch codes of vector

Jisheng Zhang <[email protected]> 於 2021年9月15日 週三 下午10:36寫道:

Quoted 4 lines

On Thu, 9 Sep 2021 01:45:32 +0800
Greentime Hu <[email protected]> wrote:

Quoted 8 lines
Quoted 3 lines

This patch replacees 2 instructions with 1 instruction to do the same thing . rs1=x0 with rd != x0 is a special form of the instruction that sets vl to MAXVL.

Similarly, the vector.S is newly introduced in this patch set, so could this optimization be folded into the __vstate_save and __vstate_restore introduction patch? Or it's better to keep this optimizaion in commit log?

Yeah, I wanted to keep the optimization commit log before, but it's ok if you think merge code is easier to read.
I'll merge this patch in the next version.

Quoted 45 lines
Quoted 43 lines
---
 arch/riscv/kernel/vector.S | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
arch/riscv/kernel/vector.S +3 -6
index 4f0c5a166e4e..f7223c81b11a 100644
@@ -27,8 +27,7 @@
 #define x_vl     t2
 #define x_vcsr   t3
 #define incr     t4
-#define m_one    t5
-#define status   t6
+#define status   t5
 
 ENTRY(__vstate_save)
      li      status, SR_VS
@@ -38,8 +37,7 @@ ENTRY(__vstate_save)
      csrr    x_vtype, CSR_VTYPE
      csrr    x_vl, CSR_VL
      csrr    x_vcsr, CSR_VCSR
-     li      m_one, -1
-     vsetvli incr, m_one, e8, m8
+     vsetvli incr, x0, e8, m8
      vse8.v   v0, (datap)
      add     datap, datap, incr
      vse8.v   v8, (datap)
@@ -61,8 +59,7 @@ ENTRY(__vstate_restore)
      li      status, SR_VS
      csrs    CSR_STATUS, status
 
-     li      m_one, -1
-     vsetvli incr, m_one, e8, m8
+     vsetvli incr, x0, e8, m8
      vle8.v   v0, (datap)
      add     datap, datap, incr
      vle8.v   v8, (datap)
#51 lore raw

RFC PATCH v8 21/21 riscv: Turn has_vector into a static key if VECTOR=y

In reply to Greentime Hu

Just like fpu, we can use static key for has_vector.
The has_vector check sits at hot code path: switch_to(). Currently, has_vector is a bool variable if VECTOR=y, switch_to() checks it each time, we can optimize out this check by turning the has_vector into a static key.

---
 arch/riscv/include/asm/switch_to.h     | 10 +++++++---
 arch/riscv/kernel/cpufeature.c         |  4 ++--
 arch/riscv/kernel/kernel_mode_vector.c |  4 ++--
 arch/riscv/kernel/process.c            |  8 ++++----
 arch/riscv/kernel/signal.c             |  6 +++---
 5 files changed, 18 insertions(+), 14 deletions(-)
arch/riscv/include/asm/switch_to.h +7 -3
index b48c9c974564..576204217e0f 100644
@@ -71,7 +71,11 @@ static __always_inline bool has_fpu(void) { return false; }
 #endif
 
 #ifdef CONFIG_VECTOR
-extern bool has_vector;
+extern struct static_key_false cpu_hwcap_vector;
+static __always_inline bool has_vector(void)
+{
+	return static_branch_likely(&cpu_hwcap_vector);
+}
 extern unsigned long riscv_vsize;
 extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
 extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
@@ -120,7 +124,7 @@ static inline void __switch_to_vector(struct task_struct *prev,
 }
 
 #else
-#define has_vector false
+static __always_inline bool has_vector(void) { return false; }
 #define riscv_vsize (0)
 #define vstate_save(task, regs) do { } while (0)
 #define vstate_restore(task, regs) do { } while (0)
@@ -136,7 +140,7 @@ do {							\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
 		__switch_to_fpu(__prev, __next);	\
-	if (has_vector)					\
+	if (has_vector())					\
 		__switch_to_vector(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
arch/riscv/kernel/cpufeature.c +2 -2
index af984f875f60..0139ec20adce 100644
@@ -23,7 +23,7 @@ __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
 #ifdef CONFIG_VECTOR
 #include <asm/vector.h>
-bool has_vector __read_mostly;
+__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_vector);
 unsigned long riscv_vsize __read_mostly;
 #endif
 
@@ -157,7 +157,7 @@ void __init riscv_fill_hwcap(void)
 
 #ifdef CONFIG_VECTOR
 	if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
-		has_vector = true;
+		static_branch_enable(&cpu_hwcap_vector);
 		/* There are 32 vector registers with vlenb length. */
 		rvv_enable();
 		riscv_vsize = csr_read(CSR_VLENB) * 32;
arch/riscv/kernel/kernel_mode_vector.c +2 -2
index 0d990bd8b8dd..0d08954c30af 100644
@@ -110,7 +110,7 @@ static void vector_flush_cpu_state(void)
  */
 void kernel_rvv_begin(void)
 {
-	if (WARN_ON(!has_vector))
+	if (WARN_ON(!has_vector()))
 		return;
 
 	WARN_ON(!may_use_vector());
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(kernel_rvv_begin);
  */
 void kernel_rvv_end(void)
 {
-	if (WARN_ON(!has_vector))
+	if (WARN_ON(!has_vector()))
 		return;
 
 	/* Invalidate vector regs */
arch/riscv/kernel/process.c +4 -4
index 05ff5f934e7e..62540815ba1c 100644
@@ -96,7 +96,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
 		fstate_restore(current, regs);
 	}
 
-	if (has_vector) {
+	if (has_vector()) {
 		struct __riscv_v_state *vstate = &(current->thread.vstate);
 
 		/* Enable vector and allocate memory for vector registers. */
@@ -141,11 +141,11 @@ void flush_thread(void)
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	fstate_save(src, task_pt_regs(src));
-	if (has_vector)
+	if (has_vector())
 		/* To make sure every dirty vector context is saved. */
 		vstate_save(src, task_pt_regs(src));
 	*dst = *src;
-	if (has_vector) {
+	if (has_vector()) {
 		/* Copy vector context to the forked task from parent. */
 		if ((task_pt_regs(src)->status & SR_VS) != SR_VS_OFF) {
 			dst->thread.vstate.datap = kzalloc(riscv_vsize, GFP_KERNEL);
@@ -164,7 +164,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 void arch_release_task_struct(struct task_struct *tsk)
 {
 	/* Free the vector context of datap. */
-	if (has_vector)
+	if (has_vector())
 		kfree(tsk->thread.vstate.datap);
 }
 
arch/riscv/kernel/signal.c +3 -3
index d30a3b588156..6a19b4b7b206 100644
@@ -192,7 +192,7 @@ static long restore_sigcontext(struct pt_regs *regs,
 				goto invalid;
 			goto done;
 		case RVV_MAGIC:
-			if (!has_vector)
+			if (!has_vector())
 				goto invalid;
 			if (size != rvv_sc_size)
 				goto invalid;
@@ -221,7 +221,7 @@ static size_t cal_rt_frame_size(void)
 
 	frame_size = sizeof(*frame);
 
-	if (has_vector)
+	if (has_vector())
 		total_context_size += rvv_sc_size;
 	/* Preserved a __riscv_ctx_hdr for END signal context header. */
 	total_context_size += sizeof(struct __riscv_ctx_hdr);
@@ -288,7 +288,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
 	if (has_fpu())
 		err |= save_fp_state(regs, &sc->sc_fpregs);
 	/* Save the vector state. */
-	if (has_vector)
+	if (has_vector())
 		err |= save_v_state(regs, &sc_reserved_free_ptr);
 
 	/* Put END __riscv_ctx_hdr at the end. */
Signature · 1 line
2.31.1
#52 lore raw

Re: [RFC PATCH v8 21/21] riscv: Turn has_vector into a static key if VECTOR=y

Quoted 5 lines · On Thu, 9 Sep 2021 01:45:33 +0800 Greentime Hu <[email protected]> wrote:

Just like fpu, we can use static key for has_vector.
The has_vector check sits at hot code path: switch_to(). Currently, has_vector is a bool variable if VECTOR=y, switch_to() checks it each time, we can optimize out this check by turning the has_vector into a static key.

has_vector is newly introduced in this patch set so I believe this patch can be folded into has_vector introducing patch, I.E patch 6

Quoted 155 lines
---
 arch/riscv/include/asm/switch_to.h     | 10 +++++++---
 arch/riscv/kernel/cpufeature.c         |  4 ++--
 arch/riscv/kernel/kernel_mode_vector.c |  4 ++--
 arch/riscv/kernel/process.c            |  8 ++++----
 arch/riscv/kernel/signal.c             |  6 +++---
 5 files changed, 18 insertions(+), 14 deletions(-)
arch/riscv/include/asm/switch_to.h +7 -3
index b48c9c974564..576204217e0f 100644
@@ -71,7 +71,11 @@ static __always_inline bool has_fpu(void) { return false; }
 #endif
 
 #ifdef CONFIG_VECTOR
-extern bool has_vector;
+extern struct static_key_false cpu_hwcap_vector;
+static __always_inline bool has_vector(void)
+{
+	return static_branch_likely(&cpu_hwcap_vector);
+}
 extern unsigned long riscv_vsize;
 extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
 extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
@@ -120,7 +124,7 @@ static inline void __switch_to_vector(struct task_struct *prev,
 }
 
 #else
-#define has_vector false
+static __always_inline bool has_vector(void) { return false; }
 #define riscv_vsize (0)
 #define vstate_save(task, regs) do { } while (0)
 #define vstate_restore(task, regs) do { } while (0)
@@ -136,7 +140,7 @@ do {							\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
 		__switch_to_fpu(__prev, __next);	\
-	if (has_vector)					\
+	if (has_vector())					\
 		__switch_to_vector(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
arch/riscv/kernel/cpufeature.c +2 -2
index af984f875f60..0139ec20adce 100644
@@ -23,7 +23,7 @@ __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
 #ifdef CONFIG_VECTOR
 #include <asm/vector.h>
-bool has_vector __read_mostly;
+__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_vector);
 unsigned long riscv_vsize __read_mostly;
 #endif
 
@@ -157,7 +157,7 @@ void __init riscv_fill_hwcap(void)
 
 #ifdef CONFIG_VECTOR
 	if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
-		has_vector = true;
+		static_branch_enable(&cpu_hwcap_vector);
 		/* There are 32 vector registers with vlenb length. */
 		rvv_enable();
 		riscv_vsize = csr_read(CSR_VLENB) * 32;
arch/riscv/kernel/kernel_mode_vector.c +2 -2
index 0d990bd8b8dd..0d08954c30af 100644
@@ -110,7 +110,7 @@ static void vector_flush_cpu_state(void)
  */
 void kernel_rvv_begin(void)
 {
-	if (WARN_ON(!has_vector))
+	if (WARN_ON(!has_vector()))
 		return;
 
 	WARN_ON(!may_use_vector());
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(kernel_rvv_begin);
  */
 void kernel_rvv_end(void)
 {
-	if (WARN_ON(!has_vector))
+	if (WARN_ON(!has_vector()))
 		return;
 
 	/* Invalidate vector regs */
arch/riscv/kernel/process.c +4 -4
index 05ff5f934e7e..62540815ba1c 100644
@@ -96,7 +96,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
 		fstate_restore(current, regs);
 	}
 
-	if (has_vector) {
+	if (has_vector()) {
 		struct __riscv_v_state *vstate = &(current->thread.vstate);
 
 		/* Enable vector and allocate memory for vector registers. */
@@ -141,11 +141,11 @@ void flush_thread(void)
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	fstate_save(src, task_pt_regs(src));
-	if (has_vector)
+	if (has_vector())
 		/* To make sure every dirty vector context is saved. */
 		vstate_save(src, task_pt_regs(src));
 	*dst = *src;
-	if (has_vector) {
+	if (has_vector()) {
 		/* Copy vector context to the forked task from parent. */
 		if ((task_pt_regs(src)->status & SR_VS) != SR_VS_OFF) {
 			dst->thread.vstate.datap = kzalloc(riscv_vsize, GFP_KERNEL);
@@ -164,7 +164,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 void arch_release_task_struct(struct task_struct *tsk)
 {
 	/* Free the vector context of datap. */
-	if (has_vector)
+	if (has_vector())
 		kfree(tsk->thread.vstate.datap);
 }
 
arch/riscv/kernel/signal.c +3 -3
index d30a3b588156..6a19b4b7b206 100644
@@ -192,7 +192,7 @@ static long restore_sigcontext(struct pt_regs *regs,
 				goto invalid;
 			goto done;
 		case RVV_MAGIC:
-			if (!has_vector)
+			if (!has_vector())
 				goto invalid;
 			if (size != rvv_sc_size)
 				goto invalid;
@@ -221,7 +221,7 @@ static size_t cal_rt_frame_size(void)
 
 	frame_size = sizeof(*frame);
 
-	if (has_vector)
+	if (has_vector())
 		total_context_size += rvv_sc_size;
 	/* Preserved a __riscv_ctx_hdr for END signal context header. */
 	total_context_size += sizeof(struct __riscv_ctx_hdr);
@@ -288,7 +288,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
 	if (has_fpu())
 		err |= save_fp_state(regs, &sc->sc_fpregs);
 	/* Save the vector state. */
-	if (has_vector)
+	if (has_vector())
 		err |= save_v_state(regs, &sc_reserved_free_ptr);
 
 	/* Put END __riscv_ctx_hdr at the end. */
#53 lore raw

Re: [RFC PATCH v8 21/21] riscv: Turn has_vector into a static key if VECTOR=y

Jisheng Zhang <[email protected]> 於 2021年9月15日 週三 下午10:31寫道:

Quoted 4 lines

On Thu, 9 Sep 2021 01:45:33 +0800
Greentime Hu <[email protected]> wrote:

Quoted 9 lines
Quoted 5 lines

Just like fpu, we can use static key for has_vector.
The has_vector check sits at hot code path: switch_to(). Currently, has_vector is a bool variable if VECTOR=y, switch_to() checks it each time, we can optimize out this check by turning the has_vector into a static key.

has_vector is newly introduced in this patch set so I believe this patch can be folded into has_vector introducing patch, I.E patch 6

ok, I'll split this patch and merge these codes into its related patches.

Quoted 158 lines
Quoted 156 lines
---
 arch/riscv/include/asm/switch_to.h     | 10 +++++++---
 arch/riscv/kernel/cpufeature.c         |  4 ++--
 arch/riscv/kernel/kernel_mode_vector.c |  4 ++--
 arch/riscv/kernel/process.c            |  8 ++++----
 arch/riscv/kernel/signal.c             |  6 +++---
 5 files changed, 18 insertions(+), 14 deletions(-)
arch/riscv/include/asm/switch_to.h +7 -3
index b48c9c974564..576204217e0f 100644
@@ -71,7 +71,11 @@ static __always_inline bool has_fpu(void) { return false; }
 #endif
 
 #ifdef CONFIG_VECTOR
-extern bool has_vector;
+extern struct static_key_false cpu_hwcap_vector;
+static __always_inline bool has_vector(void)
+{
+     return static_branch_likely(&cpu_hwcap_vector);
+}
 extern unsigned long riscv_vsize;
 extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
 extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
@@ -120,7 +124,7 @@ static inline void __switch_to_vector(struct task_struct *prev,
 }
 
 #else
-#define has_vector false
+static __always_inline bool has_vector(void) { return false; }
 #define riscv_vsize (0)
 #define vstate_save(task, regs) do { } while (0)
 #define vstate_restore(task, regs) do { } while (0)
@@ -136,7 +140,7 @@ do {                                                      \
      struct task_struct *__next = (next);            \
      if (has_fpu())                                  \
              __switch_to_fpu(__prev, __next);        \
-     if (has_vector)                                 \
+     if (has_vector())                                       \
              __switch_to_vector(__prev, __next);     \
      ((last) = __switch_to(__prev, __next));         \
 } while (0)
arch/riscv/kernel/cpufeature.c +2 -2
index af984f875f60..0139ec20adce 100644
@@ -23,7 +23,7 @@ __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
 #ifdef CONFIG_VECTOR
 #include <asm/vector.h>
-bool has_vector __read_mostly;
+__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_vector);
 unsigned long riscv_vsize __read_mostly;
 #endif
 
@@ -157,7 +157,7 @@ void __init riscv_fill_hwcap(void)
 
 #ifdef CONFIG_VECTOR
      if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
-             has_vector = true;
+             static_branch_enable(&cpu_hwcap_vector);
              /* There are 32 vector registers with vlenb length. */
              rvv_enable();
              riscv_vsize = csr_read(CSR_VLENB) * 32;
arch/riscv/kernel/kernel_mode_vector.c +2 -2
index 0d990bd8b8dd..0d08954c30af 100644
@@ -110,7 +110,7 @@ static void vector_flush_cpu_state(void)
  */
 void kernel_rvv_begin(void)
 {
-     if (WARN_ON(!has_vector))
+     if (WARN_ON(!has_vector()))
              return;
 
      WARN_ON(!may_use_vector());
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(kernel_rvv_begin);
  */
 void kernel_rvv_end(void)
 {
-     if (WARN_ON(!has_vector))
+     if (WARN_ON(!has_vector()))
              return;
 
      /* Invalidate vector regs */
arch/riscv/kernel/process.c +4 -4
index 05ff5f934e7e..62540815ba1c 100644
@@ -96,7 +96,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
              fstate_restore(current, regs);
      }
 
-     if (has_vector) {
+     if (has_vector()) {
              struct __riscv_v_state *vstate = &(current->thread.vstate);
 
              /* Enable vector and allocate memory for vector registers. */
@@ -141,11 +141,11 @@ void flush_thread(void)
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
      fstate_save(src, task_pt_regs(src));
-     if (has_vector)
+     if (has_vector())
              /* To make sure every dirty vector context is saved. */
              vstate_save(src, task_pt_regs(src));
      *dst = *src;
-     if (has_vector) {
+     if (has_vector()) {
              /* Copy vector context to the forked task from parent. */
              if ((task_pt_regs(src)->status & SR_VS) != SR_VS_OFF) {
                      dst->thread.vstate.datap = kzalloc(riscv_vsize, GFP_KERNEL);
@@ -164,7 +164,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 void arch_release_task_struct(struct task_struct *tsk)
 {
      /* Free the vector context of datap. */
-     if (has_vector)
+     if (has_vector())
              kfree(tsk->thread.vstate.datap);
 }
 
arch/riscv/kernel/signal.c +3 -3
index d30a3b588156..6a19b4b7b206 100644
@@ -192,7 +192,7 @@ static long restore_sigcontext(struct pt_regs *regs,
                              goto invalid;
                      goto done;
              case RVV_MAGIC:
-                     if (!has_vector)
+                     if (!has_vector())
                              goto invalid;
                      if (size != rvv_sc_size)
                              goto invalid;
@@ -221,7 +221,7 @@ static size_t cal_rt_frame_size(void)
 
      frame_size = sizeof(*frame);
 
-     if (has_vector)
+     if (has_vector())
              total_context_size += rvv_sc_size;
      /* Preserved a __riscv_ctx_hdr for END signal context header. */
      total_context_size += sizeof(struct __riscv_ctx_hdr);
@@ -288,7 +288,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
      if (has_fpu())
              err |= save_fp_state(regs, &sc->sc_fpregs);
      /* Save the vector state. */
-     if (has_vector)
+     if (has_vector())
              err |= save_v_state(regs, &sc_reserved_free_ptr);
 
      /* Put END __riscv_ctx_hdr at the end. */
#54 lore raw
In reply to Greentime Hu

Hi all,

The associated Glibc vector patches could be found here
https://sourceware.org/pipermail/libc-alpha/2021-September/130897.html
Thanks

Quoted 146 lines · Greentime Hu

This patchset is implemented based on vector 1.0-rc1 spec to add vector support in riscv Linux kernel. To make this happen, we defined a new structure __riscv_v_state to save the vector related registers. It is used for both kernel space and user space.

- In kernel space, the datap pointer in __riscv_v_state will be allocated dynamically to save vector registers.
- In user space,
- In signal handler of user space, datap will point to the address of the __riscv_v_state data structure to save vector registers in stack. We also create a __reserved[] array for future extensions.
- In ptrace, the data will be put in ubuf in which we use riscv_vr_get()/riscv_vr_set() to get or set the __riscv_v_state data structure from/to it, datap pointer would be zeroed and vector registers will be copied to the address right after the __riscv_v_state structure in ubuf.

This patchset also adds support for kernel mode vector, kernel XOR implementation with vector ISA and includes several bug fixes and code refinement.

This patchset is rebased to v5.14 and it is tested by running several vector programs simultaneously. It also can get the correct ucontext_t in signal handler and restore correct context after sigreturn. It is also tested with ptrace() syscall to use PTRACE_GETREGSET/PTRACE_SETREGSET to get/set the vector registers. I have tested vlen=128 and vlen=256 cases in qemu-system-riscv64 provided by Frank Chang.

We have sent patches to glibc mailing list for ifunc support and sigcontext changes. We will send patches for vector support to glibc mailing list recently.

[1] https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc

---
Changelog V8
- Rebase to v5.14
- Refine struct __riscv_v_state with struct __riscv_ctx_hdr
- Refine has_vector into a static key
- Defined __reserved space in struct sigcontext for vector and future extensions

Changelog V7
- Add support for kernel mode vector
- Add vector extension XOR implementation
- Optimize task switch codes of vector
- Allocate space for vector registers in start_thread()
- Fix an illegal instruction exception when accessing vlenb
- Optimize vector registers initialization
- Initialize vector registers with proper vsetvli then it can work normally
- Refine ptrace porting due to generic API changed
- Code clean up

Changelog V6
- Replace vle.v/vse.v instructions with vle8.v/vse8.v based on 0.9 spec
- Add comments based on mailinglist feedback
- Fix rv32 build error

Changelog V5
- Using regset_size() correctly in generic ptrace
- Fix the ptrace porting
- Fix compile warning

Changelog V4
- Support dynamic vlen
- Fix bugs: lazy save/resotre, not saving vtype
- Update VS bit offset based on latest vector spec
- Add new vector csr based on latest vector spec
- Code refine and removed unused macros

Changelog V3
- Rebase linux-5.6-rc3 and tested with qemu
- Seperate patches with Anup's advice
- Give out a ABI puzzle with unlimited vlen

Changelog V2
- Fixup typo "vecotr, fstate_save->vstate_save".
- Fixup wrong saved registers' length in vector.S.
- Seperate unrelated patches from this one.

Greentime Hu (15):
riscv: Add new csr defines related to vector extension
riscv: Add has_vector/riscv_vsize to save vector features.
riscv: Add vector struct and assembler definitions
riscv: Add task switch support for vector
riscv: Add ptrace vector support
riscv: Add sigcontext save/restore for vector
riscv: Add support for kernel mode vector
riscv: Use CSR_STATUS to replace sstatus in vector.S
riscv: Add vector extension XOR implementation
riscv: Initialize vector registers with proper vsetvli then it can
work normally
riscv: Optimize vector registers initialization
riscv: Fix an illegal instruction exception when accessing vlenb
without enable vector first
riscv: Allocate space for vector registers in start_thread()
riscv: Optimize task switch codes of vector
riscv: Turn has_vector into a static key if VECTOR=y

Guo Ren (5):
riscv: Separate patch for cflags and aflags
riscv: Rename __switch_to_aux -> fpu
riscv: Extending cpufeature.c to detect V-extension
riscv: Add vector feature to compile
riscv: Reset vector register

Vincent Chen (1):
riscv: signal: Report signal frame size to userspace via auxv

 arch/riscv/Kconfig                       |   9 ++
 arch/riscv/Makefile                      |  19 ++-
 arch/riscv/include/asm/csr.h             |  16 ++-
 arch/riscv/include/asm/elf.h             |  41 +++---
 arch/riscv/include/asm/processor.h       |   3 +
 arch/riscv/include/asm/switch_to.h       |  71 +++++++++-
 arch/riscv/include/asm/vector.h          |  16 +++
 arch/riscv/include/asm/xor.h             |  74 ++++++++++
 arch/riscv/include/uapi/asm/auxvec.h     |   1 +
 arch/riscv/include/uapi/asm/hwcap.h      |   1 +
 arch/riscv/include/uapi/asm/ptrace.h     |  25 ++++
 arch/riscv/include/uapi/asm/sigcontext.h |  24 ++++
 arch/riscv/kernel/Makefile               |   7 +
 arch/riscv/kernel/asm-offsets.c          |   8 ++
 arch/riscv/kernel/cpufeature.c           |  16 +++
 arch/riscv/kernel/entry.S                |   6 +-
 arch/riscv/kernel/head.S                 |  22 ++-
 arch/riscv/kernel/kernel_mode_vector.c   | 158 +++++++++++++++++++++
 arch/riscv/kernel/process.c              |  49 +++++++
 arch/riscv/kernel/ptrace.c               |  71 ++++++++++
 arch/riscv/kernel/setup.c                |   4 +
 arch/riscv/kernel/signal.c               | 172 ++++++++++++++++++++++-
 arch/riscv/kernel/vector.S               |  81 +++++++++++
 arch/riscv/lib/Makefile                  |   1 +
 arch/riscv/lib/xor.S                     |  81 +++++++++++
 include/uapi/linux/elf.h                 |   1 +
 26 files changed, 941 insertions(+), 36 deletions(-)
 create mode 100644 arch/riscv/include/asm/vector.h
 create mode 100644 arch/riscv/include/asm/xor.h
 create mode 100644 arch/riscv/kernel/kernel_mode_vector.c
 create mode 100644 arch/riscv/kernel/vector.S
 create mode 100644 arch/riscv/lib/xor.S

--
2.31.1

#55 lore raw
In reply to Greentime Hu
Quoted 22 lines · Greentime Hu

This patchset is implemented based on vector 1.0-rc1 spec to add vector support in riscv Linux kernel. To make this happen, we defined a new structure __riscv_v_state to save the vector related registers. It is used for both kernel space and user space.

- In kernel space, the datap pointer in __riscv_v_state will be allocated dynamically to save vector registers.
- In user space,
- In signal handler of user space, datap will point to the address of the __riscv_v_state data structure to save vector registers in stack. We also create a __reserved[] array for future extensions.
- In ptrace, the data will be put in ubuf in which we use riscv_vr_get()/riscv_vr_set() to get or set the __riscv_v_state data structure from/to it, datap pointer would be zeroed and vector registers will be copied to the address right after the __riscv_v_state structure in ubuf.

This patchset also adds support for kernel mode vector, kernel XOR implementation with vector ISA and includes several bug fixes and code refinement.

Quoted 6 lines

This patchset is rebased to v5.14 and it is tested by running several vector programs simultaneously. It also can get the correct ucontext_t in signal handler and restore correct context after sigreturn. It is also tested with ptrace() syscall to use PTRACE_GETREGSET/PTRACE_SETREGSET to get/set the vector registers. I have tested vlen=128 and vlen=256 cases in qemu-system-riscv64 provided by Frank Chang.

Are QEMU/Spike changes available somewhere publicly for people to try this ?

Thx,
-Vineet

Quoted 114 lines

We have sent patches to glibc mailing list for ifunc support and sigcontext changes. We will send patches for vector support to glibc mailing list recently.

[1] https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc

---
Changelog V8
- Rebase to v5.14
- Refine struct __riscv_v_state with struct __riscv_ctx_hdr
- Refine has_vector into a static key
- Defined __reserved space in struct sigcontext for vector and future extensions

Changelog V7
- Add support for kernel mode vector
- Add vector extension XOR implementation
- Optimize task switch codes of vector
- Allocate space for vector registers in start_thread()
- Fix an illegal instruction exception when accessing vlenb
- Optimize vector registers initialization
- Initialize vector registers with proper vsetvli then it can work normally
- Refine ptrace porting due to generic API changed
- Code clean up

Changelog V6
- Replace vle.v/vse.v instructions with vle8.v/vse8.v based on 0.9 spec
- Add comments based on mailinglist feedback
- Fix rv32 build error

Changelog V5
- Using regset_size() correctly in generic ptrace
- Fix the ptrace porting
- Fix compile warning

Changelog V4
- Support dynamic vlen
- Fix bugs: lazy save/resotre, not saving vtype
- Update VS bit offset based on latest vector spec
- Add new vector csr based on latest vector spec
- Code refine and removed unused macros

Changelog V3
- Rebase linux-5.6-rc3 and tested with qemu
- Seperate patches with Anup's advice
- Give out a ABI puzzle with unlimited vlen

Changelog V2
- Fixup typo "vecotr, fstate_save->vstate_save".
- Fixup wrong saved registers' length in vector.S.
- Seperate unrelated patches from this one.

Greentime Hu (15):
riscv: Add new csr defines related to vector extension
riscv: Add has_vector/riscv_vsize to save vector features.
riscv: Add vector struct and assembler definitions
riscv: Add task switch support for vector
riscv: Add ptrace vector support
riscv: Add sigcontext save/restore for vector
riscv: Add support for kernel mode vector
riscv: Use CSR_STATUS to replace sstatus in vector.S
riscv: Add vector extension XOR implementation
riscv: Initialize vector registers with proper vsetvli then it can
work normally
riscv: Optimize vector registers initialization
riscv: Fix an illegal instruction exception when accessing vlenb
without enable vector first
riscv: Allocate space for vector registers in start_thread()
riscv: Optimize task switch codes of vector
riscv: Turn has_vector into a static key if VECTOR=y

Guo Ren (5):
riscv: Separate patch for cflags and aflags
riscv: Rename __switch_to_aux -> fpu
riscv: Extending cpufeature.c to detect V-extension
riscv: Add vector feature to compile
riscv: Reset vector register

Vincent Chen (1):
riscv: signal: Report signal frame size to userspace via auxv

  arch/riscv/Kconfig                       |   9 ++
  arch/riscv/Makefile                      |  19 ++-
  arch/riscv/include/asm/csr.h             |  16 ++-
  arch/riscv/include/asm/elf.h             |  41 +++---
  arch/riscv/include/asm/processor.h       |   3 +
  arch/riscv/include/asm/switch_to.h       |  71 +++++++++-
  arch/riscv/include/asm/vector.h          |  16 +++
  arch/riscv/include/asm/xor.h             |  74 ++++++++++
  arch/riscv/include/uapi/asm/auxvec.h     |   1 +
  arch/riscv/include/uapi/asm/hwcap.h      |   1 +
  arch/riscv/include/uapi/asm/ptrace.h     |  25 ++++
  arch/riscv/include/uapi/asm/sigcontext.h |  24 ++++
  arch/riscv/kernel/Makefile               |   7 +
  arch/riscv/kernel/asm-offsets.c          |   8 ++
  arch/riscv/kernel/cpufeature.c           |  16 +++
  arch/riscv/kernel/entry.S                |   6 +-
  arch/riscv/kernel/head.S                 |  22 ++-
  arch/riscv/kernel/kernel_mode_vector.c   | 158 +++++++++++++++++++++
  arch/riscv/kernel/process.c              |  49 +++++++
  arch/riscv/kernel/ptrace.c               |  71 ++++++++++
  arch/riscv/kernel/setup.c                |   4 +
  arch/riscv/kernel/signal.c               | 172 ++++++++++++++++++++++-
  arch/riscv/kernel/vector.S               |  81 +++++++++++
  arch/riscv/lib/Makefile                  |   1 +
  arch/riscv/lib/xor.S                     |  81 +++++++++++
  include/uapi/linux/elf.h                 |   1 +
  26 files changed, 941 insertions(+), 36 deletions(-)

create mode 100644 arch/riscv/include/asm/vector.h create mode 100644 arch/riscv/include/asm/xor.h create mode 100644 arch/riscv/kernel/kernel_mode_vector.c create mode 100644 arch/riscv/kernel/vector.S create mode 100644 arch/riscv/lib/xor.S