162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Channel subsystem I/O instructions. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/export.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <asm/asm-extable.h> 962306a36Sopenharmony_ci#include <asm/chpid.h> 1062306a36Sopenharmony_ci#include <asm/schid.h> 1162306a36Sopenharmony_ci#include <asm/crw.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "ioasm.h" 1462306a36Sopenharmony_ci#include "orb.h" 1562306a36Sopenharmony_ci#include "cio.h" 1662306a36Sopenharmony_ci#include "cio_inject.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic inline int __stsch(struct subchannel_id schid, struct schib *addr) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci unsigned long r1 = *(unsigned int *)&schid; 2162306a36Sopenharmony_ci int ccode = -EIO; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci asm volatile( 2462306a36Sopenharmony_ci " lgr 1,%[r1]\n" 2562306a36Sopenharmony_ci " stsch %[addr]\n" 2662306a36Sopenharmony_ci "0: ipm %[cc]\n" 2762306a36Sopenharmony_ci " srl %[cc],28\n" 2862306a36Sopenharmony_ci "1:\n" 2962306a36Sopenharmony_ci EX_TABLE(0b, 1b) 3062306a36Sopenharmony_ci : [cc] "+&d" (ccode), [addr] "=Q" (*addr) 3162306a36Sopenharmony_ci : [r1] "d" (r1) 3262306a36Sopenharmony_ci : "cc", "1"); 3362306a36Sopenharmony_ci return ccode; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciint stsch(struct subchannel_id schid, struct schib *addr) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci int ccode; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci ccode = __stsch(schid, addr); 4162306a36Sopenharmony_ci trace_s390_cio_stsch(schid, addr, ccode); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return ccode; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ciEXPORT_SYMBOL(stsch); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic inline int __msch(struct subchannel_id schid, struct schib *addr) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci unsigned long r1 = *(unsigned int *)&schid; 5062306a36Sopenharmony_ci int ccode = -EIO; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci asm volatile( 5362306a36Sopenharmony_ci " lgr 1,%[r1]\n" 5462306a36Sopenharmony_ci " msch %[addr]\n" 5562306a36Sopenharmony_ci "0: ipm %[cc]\n" 5662306a36Sopenharmony_ci " srl %[cc],28\n" 5762306a36Sopenharmony_ci "1:\n" 5862306a36Sopenharmony_ci EX_TABLE(0b, 1b) 5962306a36Sopenharmony_ci : [cc] "+&d" (ccode) 6062306a36Sopenharmony_ci : [r1] "d" (r1), [addr] "Q" (*addr) 6162306a36Sopenharmony_ci : "cc", "1"); 6262306a36Sopenharmony_ci return ccode; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciint msch(struct subchannel_id schid, struct schib *addr) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci int ccode; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci ccode = __msch(schid, addr); 7062306a36Sopenharmony_ci trace_s390_cio_msch(schid, addr, ccode); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return ccode; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic inline int __tsch(struct subchannel_id schid, struct irb *addr) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci unsigned long r1 = *(unsigned int *)&schid; 7862306a36Sopenharmony_ci int ccode; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci asm volatile( 8162306a36Sopenharmony_ci " lgr 1,%[r1]\n" 8262306a36Sopenharmony_ci " tsch %[addr]\n" 8362306a36Sopenharmony_ci " ipm %[cc]\n" 8462306a36Sopenharmony_ci " srl %[cc],28" 8562306a36Sopenharmony_ci : [cc] "=&d" (ccode), [addr] "=Q" (*addr) 8662306a36Sopenharmony_ci : [r1] "d" (r1) 8762306a36Sopenharmony_ci : "cc", "1"); 8862306a36Sopenharmony_ci return ccode; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciint tsch(struct subchannel_id schid, struct irb *addr) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci int ccode; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci ccode = __tsch(schid, addr); 9662306a36Sopenharmony_ci trace_s390_cio_tsch(schid, addr, ccode); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return ccode; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic inline int __ssch(struct subchannel_id schid, union orb *addr) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci unsigned long r1 = *(unsigned int *)&schid; 10462306a36Sopenharmony_ci int ccode = -EIO; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci asm volatile( 10762306a36Sopenharmony_ci " lgr 1,%[r1]\n" 10862306a36Sopenharmony_ci " ssch %[addr]\n" 10962306a36Sopenharmony_ci "0: ipm %[cc]\n" 11062306a36Sopenharmony_ci " srl %[cc],28\n" 11162306a36Sopenharmony_ci "1:\n" 11262306a36Sopenharmony_ci EX_TABLE(0b, 1b) 11362306a36Sopenharmony_ci : [cc] "+&d" (ccode) 11462306a36Sopenharmony_ci : [r1] "d" (r1), [addr] "Q" (*addr) 11562306a36Sopenharmony_ci : "cc", "memory", "1"); 11662306a36Sopenharmony_ci return ccode; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ciint ssch(struct subchannel_id schid, union orb *addr) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci int ccode; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci ccode = __ssch(schid, addr); 12462306a36Sopenharmony_ci trace_s390_cio_ssch(schid, addr, ccode); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return ccode; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ciEXPORT_SYMBOL(ssch); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic inline int __csch(struct subchannel_id schid) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci unsigned long r1 = *(unsigned int *)&schid; 13362306a36Sopenharmony_ci int ccode; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci asm volatile( 13662306a36Sopenharmony_ci " lgr 1,%[r1]\n" 13762306a36Sopenharmony_ci " csch\n" 13862306a36Sopenharmony_ci " ipm %[cc]\n" 13962306a36Sopenharmony_ci " srl %[cc],28\n" 14062306a36Sopenharmony_ci : [cc] "=&d" (ccode) 14162306a36Sopenharmony_ci : [r1] "d" (r1) 14262306a36Sopenharmony_ci : "cc", "1"); 14362306a36Sopenharmony_ci return ccode; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciint csch(struct subchannel_id schid) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci int ccode; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ccode = __csch(schid); 15162306a36Sopenharmony_ci trace_s390_cio_csch(schid, ccode); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return ccode; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ciEXPORT_SYMBOL(csch); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ciint tpi(struct tpi_info *addr) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci int ccode; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci asm volatile( 16262306a36Sopenharmony_ci " tpi %[addr]\n" 16362306a36Sopenharmony_ci " ipm %[cc]\n" 16462306a36Sopenharmony_ci " srl %[cc],28" 16562306a36Sopenharmony_ci : [cc] "=&d" (ccode), [addr] "=Q" (*addr) 16662306a36Sopenharmony_ci : 16762306a36Sopenharmony_ci : "cc"); 16862306a36Sopenharmony_ci trace_s390_cio_tpi(addr, ccode); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return ccode; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciint chsc(void *chsc_area) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci typedef struct { char _[4096]; } addr_type; 17662306a36Sopenharmony_ci int cc = -EIO; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci asm volatile( 17962306a36Sopenharmony_ci " .insn rre,0xb25f0000,%[chsc_area],0\n" 18062306a36Sopenharmony_ci "0: ipm %[cc]\n" 18162306a36Sopenharmony_ci " srl %[cc],28\n" 18262306a36Sopenharmony_ci "1:\n" 18362306a36Sopenharmony_ci EX_TABLE(0b, 1b) 18462306a36Sopenharmony_ci : [cc] "+&d" (cc), "+m" (*(addr_type *)chsc_area) 18562306a36Sopenharmony_ci : [chsc_area] "d" (chsc_area) 18662306a36Sopenharmony_ci : "cc"); 18762306a36Sopenharmony_ci trace_s390_cio_chsc(chsc_area, cc); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return cc; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ciEXPORT_SYMBOL(chsc); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic inline int __rsch(struct subchannel_id schid) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci unsigned long r1 = *(unsigned int *)&schid; 19662306a36Sopenharmony_ci int ccode; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci asm volatile( 19962306a36Sopenharmony_ci " lgr 1,%[r1]\n" 20062306a36Sopenharmony_ci " rsch\n" 20162306a36Sopenharmony_ci " ipm %[cc]\n" 20262306a36Sopenharmony_ci " srl %[cc],28\n" 20362306a36Sopenharmony_ci : [cc] "=&d" (ccode) 20462306a36Sopenharmony_ci : [r1] "d" (r1) 20562306a36Sopenharmony_ci : "cc", "memory", "1"); 20662306a36Sopenharmony_ci return ccode; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ciint rsch(struct subchannel_id schid) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int ccode; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ccode = __rsch(schid); 21462306a36Sopenharmony_ci trace_s390_cio_rsch(schid, ccode); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return ccode; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic inline int __hsch(struct subchannel_id schid) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci unsigned long r1 = *(unsigned int *)&schid; 22262306a36Sopenharmony_ci int ccode; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci asm volatile( 22562306a36Sopenharmony_ci " lgr 1,%[r1]\n" 22662306a36Sopenharmony_ci " hsch\n" 22762306a36Sopenharmony_ci " ipm %[cc]\n" 22862306a36Sopenharmony_ci " srl %[cc],28\n" 22962306a36Sopenharmony_ci : [cc] "=&d" (ccode) 23062306a36Sopenharmony_ci : [r1] "d" (r1) 23162306a36Sopenharmony_ci : "cc", "1"); 23262306a36Sopenharmony_ci return ccode; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ciint hsch(struct subchannel_id schid) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci int ccode; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci ccode = __hsch(schid); 24062306a36Sopenharmony_ci trace_s390_cio_hsch(schid, ccode); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci return ccode; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ciEXPORT_SYMBOL(hsch); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic inline int __xsch(struct subchannel_id schid) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci unsigned long r1 = *(unsigned int *)&schid; 24962306a36Sopenharmony_ci int ccode; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci asm volatile( 25262306a36Sopenharmony_ci " lgr 1,%[r1]\n" 25362306a36Sopenharmony_ci " xsch\n" 25462306a36Sopenharmony_ci " ipm %[cc]\n" 25562306a36Sopenharmony_ci " srl %[cc],28\n" 25662306a36Sopenharmony_ci : [cc] "=&d" (ccode) 25762306a36Sopenharmony_ci : [r1] "d" (r1) 25862306a36Sopenharmony_ci : "cc", "1"); 25962306a36Sopenharmony_ci return ccode; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ciint xsch(struct subchannel_id schid) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci int ccode; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ccode = __xsch(schid); 26762306a36Sopenharmony_ci trace_s390_cio_xsch(schid, ccode); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return ccode; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic inline int __stcrw(struct crw *crw) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci int ccode; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci asm volatile( 27762306a36Sopenharmony_ci " stcrw %[crw]\n" 27862306a36Sopenharmony_ci " ipm %[cc]\n" 27962306a36Sopenharmony_ci " srl %[cc],28\n" 28062306a36Sopenharmony_ci : [cc] "=&d" (ccode), [crw] "=Q" (*crw) 28162306a36Sopenharmony_ci : 28262306a36Sopenharmony_ci : "cc"); 28362306a36Sopenharmony_ci return ccode; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic inline int _stcrw(struct crw *crw) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci#ifdef CONFIG_CIO_INJECT 28962306a36Sopenharmony_ci if (static_branch_unlikely(&cio_inject_enabled)) { 29062306a36Sopenharmony_ci if (stcrw_get_injected(crw) == 0) 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci#endif 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return __stcrw(crw); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciint stcrw(struct crw *crw) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int ccode; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ccode = _stcrw(crw); 30362306a36Sopenharmony_ci trace_s390_cio_stcrw(crw, ccode); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return ccode; 30662306a36Sopenharmony_ci} 307