xref: /linux/arch/s390/kernel/fpu.c (revision 4b911a9690d72641879ea6d13cce1de31d346d79)
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(&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);
194