xref: /kernel/linux/linux-6.6/drivers/s390/cio/ioasm.c (revision 62306a36)
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, addr);
41	trace_s390_cio_stsch(schid, addr, 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, addr);
70	trace_s390_cio_msch(schid, addr, 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, addr);
96	trace_s390_cio_tsch(schid, addr, 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, addr);
124	trace_s390_cio_ssch(schid, addr, 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);
151	trace_s390_cio_csch(schid, 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, 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_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);
214	trace_s390_cio_rsch(schid, 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);
240	trace_s390_cio_hsch(schid, 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);
267	trace_s390_cio_xsch(schid, 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, ccode);
304
305	return ccode;
306}
307