zonefs: convert zonefs to use the new mount api
[sfrench/cifs-2.6.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/types.h>
12 #include <asm/fpu/api.h>
13 #include <asm/vx-insn.h>
14
15 void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags)
16 {
17         /*
18          * Limit the save to the FPU/vector registers already
19          * in use by the previous context
20          */
21         flags &= state->mask;
22
23         if (flags & KERNEL_FPC)
24                 /* Save floating point control */
25                 asm volatile("stfpc %0" : "=Q" (state->fpc));
26
27         if (!cpu_has_vx()) {
28                 if (flags & KERNEL_VXR_V0V7) {
29                         /* Save floating-point registers */
30                         asm volatile("std 0,%0" : "=Q" (state->fprs[0]));
31                         asm volatile("std 1,%0" : "=Q" (state->fprs[1]));
32                         asm volatile("std 2,%0" : "=Q" (state->fprs[2]));
33                         asm volatile("std 3,%0" : "=Q" (state->fprs[3]));
34                         asm volatile("std 4,%0" : "=Q" (state->fprs[4]));
35                         asm volatile("std 5,%0" : "=Q" (state->fprs[5]));
36                         asm volatile("std 6,%0" : "=Q" (state->fprs[6]));
37                         asm volatile("std 7,%0" : "=Q" (state->fprs[7]));
38                         asm volatile("std 8,%0" : "=Q" (state->fprs[8]));
39                         asm volatile("std 9,%0" : "=Q" (state->fprs[9]));
40                         asm volatile("std 10,%0" : "=Q" (state->fprs[10]));
41                         asm volatile("std 11,%0" : "=Q" (state->fprs[11]));
42                         asm volatile("std 12,%0" : "=Q" (state->fprs[12]));
43                         asm volatile("std 13,%0" : "=Q" (state->fprs[13]));
44                         asm volatile("std 14,%0" : "=Q" (state->fprs[14]));
45                         asm volatile("std 15,%0" : "=Q" (state->fprs[15]));
46                 }
47                 return;
48         }
49
50         /* Test and save vector registers */
51         asm volatile (
52                 /*
53                  * Test if any vector register must be saved and, if so,
54                  * test if all register can be saved.
55                  */
56                 "       la      1,%[vxrs]\n"    /* load save area */
57                 "       tmll    %[m],30\n"      /* KERNEL_VXR */
58                 "       jz      7f\n"           /* no work -> done */
59                 "       jo      5f\n"           /* -> save V0..V31 */
60                 /*
61                  * Test for special case KERNEL_FPU_MID only. In this
62                  * case a vstm V8..V23 is the best instruction
63                  */
64                 "       chi     %[m],12\n"      /* KERNEL_VXR_MID */
65                 "       jne     0f\n"           /* -> save V8..V23 */
66                 "       VSTM    8,23,128,1\n"   /* vstm %v8,%v23,128(%r1) */
67                 "       j       7f\n"
68                 /* Test and save the first half of 16 vector registers */
69                 "0:     tmll    %[m],6\n"       /* KERNEL_VXR_LOW */
70                 "       jz      3f\n"           /* -> KERNEL_VXR_HIGH */
71                 "       jo      2f\n"           /* 11 -> save V0..V15 */
72                 "       brc     2,1f\n"         /* 10 -> save V8..V15 */
73                 "       VSTM    0,7,0,1\n"      /* vstm %v0,%v7,0(%r1) */
74                 "       j       3f\n"
75                 "1:     VSTM    8,15,128,1\n"   /* vstm %v8,%v15,128(%r1) */
76                 "       j       3f\n"
77                 "2:     VSTM    0,15,0,1\n"     /* vstm %v0,%v15,0(%r1) */
78                 /* Test and save the second half of 16 vector registers */
79                 "3:     tmll    %[m],24\n"      /* KERNEL_VXR_HIGH */
80                 "       jz      7f\n"
81                 "       jo      6f\n"           /* 11 -> save V16..V31 */
82                 "       brc     2,4f\n"         /* 10 -> save V24..V31 */
83                 "       VSTM    16,23,256,1\n"  /* vstm %v16,%v23,256(%r1) */
84                 "       j       7f\n"
85                 "4:     VSTM    24,31,384,1\n"  /* vstm %v24,%v31,384(%r1) */
86                 "       j       7f\n"
87                 "5:     VSTM    0,15,0,1\n"     /* vstm %v0,%v15,0(%r1) */
88                 "6:     VSTM    16,31,256,1\n"  /* vstm %v16,%v31,256(%r1) */
89                 "7:"
90                 : [vxrs] "=Q" (*(struct vx_array *) &state->vxrs)
91                 : [m] "d" (flags)
92                 : "1", "cc");
93 }
94 EXPORT_SYMBOL(__kernel_fpu_begin);
95
96 void __kernel_fpu_end(struct kernel_fpu *state, u32 flags)
97 {
98         /*
99          * Limit the restore to the FPU/vector registers of the
100          * previous context that have been overwritte by the
101          * current context
102          */
103         flags &= state->mask;
104
105         if (flags & KERNEL_FPC)
106                 /* Restore floating-point controls */
107                 asm volatile("lfpc %0" : : "Q" (state->fpc));
108
109         if (!cpu_has_vx()) {
110                 if (flags & KERNEL_VXR_V0V7) {
111                         /* Restore floating-point registers */
112                         asm volatile("ld 0,%0" : : "Q" (state->fprs[0]));
113                         asm volatile("ld 1,%0" : : "Q" (state->fprs[1]));
114                         asm volatile("ld 2,%0" : : "Q" (state->fprs[2]));
115                         asm volatile("ld 3,%0" : : "Q" (state->fprs[3]));
116                         asm volatile("ld 4,%0" : : "Q" (state->fprs[4]));
117                         asm volatile("ld 5,%0" : : "Q" (state->fprs[5]));
118                         asm volatile("ld 6,%0" : : "Q" (state->fprs[6]));
119                         asm volatile("ld 7,%0" : : "Q" (state->fprs[7]));
120                         asm volatile("ld 8,%0" : : "Q" (state->fprs[8]));
121                         asm volatile("ld 9,%0" : : "Q" (state->fprs[9]));
122                         asm volatile("ld 10,%0" : : "Q" (state->fprs[10]));
123                         asm volatile("ld 11,%0" : : "Q" (state->fprs[11]));
124                         asm volatile("ld 12,%0" : : "Q" (state->fprs[12]));
125                         asm volatile("ld 13,%0" : : "Q" (state->fprs[13]));
126                         asm volatile("ld 14,%0" : : "Q" (state->fprs[14]));
127                         asm volatile("ld 15,%0" : : "Q" (state->fprs[15]));
128                 }
129                 return;
130         }
131
132         /* Test and restore (load) vector registers */
133         asm volatile (
134                 /*
135                  * Test if any vector register must be loaded and, if so,
136                  * test if all registers can be loaded at once.
137                  */
138                 "       la      1,%[vxrs]\n"    /* load restore area */
139                 "       tmll    %[m],30\n"      /* KERNEL_VXR */
140                 "       jz      7f\n"           /* no work -> done */
141                 "       jo      5f\n"           /* -> restore V0..V31 */
142                 /*
143                  * Test for special case KERNEL_FPU_MID only. In this
144                  * case a vlm V8..V23 is the best instruction
145                  */
146                 "       chi     %[m],12\n"      /* KERNEL_VXR_MID */
147                 "       jne     0f\n"           /* -> restore V8..V23 */
148                 "       VLM     8,23,128,1\n"   /* vlm %v8,%v23,128(%r1) */
149                 "       j       7f\n"
150                 /* Test and restore the first half of 16 vector registers */
151                 "0:     tmll    %[m],6\n"       /* KERNEL_VXR_LOW */
152                 "       jz      3f\n"           /* -> KERNEL_VXR_HIGH */
153                 "       jo      2f\n"           /* 11 -> restore V0..V15 */
154                 "       brc     2,1f\n"         /* 10 -> restore V8..V15 */
155                 "       VLM     0,7,0,1\n"      /* vlm %v0,%v7,0(%r1) */
156                 "       j       3f\n"
157                 "1:     VLM     8,15,128,1\n"   /* vlm %v8,%v15,128(%r1) */
158                 "       j       3f\n"
159                 "2:     VLM     0,15,0,1\n"     /* vlm %v0,%v15,0(%r1) */
160                 /* Test and restore the second half of 16 vector registers */
161                 "3:     tmll    %[m],24\n"      /* KERNEL_VXR_HIGH */
162                 "       jz      7f\n"
163                 "       jo      6f\n"           /* 11 -> restore V16..V31 */
164                 "       brc     2,4f\n"         /* 10 -> restore V24..V31 */
165                 "       VLM     16,23,256,1\n"  /* vlm %v16,%v23,256(%r1) */
166                 "       j       7f\n"
167                 "4:     VLM     24,31,384,1\n"  /* vlm %v24,%v31,384(%r1) */
168                 "       j       7f\n"
169                 "5:     VLM     0,15,0,1\n"     /* vlm %v0,%v15,0(%r1) */
170                 "6:     VLM     16,31,256,1\n"  /* vlm %v16,%v31,256(%r1) */
171                 "7:"
172                 : [vxrs] "=Q" (*(struct vx_array *) &state->vxrs)
173                 : [m] "d" (flags)
174                 : "1", "cc");
175 }
176 EXPORT_SYMBOL(__kernel_fpu_end);
177
178 void __load_fpu_regs(void)
179 {
180         unsigned long *regs = current->thread.fpu.regs;
181         struct fpu *state = &current->thread.fpu;
182
183         sfpc_safe(state->fpc);
184         if (likely(cpu_has_vx())) {
185                 asm volatile("lgr       1,%0\n"
186                              "VLM       0,15,0,1\n"
187                              "VLM       16,31,256,1\n"
188                              :
189                              : "d" (regs)
190                              : "1", "cc", "memory");
191         } else {
192                 asm volatile("ld 0,%0" : : "Q" (regs[0]));
193                 asm volatile("ld 1,%0" : : "Q" (regs[1]));
194                 asm volatile("ld 2,%0" : : "Q" (regs[2]));
195                 asm volatile("ld 3,%0" : : "Q" (regs[3]));
196                 asm volatile("ld 4,%0" : : "Q" (regs[4]));
197                 asm volatile("ld 5,%0" : : "Q" (regs[5]));
198                 asm volatile("ld 6,%0" : : "Q" (regs[6]));
199                 asm volatile("ld 7,%0" : : "Q" (regs[7]));
200                 asm volatile("ld 8,%0" : : "Q" (regs[8]));
201                 asm volatile("ld 9,%0" : : "Q" (regs[9]));
202                 asm volatile("ld 10,%0" : : "Q" (regs[10]));
203                 asm volatile("ld 11,%0" : : "Q" (regs[11]));
204                 asm volatile("ld 12,%0" : : "Q" (regs[12]));
205                 asm volatile("ld 13,%0" : : "Q" (regs[13]));
206                 asm volatile("ld 14,%0" : : "Q" (regs[14]));
207                 asm volatile("ld 15,%0" : : "Q" (regs[15]));
208         }
209         clear_cpu_flag(CIF_FPU);
210 }
211
212 void load_fpu_regs(void)
213 {
214         raw_local_irq_disable();
215         __load_fpu_regs();
216         raw_local_irq_enable();
217 }
218 EXPORT_SYMBOL(load_fpu_regs);
219
220 void save_fpu_regs(void)
221 {
222         unsigned long flags, *regs;
223         struct fpu *state;
224
225         local_irq_save(flags);
226
227         if (test_cpu_flag(CIF_FPU))
228                 goto out;
229
230         state = &current->thread.fpu;
231         regs = current->thread.fpu.regs;
232
233         asm volatile("stfpc %0" : "=Q" (state->fpc));
234         if (likely(cpu_has_vx())) {
235                 asm volatile("lgr       1,%0\n"
236                              "VSTM      0,15,0,1\n"
237                              "VSTM      16,31,256,1\n"
238                              :
239                              : "d" (regs)
240                              : "1", "cc", "memory");
241         } else {
242                 asm volatile("std 0,%0" : "=Q" (regs[0]));
243                 asm volatile("std 1,%0" : "=Q" (regs[1]));
244                 asm volatile("std 2,%0" : "=Q" (regs[2]));
245                 asm volatile("std 3,%0" : "=Q" (regs[3]));
246                 asm volatile("std 4,%0" : "=Q" (regs[4]));
247                 asm volatile("std 5,%0" : "=Q" (regs[5]));
248                 asm volatile("std 6,%0" : "=Q" (regs[6]));
249                 asm volatile("std 7,%0" : "=Q" (regs[7]));
250                 asm volatile("std 8,%0" : "=Q" (regs[8]));
251                 asm volatile("std 9,%0" : "=Q" (regs[9]));
252                 asm volatile("std 10,%0" : "=Q" (regs[10]));
253                 asm volatile("std 11,%0" : "=Q" (regs[11]));
254                 asm volatile("std 12,%0" : "=Q" (regs[12]));
255                 asm volatile("std 13,%0" : "=Q" (regs[13]));
256                 asm volatile("std 14,%0" : "=Q" (regs[14]));
257                 asm volatile("std 15,%0" : "=Q" (regs[15]));
258         }
259         set_cpu_flag(CIF_FPU);
260 out:
261         local_irq_restore(flags);
262 }
263 EXPORT_SYMBOL(save_fpu_regs);