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