1 // SPDX-License-Identifier: GPL-2.0
3 * Channel subsystem I/O instructions.
6 #include <linux/export.h>
8 #include <asm/asm-extable.h>
10 #include <asm/schid.h>
17 #include "cio_inject.h"
19 static inline int __stsch(struct subchannel_id schid
, struct schib
*addr
)
21 unsigned long r1
= *(unsigned int *)&schid
;
32 : CC_OUT(cc
, ccode
), [addr
] "=Q" (*addr
), [exc
] "+d" (exception
)
34 : CC_CLOBBER_LIST("1"));
35 return exception
? -EIO
: CC_TRANSFORM(ccode
);
38 int stsch(struct subchannel_id schid
, struct schib
*addr
)
42 ccode
= __stsch(schid
, addr
);
43 trace_s390_cio_stsch(schid
, addr
, ccode
);
49 static inline int __msch(struct subchannel_id schid
, struct schib
*addr
)
51 unsigned long r1
= *(unsigned int *)&schid
;
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
);
68 int msch(struct subchannel_id schid
, struct schib
*addr
)
72 ccode
= __msch(schid
, addr
);
73 trace_s390_cio_msch(schid
, addr
, ccode
);
78 static inline int __tsch(struct subchannel_id schid
, struct irb
*addr
)
80 unsigned long r1
= *(unsigned int *)&schid
;
87 : CC_OUT(cc
, ccode
), [addr
] "=Q" (*addr
)
89 : CC_CLOBBER_LIST("1"));
90 return CC_TRANSFORM(ccode
);
93 int tsch(struct subchannel_id schid
, struct irb
*addr
)
97 ccode
= __tsch(schid
, addr
);
98 trace_s390_cio_tsch(schid
, addr
, ccode
);
103 static inline int __ssch(struct subchannel_id schid
, union orb
*addr
)
105 unsigned long r1
= *(unsigned int *)&schid
;
106 int ccode
, exception
;
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
);
122 int ssch(struct subchannel_id schid
, union orb
*addr
)
126 ccode
= __ssch(schid
, addr
);
127 trace_s390_cio_ssch(schid
, addr
, ccode
);
133 static inline int __csch(struct subchannel_id schid
)
135 unsigned long r1
= *(unsigned int *)&schid
;
144 : CC_CLOBBER_LIST("1"));
145 return CC_TRANSFORM(ccode
);
148 int csch(struct subchannel_id schid
)
152 ccode
= __csch(schid
);
153 trace_s390_cio_csch(schid
, ccode
);
159 int tpi(struct tpi_info
*addr
)
166 : CC_OUT(cc
, ccode
), [addr
] "=Q" (*addr
)
169 ccode
= CC_TRANSFORM(ccode
);
170 trace_s390_cio_tpi(addr
, ccode
);
175 int chsc(void *chsc_area
)
177 typedef struct { char _
[4096]; } addr_type
;
182 " .insn rre,0xb25f0000,%[chsc_area],0\n"
187 : CC_OUT(cc
, cc
), "+m" (*(addr_type
*)chsc_area
), [exc
] "+d" (exception
)
188 : [chsc_area
] "d" (chsc_area
)
190 cc
= exception
? -EIO
: CC_TRANSFORM(cc
);
191 trace_s390_cio_chsc(chsc_area
, cc
);
197 static inline int __rsch(struct subchannel_id schid
)
199 unsigned long r1
= *(unsigned int *)&schid
;
208 : CC_CLOBBER_LIST("memory", "1"));
209 return CC_TRANSFORM(ccode
);
212 int rsch(struct subchannel_id schid
)
216 ccode
= __rsch(schid
);
217 trace_s390_cio_rsch(schid
, ccode
);
222 static inline int __hsch(struct subchannel_id schid
)
224 unsigned long r1
= *(unsigned int *)&schid
;
233 : CC_CLOBBER_LIST("1"));
234 return CC_TRANSFORM(ccode
);
237 int hsch(struct subchannel_id schid
)
241 ccode
= __hsch(schid
);
242 trace_s390_cio_hsch(schid
, ccode
);
248 static inline int __xsch(struct subchannel_id schid
)
250 unsigned long r1
= *(unsigned int *)&schid
;
261 return CC_TRANSFORM(ccode
);
264 int xsch(struct subchannel_id schid
)
268 ccode
= __xsch(schid
);
269 trace_s390_cio_xsch(schid
, ccode
);
274 static inline int __stcrw(struct crw
*crw
)
281 : CC_OUT(cc
, ccode
), [crw
] "=Q" (*crw
)
284 return CC_TRANSFORM(ccode
);
287 static inline int _stcrw(struct crw
*crw
)
289 #ifdef CONFIG_CIO_INJECT
290 if (static_branch_unlikely(&cio_inject_enabled
)) {
291 if (stcrw_get_injected(crw
) == 0)
299 int stcrw(struct crw
*crw
)
304 trace_s390_cio_stcrw(crw
, ccode
);