mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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 <vincent.chen@sifive.com> Signed-off-by: Vincent Chen <vincent.chen@sifive.com> Signed-off-by: Greentime Hu <greentime.hu@sifive.com> Signed-off-by: Andy Chiu <andy.chiu@sifive.com> Reviewed-by: Eric Biggers <ebiggers@google.com> Tested-by: Björn Töpel <bjorn@rivosinc.com> Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> Link: https://lore.kernel.org/r/20240115055929.4736-2-andy.chiu@sifive.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
This commit is contained in:
parent
b85ea95d08
commit
ecd2ada8a5
6 changed files with 182 additions and 1 deletions
|
@ -73,6 +73,15 @@
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
struct pt_regs;
|
struct pt_regs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use a flag to track in-kernel Vector context. Currently the flag has the
|
||||||
|
* following meaning:
|
||||||
|
*
|
||||||
|
* - bit 0: indicates whether the in-kernel Vector context is active. The
|
||||||
|
* activation of this state disables the preemption.
|
||||||
|
*/
|
||||||
|
#define RISCV_KERNEL_MODE_V 0x1
|
||||||
|
|
||||||
/* CPU-specific state of a task */
|
/* CPU-specific state of a task */
|
||||||
struct thread_struct {
|
struct thread_struct {
|
||||||
/* Callee-saved registers */
|
/* Callee-saved registers */
|
||||||
|
@ -81,7 +90,8 @@ struct thread_struct {
|
||||||
unsigned long s[12]; /* s[0]: frame pointer */
|
unsigned long s[12]; /* s[0]: frame pointer */
|
||||||
struct __riscv_d_ext_state fstate;
|
struct __riscv_d_ext_state fstate;
|
||||||
unsigned long bad_cause;
|
unsigned long bad_cause;
|
||||||
unsigned long vstate_ctrl;
|
u32 riscv_v_flags;
|
||||||
|
u32 vstate_ctrl;
|
||||||
struct __riscv_v_ext_state vstate;
|
struct __riscv_v_ext_state vstate;
|
||||||
unsigned long align_ctl;
|
unsigned long align_ctl;
|
||||||
};
|
};
|
||||||
|
|
44
arch/riscv/include/asm/simd.h
Normal file
44
arch/riscv/include/asm/simd.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||||
|
* Copyright (C) 2023 SiFive
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_SIMD_H
|
||||||
|
#define __ASM_SIMD_H
|
||||||
|
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/irqflags.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
#include <linux/preempt.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include <asm/vector.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_RISCV_ISA_V
|
||||||
|
/*
|
||||||
|
* may_use_simd - whether it is allowable at this time to issue vector
|
||||||
|
* instructions or access the vector register file
|
||||||
|
*
|
||||||
|
* Callers must not assume that the result remains true beyond the next
|
||||||
|
* preempt_enable() or return from softirq context.
|
||||||
|
*/
|
||||||
|
static __must_check inline bool may_use_simd(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* RISCV_KERNEL_MODE_V is only set while preemption is disabled,
|
||||||
|
* and is clear whenever preemption is enabled.
|
||||||
|
*/
|
||||||
|
return !in_hardirq() && !in_nmi() && !(riscv_v_flags() & RISCV_KERNEL_MODE_V);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* ! CONFIG_RISCV_ISA_V */
|
||||||
|
|
||||||
|
static __must_check inline bool may_use_simd(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ! CONFIG_RISCV_ISA_V */
|
||||||
|
|
||||||
|
#endif
|
|
@ -22,6 +22,15 @@
|
||||||
extern unsigned long riscv_v_vsize;
|
extern unsigned long riscv_v_vsize;
|
||||||
int riscv_v_setup_vsize(void);
|
int riscv_v_setup_vsize(void);
|
||||||
bool riscv_v_first_use_handler(struct pt_regs *regs);
|
bool riscv_v_first_use_handler(struct pt_regs *regs);
|
||||||
|
void kernel_vector_begin(void);
|
||||||
|
void kernel_vector_end(void);
|
||||||
|
void get_cpu_vector_context(void);
|
||||||
|
void put_cpu_vector_context(void);
|
||||||
|
|
||||||
|
static inline u32 riscv_v_flags(void)
|
||||||
|
{
|
||||||
|
return current->thread.riscv_v_flags;
|
||||||
|
}
|
||||||
|
|
||||||
static __always_inline bool has_vector(void)
|
static __always_inline bool has_vector(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,6 +63,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
|
||||||
obj-$(CONFIG_RISCV_MISALIGNED) += traps_misaligned.o
|
obj-$(CONFIG_RISCV_MISALIGNED) += traps_misaligned.o
|
||||||
obj-$(CONFIG_FPU) += fpu.o
|
obj-$(CONFIG_FPU) += fpu.o
|
||||||
obj-$(CONFIG_RISCV_ISA_V) += vector.o
|
obj-$(CONFIG_RISCV_ISA_V) += vector.o
|
||||||
|
obj-$(CONFIG_RISCV_ISA_V) += kernel_mode_vector.o
|
||||||
obj-$(CONFIG_SMP) += smpboot.o
|
obj-$(CONFIG_SMP) += smpboot.o
|
||||||
obj-$(CONFIG_SMP) += smp.o
|
obj-$(CONFIG_SMP) += smp.o
|
||||||
obj-$(CONFIG_SMP) += cpu_ops.o
|
obj-$(CONFIG_SMP) += cpu_ops.o
|
||||||
|
|
116
arch/riscv/kernel/kernel_mode_vector.c
Normal file
116
arch/riscv/kernel/kernel_mode_vector.c
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 ARM Ltd.
|
||||||
|
* Author: Catalin Marinas <catalin.marinas@arm.com>
|
||||||
|
* Copyright (C) 2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||||
|
* Copyright (C) 2021 SiFive
|
||||||
|
*/
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/irqflags.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
#include <linux/preempt.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include <asm/vector.h>
|
||||||
|
#include <asm/switch_to.h>
|
||||||
|
#include <asm/simd.h>
|
||||||
|
|
||||||
|
static inline void riscv_v_flags_set(u32 flags)
|
||||||
|
{
|
||||||
|
current->thread.riscv_v_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_v_start(u32 flags)
|
||||||
|
{
|
||||||
|
int orig;
|
||||||
|
|
||||||
|
orig = riscv_v_flags();
|
||||||
|
BUG_ON((orig & flags) != 0);
|
||||||
|
riscv_v_flags_set(orig | flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_v_stop(u32 flags)
|
||||||
|
{
|
||||||
|
int orig;
|
||||||
|
|
||||||
|
orig = riscv_v_flags();
|
||||||
|
BUG_ON((orig & flags) == 0);
|
||||||
|
riscv_v_flags_set(orig & ~flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Claim ownership of the CPU vector context for use by the calling context.
|
||||||
|
*
|
||||||
|
* The caller may freely manipulate the vector context metadata until
|
||||||
|
* put_cpu_vector_context() is called.
|
||||||
|
*/
|
||||||
|
void get_cpu_vector_context(void)
|
||||||
|
{
|
||||||
|
preempt_disable();
|
||||||
|
|
||||||
|
riscv_v_start(RISCV_KERNEL_MODE_V);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release the CPU vector context.
|
||||||
|
*
|
||||||
|
* Must be called from a context in which get_cpu_vector_context() was
|
||||||
|
* previously called, with no call to put_cpu_vector_context() in the
|
||||||
|
* meantime.
|
||||||
|
*/
|
||||||
|
void put_cpu_vector_context(void)
|
||||||
|
{
|
||||||
|
riscv_v_stop(RISCV_KERNEL_MODE_V);
|
||||||
|
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kernel_vector_begin(): obtain the CPU vector registers for use by the calling
|
||||||
|
* context
|
||||||
|
*
|
||||||
|
* Must not be called unless may_use_simd() returns true.
|
||||||
|
* Task context in the vector registers is saved back to memory as necessary.
|
||||||
|
*
|
||||||
|
* A matching call to kernel_vector_end() must be made before returning from the
|
||||||
|
* calling context.
|
||||||
|
*
|
||||||
|
* The caller may freely use the vector registers until kernel_vector_end() is
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
|
void kernel_vector_begin(void)
|
||||||
|
{
|
||||||
|
if (WARN_ON(!has_vector()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
BUG_ON(!may_use_simd());
|
||||||
|
|
||||||
|
get_cpu_vector_context();
|
||||||
|
|
||||||
|
riscv_v_vstate_save(current, task_pt_regs(current));
|
||||||
|
|
||||||
|
riscv_v_enable();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(kernel_vector_begin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kernel_vector_end(): give the CPU vector registers back to the current task
|
||||||
|
*
|
||||||
|
* Must be called from a context in which kernel_vector_begin() was previously
|
||||||
|
* called, with no call to kernel_vector_end() in the meantime.
|
||||||
|
*
|
||||||
|
* The caller must not use the vector registers after this function is called,
|
||||||
|
* unless kernel_vector_begin() is called again in the meantime.
|
||||||
|
*/
|
||||||
|
void kernel_vector_end(void)
|
||||||
|
{
|
||||||
|
if (WARN_ON(!has_vector()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
riscv_v_vstate_restore(current, task_pt_regs(current));
|
||||||
|
|
||||||
|
riscv_v_disable();
|
||||||
|
|
||||||
|
put_cpu_vector_context();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(kernel_vector_end);
|
|
@ -221,6 +221,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
||||||
childregs->a0 = 0; /* Return value of fork() */
|
childregs->a0 = 0; /* Return value of fork() */
|
||||||
p->thread.s[0] = 0;
|
p->thread.s[0] = 0;
|
||||||
}
|
}
|
||||||
|
p->thread.riscv_v_flags = 0;
|
||||||
p->thread.ra = (unsigned long)ret_from_fork;
|
p->thread.ra = (unsigned long)ret_from_fork;
|
||||||
p->thread.sp = (unsigned long)childregs; /* kernel sp */
|
p->thread.sp = (unsigned long)childregs; /* kernel sp */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue