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
18static 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
36int stsch(struct subchannel_id schid, struct schib *addr)
37{
38 int ccode;
39
40 ccode = __stsch(schid: schid, addr);
41 trace_s390_cio_stsch(schid: schid, schib: addr, cc: ccode);
42
43 return ccode;
44}
45EXPORT_SYMBOL(stsch);
46
47static 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
65int msch(struct subchannel_id schid, struct schib *addr)
66{
67 int ccode;
68
69 ccode = __msch(schid: schid, addr);
70 trace_s390_cio_msch(schid: schid, schib: addr, cc: ccode);
71
72 return ccode;
73}
74
75static 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
91int tsch(struct subchannel_id schid, struct irb *addr)
92{
93 int ccode;
94
95 ccode = __tsch(schid: schid, addr);
96 trace_s390_cio_tsch(schid: schid, irb: addr, cc: ccode);
97
98 return ccode;
99}
100
101static 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
119int ssch(struct subchannel_id schid, union orb *addr)
120{
121 int ccode;
122
123 ccode = __ssch(schid: schid, addr);
124 trace_s390_cio_ssch(schid: schid, orb: addr, cc: ccode);
125
126 return ccode;
127}
128EXPORT_SYMBOL(ssch);
129
130static 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
146int csch(struct subchannel_id schid)
147{
148 int ccode;
149
150 ccode = __csch(schid: schid);
151 trace_s390_cio_csch(schid: schid, cc: ccode);
152
153 return ccode;
154}
155EXPORT_SYMBOL(csch);
156
157int 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, cc: ccode);
169
170 return ccode;
171}
172
173int 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: chsc_area, cc);
188
189 return cc;
190}
191EXPORT_SYMBOL(chsc);
192
193static 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
209int rsch(struct subchannel_id schid)
210{
211 int ccode;
212
213 ccode = __rsch(schid: schid);
214 trace_s390_cio_rsch(schid: schid, cc: ccode);
215
216 return ccode;
217}
218
219static 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
235int hsch(struct subchannel_id schid)
236{
237 int ccode;
238
239 ccode = __hsch(schid: schid);
240 trace_s390_cio_hsch(schid: schid, cc: ccode);
241
242 return ccode;
243}
244EXPORT_SYMBOL(hsch);
245
246static 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
262int xsch(struct subchannel_id schid)
263{
264 int ccode;
265
266 ccode = __xsch(schid: schid);
267 trace_s390_cio_xsch(schid: schid, cc: ccode);
268
269 return ccode;
270}
271
272static 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
286static 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
298int stcrw(struct crw *crw)
299{
300 int ccode;
301
302 ccode = _stcrw(crw);
303 trace_s390_cio_stcrw(crw, cc: ccode);
304
305 return ccode;
306}
307

source code of linux/drivers/s390/cio/ioasm.c