diff options
Diffstat (limited to 'drivers/s390/cio/ioasm.c')
| -rw-r--r-- | drivers/s390/cio/ioasm.c | 212 |
1 files changed, 121 insertions, 91 deletions
diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c index 14d328338ce2..8b06b234e110 100644 --- a/drivers/s390/cio/ioasm.c +++ b/drivers/s390/cio/ioasm.c @@ -5,29 +5,34 @@ #include <linux/export.h> +#include <asm/asm-extable.h> #include <asm/chpid.h> #include <asm/schid.h> +#include <asm/asm.h> #include <asm/crw.h> #include "ioasm.h" #include "orb.h" #include "cio.h" +#include "cio_inject.h" static inline int __stsch(struct subchannel_id schid, struct schib *addr) { - register struct subchannel_id reg1 asm ("1") = schid; - int ccode = -EIO; - - asm volatile( - " stsch 0(%3)\n" - "0: ipm %0\n" - " srl %0,28\n" + unsigned long r1 = *(unsigned int *)&schid; + int ccode, exception; + + exception = 1; + asm_inline volatile( + " lgr 1,%[r1]\n" + " stsch %[addr]\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : "+d" (ccode), "=m" (*addr) - : "d" (reg1), "a" (addr) - : "cc"); - return ccode; + : CC_OUT(cc, ccode), [addr] "=Q" (*addr), [exc] "+d" (exception) + : [r1] "d" (r1) + : CC_CLOBBER_LIST("1")); + return exception ? -EIO : CC_TRANSFORM(ccode); } int stsch(struct subchannel_id schid, struct schib *addr) @@ -43,19 +48,21 @@ EXPORT_SYMBOL(stsch); static inline int __msch(struct subchannel_id schid, struct schib *addr) { - register struct subchannel_id reg1 asm ("1") = schid; - int ccode = -EIO; - - asm volatile( - " msch 0(%2)\n" - "0: ipm %0\n" - " srl %0,28\n" + unsigned long r1 = *(unsigned int *)&schid; + int ccode, exception; + + exception = 1; + asm_inline volatile( + " lgr 1,%[r1]\n" + " msch %[addr]\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : "+d" (ccode) - : "d" (reg1), "a" (addr), "m" (*addr) - : "cc"); - return ccode; + : CC_OUT(cc, ccode), [exc] "+d" (exception) + : [r1] "d" (r1), [addr] "Q" (*addr) + : CC_CLOBBER_LIST("1")); + return exception ? -EIO : CC_TRANSFORM(ccode); } int msch(struct subchannel_id schid, struct schib *addr) @@ -70,17 +77,17 @@ int msch(struct subchannel_id schid, struct schib *addr) static inline int __tsch(struct subchannel_id schid, struct irb *addr) { - register struct subchannel_id reg1 asm ("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( - " tsch 0(%3)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode), "=m" (*addr) - : "d" (reg1), "a" (addr) - : "cc"); - return ccode; + " lgr 1,%[r1]\n" + " tsch %[addr]\n" + CC_IPM(cc) + : CC_OUT(cc, ccode), [addr] "=Q" (*addr) + : [r1] "d" (r1) + : CC_CLOBBER_LIST("1")); + return CC_TRANSFORM(ccode); } int tsch(struct subchannel_id schid, struct irb *addr) @@ -95,19 +102,21 @@ int tsch(struct subchannel_id schid, struct irb *addr) static inline int __ssch(struct subchannel_id schid, union orb *addr) { - register struct subchannel_id reg1 asm("1") = schid; - int ccode = -EIO; - - asm volatile( - " ssch 0(%2)\n" - "0: ipm %0\n" - " srl %0,28\n" + unsigned long r1 = *(unsigned int *)&schid; + int ccode, exception; + + exception = 1; + asm_inline volatile( + " lgr 1,%[r1]\n" + " ssch %[addr]\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : "+d" (ccode) - : "d" (reg1), "a" (addr), "m" (*addr) - : "cc", "memory"); - return ccode; + : CC_OUT(cc, ccode), [exc] "+d" (exception) + : [r1] "d" (r1), [addr] "Q" (*addr) + : CC_CLOBBER_LIST("memory", "1")); + return CC_TRANSFORM(ccode); } int ssch(struct subchannel_id schid, union orb *addr) @@ -123,17 +132,17 @@ EXPORT_SYMBOL(ssch); static inline int __csch(struct subchannel_id schid) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( + " lgr 1,%[r1]\n" " csch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) - : "d" (reg1) - : "cc"); - return ccode; + CC_IPM(cc) + : CC_OUT(cc, ccode) + : [r1] "d" (r1) + : CC_CLOBBER_LIST("1")); + return CC_TRANSFORM(ccode); } int csch(struct subchannel_id schid) @@ -152,12 +161,12 @@ int tpi(struct tpi_info *addr) int ccode; asm volatile( - " tpi 0(%2)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode), "=m" (*addr) - : "a" (addr) - : "cc"); + " tpi %[addr]\n" + CC_IPM(cc) + : CC_OUT(cc, ccode), [addr] "=Q" (*addr) + : + : CC_CLOBBER); + ccode = CC_TRANSFORM(ccode); trace_s390_cio_tpi(addr, ccode); return ccode; @@ -166,17 +175,19 @@ int tpi(struct tpi_info *addr) int chsc(void *chsc_area) { typedef struct { char _[4096]; } addr_type; - int cc = -EIO; + int cc, exception; - asm volatile( - " .insn rre,0xb25f0000,%2,0\n" - "0: ipm %0\n" - " srl %0,28\n" + exception = 1; + asm_inline volatile( + " .insn rre,0xb25f0000,%[chsc_area],0\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : "+d" (cc), "=m" (*(addr_type *) chsc_area) - : "d" (chsc_area), "m" (*(addr_type *) chsc_area) - : "cc"); + : CC_OUT(cc, cc), "+m" (*(addr_type *)chsc_area), [exc] "+d" (exception) + : [chsc_area] "d" (chsc_area) + : CC_CLOBBER); + cc = exception ? -EIO : CC_TRANSFORM(cc); trace_s390_cio_chsc(chsc_area, cc); return cc; @@ -185,18 +196,17 @@ EXPORT_SYMBOL(chsc); static inline int __rsch(struct subchannel_id schid) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( + " lgr 1,%[r1]\n" " rsch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) - : "d" (reg1) - : "cc", "memory"); - - return ccode; + CC_IPM(cc) + : CC_OUT(cc, ccode) + : [r1] "d" (r1) + : CC_CLOBBER_LIST("memory", "1")); + return CC_TRANSFORM(ccode); } int rsch(struct subchannel_id schid) @@ -211,17 +221,17 @@ int rsch(struct subchannel_id schid) static inline int __hsch(struct subchannel_id schid) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( + " lgr 1,%[r1]\n" " hsch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) - : "d" (reg1) - : "cc"); - return ccode; + CC_IPM(cc) + : CC_OUT(cc, ccode) + : [r1] "d" (r1) + : CC_CLOBBER_LIST("1")); + return CC_TRANSFORM(ccode); } int hsch(struct subchannel_id schid) @@ -233,20 +243,21 @@ int hsch(struct subchannel_id schid) return ccode; } +EXPORT_SYMBOL(hsch); static inline int __xsch(struct subchannel_id schid) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( + " lgr 1,%[r1]\n" " xsch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) - : "d" (reg1) - : "cc"); - return ccode; + CC_IPM(cc) + : CC_OUT(cc, ccode) + : [r1] "d" (r1) + : CC_CLOBBER_LIST("1")); + return CC_TRANSFORM(ccode); } int xsch(struct subchannel_id schid) @@ -259,17 +270,36 @@ int xsch(struct subchannel_id schid) return ccode; } -int stcrw(struct crw *crw) +static inline int __stcrw(struct crw *crw) { int ccode; asm volatile( - " stcrw 0(%2)\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode), "=m" (*crw) - : "a" (crw) - : "cc"); + " stcrw %[crw]\n" + CC_IPM(cc) + : CC_OUT(cc, ccode), [crw] "=Q" (*crw) + : + : CC_CLOBBER); + return CC_TRANSFORM(ccode); +} + +static inline int _stcrw(struct crw *crw) +{ +#ifdef CONFIG_CIO_INJECT + if (static_branch_unlikely(&cio_inject_enabled)) { + if (stcrw_get_injected(crw) == 0) + return 0; + } +#endif + + return __stcrw(crw); +} + +int stcrw(struct crw *crw) +{ + int ccode; + + ccode = _stcrw(crw); trace_s390_cio_stcrw(crw, ccode); return ccode; |
