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