diff options
Diffstat (limited to 'arch/s390/pci/pci_mmio.c')
-rw-r--r-- | arch/s390/pci/pci_mmio.c | 90 |
1 files changed, 50 insertions, 40 deletions
diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c index de5c0b389a3e..46f99dc164ad 100644 --- a/arch/s390/pci/pci_mmio.c +++ b/arch/s390/pci/pci_mmio.c @@ -14,6 +14,7 @@ #include <asm/asm-extable.h> #include <asm/pci_io.h> #include <asm/pci_debug.h> +#include <asm/asm.h> static inline void zpci_err_mmio(u8 cc, u8 status, u64 offset) { @@ -30,20 +31,21 @@ static inline int __pcistb_mio_inuser( void __iomem *ioaddr, const void __user *src, u64 len, u8 *status) { - int cc = -ENXIO; + int cc, exception; + exception = 1; asm volatile ( - " sacf 256\n" - "0: .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[src]\n" - "1: ipm %[cc]\n" - " srl %[cc],28\n" - "2: sacf 768\n" + " sacf 256\n" + "0: .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[src]\n" + "1: lhi %[exc],0\n" + "2: sacf 768\n" + CC_IPM(cc) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b) - : [cc] "+d" (cc), [len] "+d" (len) + : CC_OUT(cc, cc), [len] "+d" (len), [exc] "+d" (exception) : [ioaddr] "a" (ioaddr), [src] "Q" (*((u8 __force *)src)) - : "cc", "memory"); + : CC_CLOBBER_LIST("memory")); *status = len >> 24 & 0xff; - return cc; + return exception ? -ENXIO : CC_TRANSFORM(cc); } static inline int __pcistg_mio_inuser( @@ -51,7 +53,7 @@ static inline int __pcistg_mio_inuser( u64 ulen, u8 *status) { union register_pair ioaddr_len = {.even = (u64 __force)ioaddr, .odd = ulen}; - int cc = -ENXIO; + int cc, exception; u64 val = 0; u64 cnt = ulen; u8 tmp; @@ -61,25 +63,27 @@ static inline int __pcistg_mio_inuser( * a register, then store it to PCI at @ioaddr while in secondary * address space. pcistg then uses the user mappings. */ + exception = 1; asm volatile ( - " sacf 256\n" - "0: llgc %[tmp],0(%[src])\n" + " sacf 256\n" + "0: llgc %[tmp],0(%[src])\n" "4: sllg %[val],%[val],8\n" - " aghi %[src],1\n" - " ogr %[val],%[tmp]\n" - " brctg %[cnt],0b\n" - "1: .insn rre,0xb9d40000,%[val],%[ioaddr_len]\n" - "2: ipm %[cc]\n" - " srl %[cc],28\n" - "3: sacf 768\n" + " aghi %[src],1\n" + " ogr %[val],%[tmp]\n" + " brctg %[cnt],0b\n" + "1: .insn rre,0xb9d40000,%[val],%[ioaddr_len]\n" + "2: lhi %[exc],0\n" + "3: sacf 768\n" + CC_IPM(cc) EX_TABLE(0b, 3b) EX_TABLE(4b, 3b) EX_TABLE(1b, 3b) EX_TABLE(2b, 3b) + : [src] "+a" (src), [cnt] "+d" (cnt), + [val] "+d" (val), [tmp] "=d" (tmp), [exc] "+d" (exception), + CC_OUT(cc, cc), [ioaddr_len] "+&d" (ioaddr_len.pair) : - [src] "+a" (src), [cnt] "+d" (cnt), - [val] "+d" (val), [tmp] "=d" (tmp), - [cc] "+d" (cc), [ioaddr_len] "+&d" (ioaddr_len.pair) - :: "cc", "memory"); + : CC_CLOBBER_LIST("memory")); *status = ioaddr_len.odd >> 24 & 0xff; + cc = exception ? -ENXIO : CC_TRANSFORM(cc); /* did we read everything from user memory? */ if (!cc && cnt != 0) cc = -EFAULT; @@ -198,7 +202,7 @@ static inline int __pcilg_mio_inuser( union register_pair ioaddr_len = {.even = (u64 __force)ioaddr, .odd = ulen}; u64 cnt = ulen; int shift = ulen * 8; - int cc = -ENXIO; + int cc, exception; u64 val, tmp; /* @@ -206,27 +210,33 @@ static inline int __pcilg_mio_inuser( * user space) into a register using pcilg then store these bytes at * user address @dst */ + exception = 1; asm volatile ( - " sacf 256\n" - "0: .insn rre,0xb9d60000,%[val],%[ioaddr_len]\n" - "1: ipm %[cc]\n" - " srl %[cc],28\n" - " ltr %[cc],%[cc]\n" - " jne 4f\n" - "2: ahi %[shift],-8\n" - " srlg %[tmp],%[val],0(%[shift])\n" - "3: stc %[tmp],0(%[dst])\n" + " sacf 256\n" + "0: .insn rre,0xb9d60000,%[val],%[ioaddr_len]\n" + "1: lhi %[exc],0\n" + " jne 4f\n" + "2: ahi %[shift],-8\n" + " srlg %[tmp],%[val],0(%[shift])\n" + "3: stc %[tmp],0(%[dst])\n" "5: aghi %[dst],1\n" - " brctg %[cnt],2b\n" - "4: sacf 768\n" + " brctg %[cnt],2b\n" + /* + * Use xr to clear exc and set condition code to zero + * to ensure flag output is correct for this branch. + */ + " xr %[exc],%[exc]\n" + "4: sacf 768\n" + CC_IPM(cc) EX_TABLE(0b, 4b) EX_TABLE(1b, 4b) EX_TABLE(3b, 4b) EX_TABLE(5b, 4b) + : [ioaddr_len] "+&d" (ioaddr_len.pair), [exc] "+d" (exception), + CC_OUT(cc, cc), [val] "=d" (val), + [dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp), + [shift] "+d" (shift) : - [ioaddr_len] "+&d" (ioaddr_len.pair), - [cc] "+d" (cc), [val] "=d" (val), - [dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp), - [shift] "+d" (shift) - :: "cc", "memory"); + : CC_CLOBBER_LIST("memory")); + cc = exception ? -ENXIO : CC_TRANSFORM(cc); /* did we write everything to the user space buffer? */ if (!cc && cnt != 0) cc = -EFAULT; |