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