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 18 static 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 36 int 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 } 45 EXPORT_SYMBOL(stsch); 46 47 static 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 65 int 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 75 static 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 91 int 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 101 static 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 119 int 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 } 128 EXPORT_SYMBOL(ssch); 129 130 static 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 146 int 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 } 155 EXPORT_SYMBOL(csch); 156 157 int 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 173 int 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 } 191 EXPORT_SYMBOL(chsc); 192 193 static 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 209 int 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 219 static 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 235 int 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 } 244 EXPORT_SYMBOL(hsch); 245 246 static 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 262 int 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 272 static 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 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