2080ff9493
Add kernel_vstate to keep track of kernel-mode Vector registers when trap introduced context switch happens. Also, provide riscv_v_flags to let context save/restore routine track context status. Context tracking happens whenever the core starts its in-kernel Vector executions. An active (dirty) kernel task's V contexts will be saved to memory whenever a trap-introduced context switch happens. Or, when a softirq, which happens to nest on top of it, uses Vector. Context retoring happens when the execution transfer back to the original Kernel context where it first enable preempt_v. Also, provide a config CONFIG_RISCV_ISA_V_PREEMPTIVE to give users an option to disable preemptible kernel-mode Vector at build time. Users with constraint memory may want to disable this config as preemptible kernel-mode Vector needs extra space for tracking of per thread's kernel-mode V context. Or, users might as well want to disable it if all kernel-mode Vector code is time sensitive and cannot tolerate context switch overhead. Signed-off-by: Andy Chiu <andy.chiu@sifive.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-11-andy.chiu@sifive.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
65 lines
1.7 KiB
C
65 lines
1.7 KiB
C
/* 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 <linux/thread_info.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.
|
|
*/
|
|
if (in_hardirq() || in_nmi())
|
|
return false;
|
|
|
|
/*
|
|
* Nesting is acheived in preempt_v by spreading the control for
|
|
* preemptible and non-preemptible kernel-mode Vector into two fields.
|
|
* Always try to match with prempt_v if kernel V-context exists. Then,
|
|
* fallback to check non preempt_v if nesting happens, or if the config
|
|
* is not set.
|
|
*/
|
|
if (IS_ENABLED(CONFIG_RISCV_ISA_V_PREEMPTIVE) && current->thread.kernel_vstate.datap) {
|
|
if (!riscv_preempt_v_started(current))
|
|
return true;
|
|
}
|
|
/*
|
|
* Non-preemptible kernel-mode Vector temporarily disables bh. So we
|
|
* must not return true on irq_disabled(). Otherwise we would fail the
|
|
* lockdep check calling local_bh_enable()
|
|
*/
|
|
return !irqs_disabled() && !(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
|