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 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_inline 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 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 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_inline 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 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 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 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 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_inline 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 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 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 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 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 175 int chsc(void *chsc_area) 176 { 177 typedef struct { char _[4096]; } addr_type; 178 int cc, exception; 179 180 exception = 1; 181 asm_inline 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 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 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 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 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 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 CC_IPM(cc) 257 : CC_OUT(cc, ccode) 258 : [r1] "d" (r1) 259 : CC_CLOBBER_LIST("1")); 260 return CC_TRANSFORM(ccode); 261 } 262 263 int xsch(struct subchannel_id schid) 264 { 265 int ccode; 266 267 ccode = __xsch(schid); 268 trace_s390_cio_xsch(schid, ccode); 269 270 return ccode; 271 } 272 273 static inline int __stcrw(struct crw *crw) 274 { 275 int ccode; 276 277 asm volatile( 278 " stcrw %[crw]\n" 279 CC_IPM(cc) 280 : CC_OUT(cc, ccode), [crw] "=Q" (*crw) 281 : 282 : CC_CLOBBER); 283 return CC_TRANSFORM(ccode); 284 } 285 286 static 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 298 int 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