Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * In-kernel FPU support functions
0004  *
0005  *
0006  * Consider these guidelines before using in-kernel FPU functions:
0007  *
0008  *  1. Use kernel_fpu_begin() and kernel_fpu_end() to enclose all in-kernel
0009  *     use of floating-point or vector registers and instructions.
0010  *
0011  *  2. For kernel_fpu_begin(), specify the vector register range you want to
0012  *     use with the KERNEL_VXR_* constants. Consider these usage guidelines:
0013  *
0014  *     a) If your function typically runs in process-context, use the lower
0015  *    half of the vector registers, for example, specify KERNEL_VXR_LOW.
0016  *     b) If your function typically runs in soft-irq or hard-irq context,
0017  *    prefer using the upper half of the vector registers, for example,
0018  *    specify KERNEL_VXR_HIGH.
0019  *
0020  *     If you adhere to these guidelines, an interrupted process context
0021  *     does not require to save and restore vector registers because of
0022  *     disjoint register ranges.
0023  *
0024  *     Also note that the __kernel_fpu_begin()/__kernel_fpu_end() functions
0025  *     includes logic to save and restore up to 16 vector registers at once.
0026  *
0027  *  3. You can nest kernel_fpu_begin()/kernel_fpu_end() by using different
0028  *     struct kernel_fpu states.  Vector registers that are in use by outer
0029  *     levels are saved and restored.  You can minimize the save and restore
0030  *     effort by choosing disjoint vector register ranges.
0031  *
0032  *  5. To use vector floating-point instructions, specify the KERNEL_FPC
0033  *     flag to save and restore floating-point controls in addition to any
0034  *     vector register range.
0035  *
0036  *  6. To use floating-point registers and instructions only, specify the
0037  *     KERNEL_FPR flag.  This flag triggers a save and restore of vector
0038  *     registers V0 to V15 and floating-point controls.
0039  *
0040  * Copyright IBM Corp. 2015
0041  * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
0042  */
0043 
0044 #ifndef _ASM_S390_FPU_API_H
0045 #define _ASM_S390_FPU_API_H
0046 
0047 #include <linux/preempt.h>
0048 #include <asm/asm-extable.h>
0049 
0050 void save_fpu_regs(void);
0051 void load_fpu_regs(void);
0052 void __load_fpu_regs(void);
0053 
0054 static inline int test_fp_ctl(u32 fpc)
0055 {
0056     u32 orig_fpc;
0057     int rc;
0058 
0059     asm volatile(
0060         "   efpc    %1\n"
0061         "   sfpc    %2\n"
0062         "0: sfpc    %1\n"
0063         "   la  %0,0\n"
0064         "1:\n"
0065         EX_TABLE(0b,1b)
0066         : "=d" (rc), "=&d" (orig_fpc)
0067         : "d" (fpc), "0" (-EINVAL));
0068     return rc;
0069 }
0070 
0071 #define KERNEL_FPC      1
0072 #define KERNEL_VXR_V0V7     2
0073 #define KERNEL_VXR_V8V15    4
0074 #define KERNEL_VXR_V16V23   8
0075 #define KERNEL_VXR_V24V31   16
0076 
0077 #define KERNEL_VXR_LOW      (KERNEL_VXR_V0V7|KERNEL_VXR_V8V15)
0078 #define KERNEL_VXR_MID      (KERNEL_VXR_V8V15|KERNEL_VXR_V16V23)
0079 #define KERNEL_VXR_HIGH     (KERNEL_VXR_V16V23|KERNEL_VXR_V24V31)
0080 
0081 #define KERNEL_VXR      (KERNEL_VXR_LOW|KERNEL_VXR_HIGH)
0082 #define KERNEL_FPR      (KERNEL_FPC|KERNEL_VXR_V0V7)
0083 
0084 struct kernel_fpu;
0085 
0086 /*
0087  * Note the functions below must be called with preemption disabled.
0088  * Do not enable preemption before calling __kernel_fpu_end() to prevent
0089  * an corruption of an existing kernel FPU state.
0090  *
0091  * Prefer using the kernel_fpu_begin()/kernel_fpu_end() pair of functions.
0092  */
0093 void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags);
0094 void __kernel_fpu_end(struct kernel_fpu *state, u32 flags);
0095 
0096 
0097 static inline void kernel_fpu_begin(struct kernel_fpu *state, u32 flags)
0098 {
0099     preempt_disable();
0100     state->mask = S390_lowcore.fpu_flags;
0101     if (!test_cpu_flag(CIF_FPU))
0102         /* Save user space FPU state and register contents */
0103         save_fpu_regs();
0104     else if (state->mask & flags)
0105         /* Save FPU/vector register in-use by the kernel */
0106         __kernel_fpu_begin(state, flags);
0107     S390_lowcore.fpu_flags |= flags;
0108 }
0109 
0110 static inline void kernel_fpu_end(struct kernel_fpu *state, u32 flags)
0111 {
0112     S390_lowcore.fpu_flags = state->mask;
0113     if (state->mask & flags)
0114         /* Restore FPU/vector register in-use by the kernel */
0115         __kernel_fpu_end(state, flags);
0116     preempt_enable();
0117 }
0118 
0119 #endif /* _ASM_S390_FPU_API_H */