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