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