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
__stsch(struct subchannel_id schid,struct schib * addr)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
stsch(struct subchannel_id schid,struct schib * addr)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
__msch(struct subchannel_id schid,struct schib * addr)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
msch(struct subchannel_id schid,struct schib * addr)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
__tsch(struct subchannel_id schid,struct irb * addr)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
tsch(struct subchannel_id schid,struct irb * addr)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
__ssch(struct subchannel_id schid,union orb * addr)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
ssch(struct subchannel_id schid,union orb * addr)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
__csch(struct subchannel_id schid)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
csch(struct subchannel_id schid)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
tpi(struct tpi_info * addr)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
chsc(void * chsc_area)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
__rsch(struct subchannel_id schid)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
rsch(struct subchannel_id schid)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
__hsch(struct subchannel_id schid)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
hsch(struct subchannel_id schid)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
__xsch(struct subchannel_id schid)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
xsch(struct subchannel_id schid)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
__stcrw(struct crw * crw)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
_stcrw(struct crw * crw)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
stcrw(struct crw * crw)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