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/chpid.h> 9 #include <asm/schid.h> 10 #include <asm/crw.h> 11 12 #include "ioasm.h" 13 #include "orb.h" 14 #include "cio.h" 15 #include "cio_inject.h" 16 17 static inline int __stsch(struct subchannel_id schid, struct schib *addr) 18 { 19 unsigned long r1 = *(unsigned int *)&schid; 20 int ccode = -EIO; 21 22 asm volatile( 23 " lgr 1,%[r1]\n" 24 " stsch %[addr]\n" 25 "0: ipm %[cc]\n" 26 " srl %[cc],28\n" 27 "1:\n" 28 EX_TABLE(0b, 1b) 29 : [cc] "+&d" (ccode), [addr] "=Q" (*addr) 30 : [r1] "d" (r1) 31 : "cc", "1"); 32 return ccode; 33 } 34 35 int stsch(struct subchannel_id schid, struct schib *addr) 36 { 37 int ccode; 38 39 ccode = __stsch(schid, addr); 40 trace_s390_cio_stsch(schid, addr, ccode); 41 42 return ccode; 43 } 44 EXPORT_SYMBOL(stsch); 45 46 static inline int __msch(struct subchannel_id schid, struct schib *addr) 47 { 48 unsigned long r1 = *(unsigned int *)&schid; 49 int ccode = -EIO; 50 51 asm volatile( 52 " lgr 1,%[r1]\n" 53 " msch %[addr]\n" 54 "0: ipm %[cc]\n" 55 " srl %[cc],28\n" 56 "1:\n" 57 EX_TABLE(0b, 1b) 58 : [cc] "+&d" (ccode) 59 : [r1] "d" (r1), [addr] "Q" (*addr) 60 : "cc", "1"); 61 return ccode; 62 } 63 64 int msch(struct subchannel_id schid, struct schib *addr) 65 { 66 int ccode; 67 68 ccode = __msch(schid, addr); 69 trace_s390_cio_msch(schid, addr, ccode); 70 71 return ccode; 72 } 73 74 static inline int __tsch(struct subchannel_id schid, struct irb *addr) 75 { 76 unsigned long r1 = *(unsigned int *)&schid; 77 int ccode; 78 79 asm volatile( 80 " lgr 1,%[r1]\n" 81 " tsch %[addr]\n" 82 " ipm %[cc]\n" 83 " srl %[cc],28" 84 : [cc] "=&d" (ccode), [addr] "=Q" (*addr) 85 : [r1] "d" (r1) 86 : "cc", "1"); 87 return ccode; 88 } 89 90 int tsch(struct subchannel_id schid, struct irb *addr) 91 { 92 int ccode; 93 94 ccode = __tsch(schid, addr); 95 trace_s390_cio_tsch(schid, addr, ccode); 96 97 return ccode; 98 } 99 100 static inline int __ssch(struct subchannel_id schid, union orb *addr) 101 { 102 unsigned long r1 = *(unsigned int *)&schid; 103 int ccode = -EIO; 104 105 asm volatile( 106 " lgr 1,%[r1]\n" 107 " ssch %[addr]\n" 108 "0: ipm %[cc]\n" 109 " srl %[cc],28\n" 110 "1:\n" 111 EX_TABLE(0b, 1b) 112 : [cc] "+&d" (ccode) 113 : [r1] "d" (r1), [addr] "Q" (*addr) 114 : "cc", "memory", "1"); 115 return ccode; 116 } 117 118 int ssch(struct subchannel_id schid, union orb *addr) 119 { 120 int ccode; 121 122 ccode = __ssch(schid, addr); 123 trace_s390_cio_ssch(schid, addr, ccode); 124 125 return ccode; 126 } 127 EXPORT_SYMBOL(ssch); 128 129 static inline int __csch(struct subchannel_id schid) 130 { 131 unsigned long r1 = *(unsigned int *)&schid; 132 int ccode; 133 134 asm volatile( 135 " lgr 1,%[r1]\n" 136 " csch\n" 137 " ipm %[cc]\n" 138 " srl %[cc],28\n" 139 : [cc] "=&d" (ccode) 140 : [r1] "d" (r1) 141 : "cc", "1"); 142 return ccode; 143 } 144 145 int csch(struct subchannel_id schid) 146 { 147 int ccode; 148 149 ccode = __csch(schid); 150 trace_s390_cio_csch(schid, ccode); 151 152 return ccode; 153 } 154 EXPORT_SYMBOL(csch); 155 156 int tpi(struct tpi_info *addr) 157 { 158 int ccode; 159 160 asm volatile( 161 " tpi %[addr]\n" 162 " ipm %[cc]\n" 163 " srl %[cc],28" 164 : [cc] "=&d" (ccode), [addr] "=Q" (*addr) 165 : 166 : "cc"); 167 trace_s390_cio_tpi(addr, ccode); 168 169 return ccode; 170 } 171 172 int chsc(void *chsc_area) 173 { 174 typedef struct { char _[4096]; } addr_type; 175 int cc = -EIO; 176 177 asm volatile( 178 " .insn rre,0xb25f0000,%[chsc_area],0\n" 179 "0: ipm %[cc]\n" 180 " srl %[cc],28\n" 181 "1:\n" 182 EX_TABLE(0b, 1b) 183 : [cc] "+&d" (cc), "+m" (*(addr_type *)chsc_area) 184 : [chsc_area] "d" (chsc_area) 185 : "cc"); 186 trace_s390_cio_chsc(chsc_area, cc); 187 188 return cc; 189 } 190 EXPORT_SYMBOL(chsc); 191 192 static inline int __rsch(struct subchannel_id schid) 193 { 194 unsigned long r1 = *(unsigned int *)&schid; 195 int ccode; 196 197 asm volatile( 198 " lgr 1,%[r1]\n" 199 " rsch\n" 200 " ipm %[cc]\n" 201 " srl %[cc],28\n" 202 : [cc] "=&d" (ccode) 203 : [r1] "d" (r1) 204 : "cc", "memory", "1"); 205 return ccode; 206 } 207 208 int rsch(struct subchannel_id schid) 209 { 210 int ccode; 211 212 ccode = __rsch(schid); 213 trace_s390_cio_rsch(schid, ccode); 214 215 return ccode; 216 } 217 218 static inline int __hsch(struct subchannel_id schid) 219 { 220 unsigned long r1 = *(unsigned int *)&schid; 221 int ccode; 222 223 asm volatile( 224 " lgr 1,%[r1]\n" 225 " hsch\n" 226 " ipm %[cc]\n" 227 " srl %[cc],28\n" 228 : [cc] "=&d" (ccode) 229 : [r1] "d" (r1) 230 : "cc", "1"); 231 return ccode; 232 } 233 234 int hsch(struct subchannel_id schid) 235 { 236 int ccode; 237 238 ccode = __hsch(schid); 239 trace_s390_cio_hsch(schid, ccode); 240 241 return ccode; 242 } 243 EXPORT_SYMBOL(hsch); 244 245 static inline int __xsch(struct subchannel_id schid) 246 { 247 unsigned long r1 = *(unsigned int *)&schid; 248 int ccode; 249 250 asm volatile( 251 " lgr 1,%[r1]\n" 252 " xsch\n" 253 " ipm %[cc]\n" 254 " srl %[cc],28\n" 255 : [cc] "=&d" (ccode) 256 : [r1] "d" (r1) 257 : "cc", "1"); 258 return ccode; 259 } 260 261 int xsch(struct subchannel_id schid) 262 { 263 int ccode; 264 265 ccode = __xsch(schid); 266 trace_s390_cio_xsch(schid, ccode); 267 268 return ccode; 269 } 270 271 static inline int __stcrw(struct crw *crw) 272 { 273 int ccode; 274 275 asm volatile( 276 " stcrw %[crw]\n" 277 " ipm %[cc]\n" 278 " srl %[cc],28\n" 279 : [cc] "=&d" (ccode), [crw] "=Q" (*crw) 280 : 281 : "cc"); 282 return ccode; 283 } 284 285 static inline int _stcrw(struct crw *crw) 286 { 287 #ifdef CONFIG_CIO_INJECT 288 if (static_branch_unlikely(&cio_inject_enabled)) { 289 if (stcrw_get_injected(crw) == 0) 290 return 0; 291 } 292 #endif 293 294 return __stcrw(crw); 295 } 296 297 int stcrw(struct crw *crw) 298 { 299 int ccode; 300 301 ccode = _stcrw(crw); 302 trace_s390_cio_stcrw(crw, ccode); 303 304 return ccode; 305 } 306