1 /* 2 * s390 specific pci instructions 3 * 4 * Copyright IBM Corp. 2013 5 */ 6 7 #include <linux/export.h> 8 #include <linux/errno.h> 9 #include <linux/delay.h> 10 #include <asm/pci_insn.h> 11 #include <asm/pci_debug.h> 12 #include <asm/processor.h> 13 14 #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */ 15 16 static inline void zpci_err_insn(u8 cc, u8 status, u64 req, u64 offset) 17 { 18 struct { 19 u64 req; 20 u64 offset; 21 u8 cc; 22 u8 status; 23 } __packed data = {req, offset, cc, status}; 24 25 zpci_err_hex(&data, sizeof(data)); 26 } 27 28 /* Modify PCI Function Controls */ 29 static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status) 30 { 31 u8 cc; 32 33 asm volatile ( 34 " .insn rxy,0xe300000000d0,%[req],%[fib]\n" 35 " ipm %[cc]\n" 36 " srl %[cc],28\n" 37 : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib) 38 : : "cc"); 39 *status = req >> 24 & 0xff; 40 return cc; 41 } 42 43 int zpci_mod_fc(u64 req, struct zpci_fib *fib) 44 { 45 u8 cc, status; 46 47 do { 48 cc = __mpcifc(req, fib, &status); 49 if (cc == 2) 50 msleep(ZPCI_INSN_BUSY_DELAY); 51 } while (cc == 2); 52 53 if (cc) 54 zpci_err_insn(cc, status, req, 0); 55 56 return (cc) ? -EIO : 0; 57 } 58 59 /* Refresh PCI Translations */ 60 static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status) 61 { 62 register u64 __addr asm("2") = addr; 63 register u64 __range asm("3") = range; 64 u8 cc; 65 66 asm volatile ( 67 " .insn rre,0xb9d30000,%[fn],%[addr]\n" 68 " ipm %[cc]\n" 69 " srl %[cc],28\n" 70 : [cc] "=d" (cc), [fn] "+d" (fn) 71 : [addr] "d" (__addr), "d" (__range) 72 : "cc"); 73 *status = fn >> 24 & 0xff; 74 return cc; 75 } 76 77 int zpci_refresh_trans(u64 fn, u64 addr, u64 range) 78 { 79 u8 cc, status; 80 81 do { 82 cc = __rpcit(fn, addr, range, &status); 83 if (cc == 2) 84 udelay(ZPCI_INSN_BUSY_DELAY); 85 } while (cc == 2); 86 87 if (cc) 88 zpci_err_insn(cc, status, addr, range); 89 90 return (cc) ? -EIO : 0; 91 } 92 93 /* Set Interruption Controls */ 94 void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc) 95 { 96 asm volatile ( 97 " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n" 98 : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused)); 99 } 100 101 /* PCI Load */ 102 static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status) 103 { 104 register u64 __req asm("2") = req; 105 register u64 __offset asm("3") = offset; 106 int cc = -ENXIO; 107 u64 __data; 108 109 asm volatile ( 110 " .insn rre,0xb9d20000,%[data],%[req]\n" 111 "0: ipm %[cc]\n" 112 " srl %[cc],28\n" 113 "1:\n" 114 EX_TABLE(0b, 1b) 115 : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req) 116 : "d" (__offset) 117 : "cc"); 118 *status = __req >> 24 & 0xff; 119 *data = __data; 120 return cc; 121 } 122 123 static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status) 124 { 125 u64 __data; 126 int cc; 127 128 cc = ____pcilg(&__data, req, offset, status); 129 if (!cc) 130 *data = __data; 131 132 return cc; 133 } 134 135 int zpci_load(u64 *data, u64 req, u64 offset) 136 { 137 u8 status; 138 int cc; 139 140 do { 141 cc = __pcilg(data, req, offset, &status); 142 if (cc == 2) 143 udelay(ZPCI_INSN_BUSY_DELAY); 144 } while (cc == 2); 145 146 if (cc) 147 zpci_err_insn(cc, status, req, offset); 148 149 return (cc > 0) ? -EIO : cc; 150 } 151 EXPORT_SYMBOL_GPL(zpci_load); 152 153 /* PCI Store */ 154 static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status) 155 { 156 register u64 __req asm("2") = req; 157 register u64 __offset asm("3") = offset; 158 int cc = -ENXIO; 159 160 asm volatile ( 161 " .insn rre,0xb9d00000,%[data],%[req]\n" 162 "0: ipm %[cc]\n" 163 " srl %[cc],28\n" 164 "1:\n" 165 EX_TABLE(0b, 1b) 166 : [cc] "+d" (cc), [req] "+d" (__req) 167 : "d" (__offset), [data] "d" (data) 168 : "cc"); 169 *status = __req >> 24 & 0xff; 170 return cc; 171 } 172 173 int zpci_store(u64 data, u64 req, u64 offset) 174 { 175 u8 status; 176 int cc; 177 178 do { 179 cc = __pcistg(data, req, offset, &status); 180 if (cc == 2) 181 udelay(ZPCI_INSN_BUSY_DELAY); 182 } while (cc == 2); 183 184 if (cc) 185 zpci_err_insn(cc, status, req, offset); 186 187 return (cc > 0) ? -EIO : cc; 188 } 189 EXPORT_SYMBOL_GPL(zpci_store); 190 191 /* PCI Store Block */ 192 static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) 193 { 194 int cc = -ENXIO; 195 196 asm volatile ( 197 " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" 198 "0: ipm %[cc]\n" 199 " srl %[cc],28\n" 200 "1:\n" 201 EX_TABLE(0b, 1b) 202 : [cc] "+d" (cc), [req] "+d" (req) 203 : [offset] "d" (offset), [data] "Q" (*data) 204 : "cc"); 205 *status = req >> 24 & 0xff; 206 return cc; 207 } 208 209 int zpci_store_block(const u64 *data, u64 req, u64 offset) 210 { 211 u8 status; 212 int cc; 213 214 do { 215 cc = __pcistb(data, req, offset, &status); 216 if (cc == 2) 217 udelay(ZPCI_INSN_BUSY_DELAY); 218 } while (cc == 2); 219 220 if (cc) 221 zpci_err_insn(cc, status, req, offset); 222 223 return (cc > 0) ? -EIO : cc; 224 } 225 EXPORT_SYMBOL_GPL(zpci_store_block); 226