Merge branch 'address-masking'
[linux-2.6-microblaze.git] / arch / s390 / kernel / fpu.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * In-kernel vector facility support functions
4  *
5  * Copyright IBM Corp. 2015
6  * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
7  */
8 #include <linux/kernel.h>
9 #include <linux/cpu.h>
10 #include <linux/sched.h>
11 #include <asm/fpu.h>
12
13 void __kernel_fpu_begin(struct kernel_fpu *state, int flags)
14 {
15         __vector128 *vxrs = state->vxrs;
16         int mask;
17
18         /*
19          * Limit the save to the FPU/vector registers already
20          * in use by the previous context.
21          */
22         flags &= state->hdr.mask;
23         if (flags & KERNEL_FPC)
24                 fpu_stfpc(&state->hdr.fpc);
25         if (!cpu_has_vx()) {
26                 if (flags & KERNEL_VXR_LOW)
27                         save_fp_regs_vx(vxrs);
28                 return;
29         }
30         mask = flags & KERNEL_VXR;
31         if (mask == KERNEL_VXR) {
32                 vxrs += fpu_vstm(0, 15, vxrs);
33                 vxrs += fpu_vstm(16, 31, vxrs);
34                 return;
35         }
36         if (mask == KERNEL_VXR_MID) {
37                 vxrs += fpu_vstm(8, 23, vxrs);
38                 return;
39         }
40         mask = flags & KERNEL_VXR_LOW;
41         if (mask) {
42                 if (mask == KERNEL_VXR_LOW)
43                         vxrs += fpu_vstm(0, 15, vxrs);
44                 else if (mask == KERNEL_VXR_V0V7)
45                         vxrs += fpu_vstm(0, 7, vxrs);
46                 else
47                         vxrs += fpu_vstm(8, 15, vxrs);
48         }
49         mask = flags & KERNEL_VXR_HIGH;
50         if (mask) {
51                 if (mask == KERNEL_VXR_HIGH)
52                         vxrs += fpu_vstm(16, 31, vxrs);
53                 else if (mask == KERNEL_VXR_V16V23)
54                         vxrs += fpu_vstm(16, 23, vxrs);
55                 else
56                         vxrs += fpu_vstm(24, 31, vxrs);
57         }
58 }
59 EXPORT_SYMBOL(__kernel_fpu_begin);
60
61 void __kernel_fpu_end(struct kernel_fpu *state, int flags)
62 {
63         __vector128 *vxrs = state->vxrs;
64         int mask;
65
66         /*
67          * Limit the restore to the FPU/vector registers of the
68          * previous context that have been overwritten by the
69          * current context.
70          */
71         flags &= state->hdr.mask;
72         if (flags & KERNEL_FPC)
73                 fpu_lfpc(&state->hdr.fpc);
74         if (!cpu_has_vx()) {
75                 if (flags & KERNEL_VXR_LOW)
76                         load_fp_regs_vx(vxrs);
77                 return;
78         }
79         mask = flags & KERNEL_VXR;
80         if (mask == KERNEL_VXR) {
81                 vxrs += fpu_vlm(0, 15, vxrs);
82                 vxrs += fpu_vlm(16, 31, vxrs);
83                 return;
84         }
85         if (mask == KERNEL_VXR_MID) {
86                 vxrs += fpu_vlm(8, 23, vxrs);
87                 return;
88         }
89         mask = flags & KERNEL_VXR_LOW;
90         if (mask) {
91                 if (mask == KERNEL_VXR_LOW)
92                         vxrs += fpu_vlm(0, 15, vxrs);
93                 else if (mask == KERNEL_VXR_V0V7)
94                         vxrs += fpu_vlm(0, 7, vxrs);
95                 else
96                         vxrs += fpu_vlm(8, 15, vxrs);
97         }
98         mask = flags & KERNEL_VXR_HIGH;
99         if (mask) {
100                 if (mask == KERNEL_VXR_HIGH)
101                         vxrs += fpu_vlm(16, 31, vxrs);
102                 else if (mask == KERNEL_VXR_V16V23)
103                         vxrs += fpu_vlm(16, 23, vxrs);
104                 else
105                         vxrs += fpu_vlm(24, 31, vxrs);
106         }
107 }
108 EXPORT_SYMBOL(__kernel_fpu_end);
109
110 void load_fpu_state(struct fpu *state, int flags)
111 {
112         __vector128 *vxrs = &state->vxrs[0];
113         int mask;
114
115         if (flags & KERNEL_FPC)
116                 fpu_lfpc_safe(&state->fpc);
117         if (!cpu_has_vx()) {
118                 if (flags & KERNEL_VXR_V0V7)
119                         load_fp_regs_vx(state->vxrs);
120                 return;
121         }
122         mask = flags & KERNEL_VXR;
123         if (mask == KERNEL_VXR) {
124                 fpu_vlm(0, 15, &vxrs[0]);
125                 fpu_vlm(16, 31, &vxrs[16]);
126                 return;
127         }
128         if (mask == KERNEL_VXR_MID) {
129                 fpu_vlm(8, 23, &vxrs[8]);
130                 return;
131         }
132         mask = flags & KERNEL_VXR_LOW;
133         if (mask) {
134                 if (mask == KERNEL_VXR_LOW)
135                         fpu_vlm(0, 15, &vxrs[0]);
136                 else if (mask == KERNEL_VXR_V0V7)
137                         fpu_vlm(0, 7, &vxrs[0]);
138                 else
139                         fpu_vlm(8, 15, &vxrs[8]);
140         }
141         mask = flags & KERNEL_VXR_HIGH;
142         if (mask) {
143                 if (mask == KERNEL_VXR_HIGH)
144                         fpu_vlm(16, 31, &vxrs[16]);
145                 else if (mask == KERNEL_VXR_V16V23)
146                         fpu_vlm(16, 23, &vxrs[16]);
147                 else
148                         fpu_vlm(24, 31, &vxrs[24]);
149         }
150 }
151
152 void save_fpu_state(struct fpu *state, int flags)
153 {
154         __vector128 *vxrs = &state->vxrs[0];
155         int mask;
156
157         if (flags & KERNEL_FPC)
158                 fpu_stfpc(&state->fpc);
159         if (!cpu_has_vx()) {
160                 if (flags & KERNEL_VXR_LOW)
161                         save_fp_regs_vx(state->vxrs);
162                 return;
163         }
164         mask = flags & KERNEL_VXR;
165         if (mask == KERNEL_VXR) {
166                 fpu_vstm(0, 15, &vxrs[0]);
167                 fpu_vstm(16, 31, &vxrs[16]);
168                 return;
169         }
170         if (mask == KERNEL_VXR_MID) {
171                 fpu_vstm(8, 23, &vxrs[8]);
172                 return;
173         }
174         mask = flags & KERNEL_VXR_LOW;
175         if (mask) {
176                 if (mask == KERNEL_VXR_LOW)
177                         fpu_vstm(0, 15, &vxrs[0]);
178                 else if (mask == KERNEL_VXR_V0V7)
179                         fpu_vstm(0, 7, &vxrs[0]);
180                 else
181                         fpu_vstm(8, 15, &vxrs[8]);
182         }
183         mask = flags & KERNEL_VXR_HIGH;
184         if (mask) {
185                 if (mask == KERNEL_VXR_HIGH)
186                         fpu_vstm(16, 31, &vxrs[16]);
187                 else if (mask == KERNEL_VXR_V16V23)
188                         fpu_vstm(16, 23, &vxrs[16]);
189                 else
190                         fpu_vstm(24, 31, &vxrs[24]);
191         }
192 }
193 EXPORT_SYMBOL(save_fpu_state);