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 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 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 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 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 " 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 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 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 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 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