d09a307fde
Follow arm64 and riscv and move the EX_TABLE define to asm-extable.h which is a lot less generic than the current linkage.h. Also make sure that all files which contain EX_TABLE usages actually include the new header file. This should make sure that the files always compile and there won't be any random compile breakage due to other header file dependencies. Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
120 lines
3.8 KiB
C
120 lines
3.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* In-kernel FPU support functions
|
|
*
|
|
*
|
|
* Consider these guidelines before using in-kernel FPU functions:
|
|
*
|
|
* 1. Use kernel_fpu_begin() and kernel_fpu_end() to enclose all in-kernel
|
|
* use of floating-point or vector registers and instructions.
|
|
*
|
|
* 2. For kernel_fpu_begin(), specify the vector register range you want to
|
|
* use with the KERNEL_VXR_* constants. Consider these usage guidelines:
|
|
*
|
|
* a) If your function typically runs in process-context, use the lower
|
|
* half of the vector registers, for example, specify KERNEL_VXR_LOW.
|
|
* b) If your function typically runs in soft-irq or hard-irq context,
|
|
* prefer using the upper half of the vector registers, for example,
|
|
* specify KERNEL_VXR_HIGH.
|
|
*
|
|
* If you adhere to these guidelines, an interrupted process context
|
|
* does not require to save and restore vector registers because of
|
|
* disjoint register ranges.
|
|
*
|
|
* Also note that the __kernel_fpu_begin()/__kernel_fpu_end() functions
|
|
* includes logic to save and restore up to 16 vector registers at once.
|
|
*
|
|
* 3. You can nest kernel_fpu_begin()/kernel_fpu_end() by using different
|
|
* struct kernel_fpu states. Vector registers that are in use by outer
|
|
* levels are saved and restored. You can minimize the save and restore
|
|
* effort by choosing disjoint vector register ranges.
|
|
*
|
|
* 5. To use vector floating-point instructions, specify the KERNEL_FPC
|
|
* flag to save and restore floating-point controls in addition to any
|
|
* vector register range.
|
|
*
|
|
* 6. To use floating-point registers and instructions only, specify the
|
|
* KERNEL_FPR flag. This flag triggers a save and restore of vector
|
|
* registers V0 to V15 and floating-point controls.
|
|
*
|
|
* Copyright IBM Corp. 2015
|
|
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
|
|
*/
|
|
|
|
#ifndef _ASM_S390_FPU_API_H
|
|
#define _ASM_S390_FPU_API_H
|
|
|
|
#include <linux/preempt.h>
|
|
#include <asm/asm-extable.h>
|
|
|
|
void save_fpu_regs(void);
|
|
void load_fpu_regs(void);
|
|
void __load_fpu_regs(void);
|
|
|
|
static inline int test_fp_ctl(u32 fpc)
|
|
{
|
|
u32 orig_fpc;
|
|
int rc;
|
|
|
|
asm volatile(
|
|
" efpc %1\n"
|
|
" sfpc %2\n"
|
|
"0: sfpc %1\n"
|
|
" la %0,0\n"
|
|
"1:\n"
|
|
EX_TABLE(0b,1b)
|
|
: "=d" (rc), "=&d" (orig_fpc)
|
|
: "d" (fpc), "0" (-EINVAL));
|
|
return rc;
|
|
}
|
|
|
|
#define KERNEL_FPC 1
|
|
#define KERNEL_VXR_V0V7 2
|
|
#define KERNEL_VXR_V8V15 4
|
|
#define KERNEL_VXR_V16V23 8
|
|
#define KERNEL_VXR_V24V31 16
|
|
|
|
#define KERNEL_VXR_LOW (KERNEL_VXR_V0V7|KERNEL_VXR_V8V15)
|
|
#define KERNEL_VXR_MID (KERNEL_VXR_V8V15|KERNEL_VXR_V16V23)
|
|
#define KERNEL_VXR_HIGH (KERNEL_VXR_V16V23|KERNEL_VXR_V24V31)
|
|
|
|
#define KERNEL_VXR (KERNEL_VXR_LOW|KERNEL_VXR_HIGH)
|
|
#define KERNEL_FPR (KERNEL_FPC|KERNEL_VXR_V0V7)
|
|
|
|
struct kernel_fpu;
|
|
|
|
/*
|
|
* Note the functions below must be called with preemption disabled.
|
|
* Do not enable preemption before calling __kernel_fpu_end() to prevent
|
|
* an corruption of an existing kernel FPU state.
|
|
*
|
|
* Prefer using the kernel_fpu_begin()/kernel_fpu_end() pair of functions.
|
|
*/
|
|
void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags);
|
|
void __kernel_fpu_end(struct kernel_fpu *state, u32 flags);
|
|
|
|
|
|
static inline void kernel_fpu_begin(struct kernel_fpu *state, u32 flags)
|
|
{
|
|
preempt_disable();
|
|
state->mask = S390_lowcore.fpu_flags;
|
|
if (!test_cpu_flag(CIF_FPU))
|
|
/* Save user space FPU state and register contents */
|
|
save_fpu_regs();
|
|
else if (state->mask & flags)
|
|
/* Save FPU/vector register in-use by the kernel */
|
|
__kernel_fpu_begin(state, flags);
|
|
S390_lowcore.fpu_flags |= flags;
|
|
}
|
|
|
|
static inline void kernel_fpu_end(struct kernel_fpu *state, u32 flags)
|
|
{
|
|
S390_lowcore.fpu_flags = state->mask;
|
|
if (state->mask & flags)
|
|
/* Restore FPU/vector register in-use by the kernel */
|
|
__kernel_fpu_end(state, flags);
|
|
preempt_enable();
|
|
}
|
|
|
|
#endif /* _ASM_S390_FPU_API_H */
|