xref: /linux/arch/s390/kernel/fpu.c (revision e5c86679d5e864947a52fb31e45a425dea3e7fa9)
1 /*
2  * In-kernel vector facility support functions
3  *
4  * Copyright IBM Corp. 2015
5  * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
6  */
7 #include <linux/kernel.h>
8 #include <linux/cpu.h>
9 #include <linux/sched.h>
10 #include <asm/fpu/types.h>
11 #include <asm/fpu/api.h>
12 
13 asm(".include \"asm/vx-insn.h\"\n");
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" : "=m" (state->fpc));
26 
27 	if (!MACHINE_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 (!MACHINE_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