Skip to content

Commit ecd2ada

Browse files
greentimepalmer-dabbelt
authored andcommitted
riscv: Add support for kernel mode vector
Add kernel_vector_begin() and kernel_vector_end() function declarations and corresponding definitions in kernel_mode_vector.c These are needed to wrap uses of vector in kernel mode. Co-developed-by: Vincent Chen <[email protected]> Signed-off-by: Vincent Chen <[email protected]> Signed-off-by: Greentime Hu <[email protected]> Signed-off-by: Andy Chiu <[email protected]> Reviewed-by: Eric Biggers <[email protected]> Tested-by: Björn Töpel <[email protected]> Tested-by: Lad Prabhakar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent b85ea95 commit ecd2ada

File tree

6 files changed

+182
-1
lines changed

6 files changed

+182
-1
lines changed

arch/riscv/include/asm/processor.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@
7373
struct task_struct;
7474
struct pt_regs;
7575

76+
/*
77+
* We use a flag to track in-kernel Vector context. Currently the flag has the
78+
* following meaning:
79+
*
80+
* - bit 0: indicates whether the in-kernel Vector context is active. The
81+
* activation of this state disables the preemption.
82+
*/
83+
#define RISCV_KERNEL_MODE_V 0x1
84+
7685
/* CPU-specific state of a task */
7786
struct thread_struct {
7887
/* Callee-saved registers */
@@ -81,7 +90,8 @@ struct thread_struct {
8190
unsigned long s[12]; /* s[0]: frame pointer */
8291
struct __riscv_d_ext_state fstate;
8392
unsigned long bad_cause;
84-
unsigned long vstate_ctrl;
93+
u32 riscv_v_flags;
94+
u32 vstate_ctrl;
8595
struct __riscv_v_ext_state vstate;
8696
unsigned long align_ctl;
8797
};

arch/riscv/include/asm/simd.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2017 Linaro Ltd. <[email protected]>
4+
* Copyright (C) 2023 SiFive
5+
*/
6+
7+
#ifndef __ASM_SIMD_H
8+
#define __ASM_SIMD_H
9+
10+
#include <linux/compiler.h>
11+
#include <linux/irqflags.h>
12+
#include <linux/percpu.h>
13+
#include <linux/preempt.h>
14+
#include <linux/types.h>
15+
16+
#include <asm/vector.h>
17+
18+
#ifdef CONFIG_RISCV_ISA_V
19+
/*
20+
* may_use_simd - whether it is allowable at this time to issue vector
21+
* instructions or access the vector register file
22+
*
23+
* Callers must not assume that the result remains true beyond the next
24+
* preempt_enable() or return from softirq context.
25+
*/
26+
static __must_check inline bool may_use_simd(void)
27+
{
28+
/*
29+
* RISCV_KERNEL_MODE_V is only set while preemption is disabled,
30+
* and is clear whenever preemption is enabled.
31+
*/
32+
return !in_hardirq() && !in_nmi() && !(riscv_v_flags() & RISCV_KERNEL_MODE_V);
33+
}
34+
35+
#else /* ! CONFIG_RISCV_ISA_V */
36+
37+
static __must_check inline bool may_use_simd(void)
38+
{
39+
return false;
40+
}
41+
42+
#endif /* ! CONFIG_RISCV_ISA_V */
43+
44+
#endif

arch/riscv/include/asm/vector.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@
2222
extern unsigned long riscv_v_vsize;
2323
int riscv_v_setup_vsize(void);
2424
bool riscv_v_first_use_handler(struct pt_regs *regs);
25+
void kernel_vector_begin(void);
26+
void kernel_vector_end(void);
27+
void get_cpu_vector_context(void);
28+
void put_cpu_vector_context(void);
29+
30+
static inline u32 riscv_v_flags(void)
31+
{
32+
return current->thread.riscv_v_flags;
33+
}
2534

2635
static __always_inline bool has_vector(void)
2736
{

arch/riscv/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
6363
obj-$(CONFIG_RISCV_MISALIGNED) += traps_misaligned.o
6464
obj-$(CONFIG_FPU) += fpu.o
6565
obj-$(CONFIG_RISCV_ISA_V) += vector.o
66+
obj-$(CONFIG_RISCV_ISA_V) += kernel_mode_vector.o
6667
obj-$(CONFIG_SMP) += smpboot.o
6768
obj-$(CONFIG_SMP) += smp.o
6869
obj-$(CONFIG_SMP) += cpu_ops.o
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (C) 2012 ARM Ltd.
4+
* Author: Catalin Marinas <[email protected]>
5+
* Copyright (C) 2017 Linaro Ltd. <[email protected]>
6+
* Copyright (C) 2021 SiFive
7+
*/
8+
#include <linux/compiler.h>
9+
#include <linux/irqflags.h>
10+
#include <linux/percpu.h>
11+
#include <linux/preempt.h>
12+
#include <linux/types.h>
13+
14+
#include <asm/vector.h>
15+
#include <asm/switch_to.h>
16+
#include <asm/simd.h>
17+
18+
static inline void riscv_v_flags_set(u32 flags)
19+
{
20+
current->thread.riscv_v_flags = flags;
21+
}
22+
23+
static inline void riscv_v_start(u32 flags)
24+
{
25+
int orig;
26+
27+
orig = riscv_v_flags();
28+
BUG_ON((orig & flags) != 0);
29+
riscv_v_flags_set(orig | flags);
30+
}
31+
32+
static inline void riscv_v_stop(u32 flags)
33+
{
34+
int orig;
35+
36+
orig = riscv_v_flags();
37+
BUG_ON((orig & flags) == 0);
38+
riscv_v_flags_set(orig & ~flags);
39+
}
40+
41+
/*
42+
* Claim ownership of the CPU vector context for use by the calling context.
43+
*
44+
* The caller may freely manipulate the vector context metadata until
45+
* put_cpu_vector_context() is called.
46+
*/
47+
void get_cpu_vector_context(void)
48+
{
49+
preempt_disable();
50+
51+
riscv_v_start(RISCV_KERNEL_MODE_V);
52+
}
53+
54+
/*
55+
* Release the CPU vector context.
56+
*
57+
* Must be called from a context in which get_cpu_vector_context() was
58+
* previously called, with no call to put_cpu_vector_context() in the
59+
* meantime.
60+
*/
61+
void put_cpu_vector_context(void)
62+
{
63+
riscv_v_stop(RISCV_KERNEL_MODE_V);
64+
65+
preempt_enable();
66+
}
67+
68+
/*
69+
* kernel_vector_begin(): obtain the CPU vector registers for use by the calling
70+
* context
71+
*
72+
* Must not be called unless may_use_simd() returns true.
73+
* Task context in the vector registers is saved back to memory as necessary.
74+
*
75+
* A matching call to kernel_vector_end() must be made before returning from the
76+
* calling context.
77+
*
78+
* The caller may freely use the vector registers until kernel_vector_end() is
79+
* called.
80+
*/
81+
void kernel_vector_begin(void)
82+
{
83+
if (WARN_ON(!has_vector()))
84+
return;
85+
86+
BUG_ON(!may_use_simd());
87+
88+
get_cpu_vector_context();
89+
90+
riscv_v_vstate_save(current, task_pt_regs(current));
91+
92+
riscv_v_enable();
93+
}
94+
EXPORT_SYMBOL_GPL(kernel_vector_begin);
95+
96+
/*
97+
* kernel_vector_end(): give the CPU vector registers back to the current task
98+
*
99+
* Must be called from a context in which kernel_vector_begin() was previously
100+
* called, with no call to kernel_vector_end() in the meantime.
101+
*
102+
* The caller must not use the vector registers after this function is called,
103+
* unless kernel_vector_begin() is called again in the meantime.
104+
*/
105+
void kernel_vector_end(void)
106+
{
107+
if (WARN_ON(!has_vector()))
108+
return;
109+
110+
riscv_v_vstate_restore(current, task_pt_regs(current));
111+
112+
riscv_v_disable();
113+
114+
put_cpu_vector_context();
115+
}
116+
EXPORT_SYMBOL_GPL(kernel_vector_end);

arch/riscv/kernel/process.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
221221
childregs->a0 = 0; /* Return value of fork() */
222222
p->thread.s[0] = 0;
223223
}
224+
p->thread.riscv_v_flags = 0;
224225
p->thread.ra = (unsigned long)ret_from_fork;
225226
p->thread.sp = (unsigned long)childregs; /* kernel sp */
226227
return 0;

0 commit comments

Comments
 (0)