Commit | Line | Data |
---|---|---|
b0753902 HB |
1 | /* |
2 | * In-kernel FPU support functions | |
3 | * | |
04864808 HB |
4 | * |
5 | * Consider these guidelines before using in-kernel FPU functions: | |
6 | * | |
7 | * 1. Use kernel_fpu_begin() and kernel_fpu_end() to enclose all in-kernel | |
8 | * use of floating-point or vector registers and instructions. | |
9 | * | |
10 | * 2. For kernel_fpu_begin(), specify the vector register range you want to | |
11 | * use with the KERNEL_VXR_* constants. Consider these usage guidelines: | |
12 | * | |
13 | * a) If your function typically runs in process-context, use the lower | |
14 | * half of the vector registers, for example, specify KERNEL_VXR_LOW. | |
15 | * b) If your function typically runs in soft-irq or hard-irq context, | |
16 | * prefer using the upper half of the vector registers, for example, | |
17 | * specify KERNEL_VXR_HIGH. | |
18 | * | |
19 | * If you adhere to these guidelines, an interrupted process context | |
20 | * does not require to save and restore vector registers because of | |
21 | * disjoint register ranges. | |
22 | * | |
23 | * Also note that the __kernel_fpu_begin()/__kernel_fpu_end() functions | |
24 | * includes logic to save and restore up to 16 vector registers at once. | |
25 | * | |
26 | * 3. You can nest kernel_fpu_begin()/kernel_fpu_end() by using different | |
27 | * struct kernel_fpu states. Vector registers that are in use by outer | |
28 | * levels are saved and restored. You can minimize the save and restore | |
29 | * effort by choosing disjoint vector register ranges. | |
30 | * | |
31 | * 5. To use vector floating-point instructions, specify the KERNEL_FPC | |
32 | * flag to save and restore floating-point controls in addition to any | |
33 | * vector register range. | |
34 | * | |
35 | * 6. To use floating-point registers and instructions only, specify the | |
36 | * KERNEL_FPR flag. This flag triggers a save and restore of vector | |
37 | * registers V0 to V15 and floating-point controls. | |
38 | * | |
b0753902 HB |
39 | * Copyright IBM Corp. 2015 |
40 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | |
41 | */ | |
42 | ||
43 | #ifndef _ASM_S390_FPU_API_H | |
44 | #define _ASM_S390_FPU_API_H | |
45 | ||
04864808 HB |
46 | #include <linux/preempt.h> |
47 | ||
b0753902 HB |
48 | void save_fpu_regs(void); |
49 | ||
50 | static inline int test_fp_ctl(u32 fpc) | |
51 | { | |
52 | u32 orig_fpc; | |
53 | int rc; | |
54 | ||
55 | asm volatile( | |
56 | " efpc %1\n" | |
57 | " sfpc %2\n" | |
58 | "0: sfpc %1\n" | |
59 | " la %0,0\n" | |
60 | "1:\n" | |
61 | EX_TABLE(0b,1b) | |
bcf4dd5f | 62 | : "=d" (rc), "=&d" (orig_fpc) |
b0753902 HB |
63 | : "d" (fpc), "0" (-EINVAL)); |
64 | return rc; | |
65 | } | |
66 | ||
7f79695c MS |
67 | #define KERNEL_FPC 1 |
68 | #define KERNEL_VXR_V0V7 2 | |
69 | #define KERNEL_VXR_V8V15 4 | |
70 | #define KERNEL_VXR_V16V23 8 | |
71 | #define KERNEL_VXR_V24V31 16 | |
04864808 HB |
72 | |
73 | #define KERNEL_VXR_LOW (KERNEL_VXR_V0V7|KERNEL_VXR_V8V15) | |
74 | #define KERNEL_VXR_MID (KERNEL_VXR_V8V15|KERNEL_VXR_V16V23) | |
75 | #define KERNEL_VXR_HIGH (KERNEL_VXR_V16V23|KERNEL_VXR_V24V31) | |
76 | ||
7f79695c MS |
77 | #define KERNEL_VXR (KERNEL_VXR_LOW|KERNEL_VXR_HIGH) |
78 | #define KERNEL_FPR (KERNEL_FPC|KERNEL_VXR_V0V7) | |
04864808 HB |
79 | |
80 | struct kernel_fpu; | |
81 | ||
82 | /* | |
83 | * Note the functions below must be called with preemption disabled. | |
84 | * Do not enable preemption before calling __kernel_fpu_end() to prevent | |
85 | * an corruption of an existing kernel FPU state. | |
86 | * | |
87 | * Prefer using the kernel_fpu_begin()/kernel_fpu_end() pair of functions. | |
88 | */ | |
89 | void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags); | |
7f79695c | 90 | void __kernel_fpu_end(struct kernel_fpu *state, u32 flags); |
04864808 HB |
91 | |
92 | ||
93 | static inline void kernel_fpu_begin(struct kernel_fpu *state, u32 flags) | |
94 | { | |
95 | preempt_disable(); | |
7f79695c MS |
96 | state->mask = S390_lowcore.fpu_flags; |
97 | if (!test_cpu_flag(CIF_FPU)) | |
98 | /* Save user space FPU state and register contents */ | |
99 | save_fpu_regs(); | |
100 | else if (state->mask & flags) | |
101 | /* Save FPU/vector register in-use by the kernel */ | |
102 | __kernel_fpu_begin(state, flags); | |
103 | S390_lowcore.fpu_flags |= flags; | |
04864808 HB |
104 | } |
105 | ||
7f79695c | 106 | static inline void kernel_fpu_end(struct kernel_fpu *state, u32 flags) |
04864808 | 107 | { |
7f79695c MS |
108 | S390_lowcore.fpu_flags = state->mask; |
109 | if (state->mask & flags) | |
110 | /* Restore FPU/vector register in-use by the kernel */ | |
111 | __kernel_fpu_end(state, flags); | |
04864808 HB |
112 | preempt_enable(); |
113 | } | |
114 | ||
b0753902 | 115 | #endif /* _ASM_S390_FPU_API_H */ |