xref: /linux/drivers/s390/cio/ioasm.c (revision a514e6f8f5caa24413731bed54b322bd34d918dd)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Channel subsystem I/O instructions.
4  */
5 
6 #include <linux/export.h>
7 
8 #include <asm/asm-extable.h>
9 #include <asm/chpid.h>
10 #include <asm/schid.h>
11 #include <asm/asm.h>
12 #include <asm/crw.h>
13 
14 #include "ioasm.h"
15 #include "orb.h"
16 #include "cio.h"
17 #include "cio_inject.h"
18 
19 static inline int __stsch(struct subchannel_id schid, struct schib *addr)
20 {
21 	unsigned long r1 = *(unsigned int *)&schid;
22 	int ccode, exception;
23 
24 	exception = 1;
25 	asm volatile(
26 		"	lgr	1,%[r1]\n"
27 		"	stsch	%[addr]\n"
28 		"0:	lhi	%[exc],0\n"
29 		"1:\n"
30 		CC_IPM(cc)
31 		EX_TABLE(0b, 1b)
32 		: CC_OUT(cc, ccode), [addr] "=Q" (*addr), [exc] "+d" (exception)
33 		: [r1] "d" (r1)
34 		: CC_CLOBBER_LIST("1"));
35 	return exception ? -EIO : CC_TRANSFORM(ccode);
36 }
37 
38 int stsch(struct subchannel_id schid, struct schib *addr)
39 {
40 	int ccode;
41 
42 	ccode = __stsch(schid, addr);
43 	trace_s390_cio_stsch(schid, addr, ccode);
44 
45 	return ccode;
46 }
47 EXPORT_SYMBOL(stsch);
48 
49 static inline int __msch(struct subchannel_id schid, struct schib *addr)
50 {
51 	unsigned long r1 = *(unsigned int *)&schid;
52 	int ccode, exception;
53 
54 	exception = 1;
55 	asm volatile(
56 		"	lgr	1,%[r1]\n"
57 		"	msch	%[addr]\n"
58 		"0:	lhi	%[exc],0\n"
59 		"1:\n"
60 		CC_IPM(cc)
61 		EX_TABLE(0b, 1b)
62 		: CC_OUT(cc, ccode), [exc] "+d" (exception)
63 		: [r1] "d" (r1), [addr] "Q" (*addr)
64 		: CC_CLOBBER_LIST("1"));
65 	return exception ? -EIO : CC_TRANSFORM(ccode);
66 }
67 
68 int msch(struct subchannel_id schid, struct schib *addr)
69 {
70 	int ccode;
71 
72 	ccode = __msch(schid, addr);
73 	trace_s390_cio_msch(schid, addr, ccode);
74 
75 	return ccode;
76 }
77 
78 static inline int __tsch(struct subchannel_id schid, struct irb *addr)
79 {
80 	unsigned long r1 = *(unsigned int *)&schid;
81 	int ccode;
82 
83 	asm volatile(
84 		"	lgr	1,%[r1]\n"
85 		"	tsch	%[addr]\n"
86 		CC_IPM(cc)
87 		: CC_OUT(cc, ccode), [addr] "=Q" (*addr)
88 		: [r1] "d" (r1)
89 		: CC_CLOBBER_LIST("1"));
90 	return CC_TRANSFORM(ccode);
91 }
92 
93 int tsch(struct subchannel_id schid, struct irb *addr)
94 {
95 	int ccode;
96 
97 	ccode = __tsch(schid, addr);
98 	trace_s390_cio_tsch(schid, addr, ccode);
99 
100 	return ccode;
101 }
102 
103 static inline int __ssch(struct subchannel_id schid, union orb *addr)
104 {
105 	unsigned long r1 = *(unsigned int *)&schid;
106 	int ccode, exception;
107 
108 	exception = 1;
109 	asm volatile(
110 		"	lgr	1,%[r1]\n"
111 		"	ssch	%[addr]\n"
112 		"0:	lhi	%[exc],0\n"
113 		"1:\n"
114 		CC_IPM(cc)
115 		EX_TABLE(0b, 1b)
116 		: CC_OUT(cc, ccode), [exc] "+d" (exception)
117 		: [r1] "d" (r1), [addr] "Q" (*addr)
118 		: CC_CLOBBER_LIST("memory", "1"));
119 	return CC_TRANSFORM(ccode);
120 }
121 
122 int ssch(struct subchannel_id schid, union orb *addr)
123 {
124 	int ccode;
125 
126 	ccode = __ssch(schid, addr);
127 	trace_s390_cio_ssch(schid, addr, ccode);
128 
129 	return ccode;
130 }
131 EXPORT_SYMBOL(ssch);
132 
133 static inline int __csch(struct subchannel_id schid)
134 {
135 	unsigned long r1 = *(unsigned int *)&schid;
136 	int ccode;
137 
138 	asm volatile(
139 		"	lgr	1,%[r1]\n"
140 		"	csch\n"
141 		CC_IPM(cc)
142 		: CC_OUT(cc, ccode)
143 		: [r1] "d" (r1)
144 		: CC_CLOBBER_LIST("1"));
145 	return CC_TRANSFORM(ccode);
146 }
147 
148 int csch(struct subchannel_id schid)
149 {
150 	int ccode;
151 
152 	ccode = __csch(schid);
153 	trace_s390_cio_csch(schid, ccode);
154 
155 	return ccode;
156 }
157 EXPORT_SYMBOL(csch);
158 
159 int tpi(struct tpi_info *addr)
160 {
161 	int ccode;
162 
163 	asm volatile(
164 		"	tpi	%[addr]\n"
165 		CC_IPM(cc)
166 		: CC_OUT(cc, ccode), [addr] "=Q" (*addr)
167 		:
168 		: CC_CLOBBER);
169 	ccode = CC_TRANSFORM(ccode);
170 	trace_s390_cio_tpi(addr, ccode);
171 
172 	return ccode;
173 }
174 
175 int chsc(void *chsc_area)
176 {
177 	typedef struct { char _[4096]; } addr_type;
178 	int cc, exception;
179 
180 	exception = 1;
181 	asm volatile(
182 		"	.insn	rre,0xb25f0000,%[chsc_area],0\n"
183 		"0:	lhi	%[exc],0\n"
184 		"1:\n"
185 		CC_IPM(cc)
186 		EX_TABLE(0b, 1b)
187 		: CC_OUT(cc, cc), "+m" (*(addr_type *)chsc_area), [exc] "+d" (exception)
188 		: [chsc_area] "d" (chsc_area)
189 		: CC_CLOBBER);
190 	cc = exception ? -EIO : CC_TRANSFORM(cc);
191 	trace_s390_cio_chsc(chsc_area, cc);
192 
193 	return cc;
194 }
195 EXPORT_SYMBOL(chsc);
196 
197 static inline int __rsch(struct subchannel_id schid)
198 {
199 	unsigned long r1 = *(unsigned int *)&schid;
200 	int ccode;
201 
202 	asm volatile(
203 		"	lgr	1,%[r1]\n"
204 		"	rsch\n"
205 		CC_IPM(cc)
206 		: CC_OUT(cc, ccode)
207 		: [r1] "d" (r1)
208 		: CC_CLOBBER_LIST("memory", "1"));
209 	return CC_TRANSFORM(ccode);
210 }
211 
212 int rsch(struct subchannel_id schid)
213 {
214 	int ccode;
215 
216 	ccode = __rsch(schid);
217 	trace_s390_cio_rsch(schid, ccode);
218 
219 	return ccode;
220 }
221 
222 static inline int __hsch(struct subchannel_id schid)
223 {
224 	unsigned long r1 = *(unsigned int *)&schid;
225 	int ccode;
226 
227 	asm volatile(
228 		"	lgr	1,%[r1]\n"
229 		"	hsch\n"
230 		CC_IPM(cc)
231 		: CC_OUT(cc, ccode)
232 		: [r1] "d" (r1)
233 		: CC_CLOBBER_LIST("1"));
234 	return CC_TRANSFORM(ccode);
235 }
236 
237 int hsch(struct subchannel_id schid)
238 {
239 	int ccode;
240 
241 	ccode = __hsch(schid);
242 	trace_s390_cio_hsch(schid, ccode);
243 
244 	return ccode;
245 }
246 EXPORT_SYMBOL(hsch);
247 
248 static inline int __xsch(struct subchannel_id schid)
249 {
250 	unsigned long r1 = *(unsigned int *)&schid;
251 	int ccode;
252 
253 	asm volatile(
254 		"	lgr	1,%[r1]\n"
255 		"	xsch\n"
256 		"	ipm	%[cc]\n"
257 		"	srl	%[cc],28\n"
258 		: [cc] "=&d" (ccode)
259 		: [r1] "d" (r1)
260 		: "cc", "1");
261 	return CC_TRANSFORM(ccode);
262 }
263 
264 int xsch(struct subchannel_id schid)
265 {
266 	int ccode;
267 
268 	ccode = __xsch(schid);
269 	trace_s390_cio_xsch(schid, ccode);
270 
271 	return ccode;
272 }
273 
274 static inline int __stcrw(struct crw *crw)
275 {
276 	int ccode;
277 
278 	asm volatile(
279 		"	stcrw	%[crw]\n"
280 		CC_IPM(cc)
281 		: CC_OUT(cc, ccode), [crw] "=Q" (*crw)
282 		:
283 		: CC_CLOBBER);
284 	return CC_TRANSFORM(ccode);
285 }
286 
287 static inline int _stcrw(struct crw *crw)
288 {
289 #ifdef CONFIG_CIO_INJECT
290 	if (static_branch_unlikely(&cio_inject_enabled)) {
291 		if (stcrw_get_injected(crw) == 0)
292 			return 0;
293 	}
294 #endif
295 
296 	return __stcrw(crw);
297 }
298 
299 int stcrw(struct crw *crw)
300 {
301 	int ccode;
302 
303 	ccode = _stcrw(crw);
304 	trace_s390_cio_stcrw(crw, ccode);
305 
306 	return ccode;
307 }
308