1cbcca5d0SSebastian Ott /* 2cbcca5d0SSebastian Ott * s390 specific pci instructions 3cbcca5d0SSebastian Ott * 4cbcca5d0SSebastian Ott * Copyright IBM Corp. 2013 5cbcca5d0SSebastian Ott */ 6cbcca5d0SSebastian Ott 7cbcca5d0SSebastian Ott #include <linux/export.h> 8cbcca5d0SSebastian Ott #include <linux/errno.h> 9cbcca5d0SSebastian Ott #include <linux/delay.h> 10cbcca5d0SSebastian Ott #include <asm/pci_insn.h> 113d8258e4SSebastian Ott #include <asm/pci_debug.h> 12f0bacb7fSSebastian Ott #include <asm/processor.h> 13cbcca5d0SSebastian Ott 14cbcca5d0SSebastian Ott #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */ 15cbcca5d0SSebastian Ott 163d8258e4SSebastian Ott static inline void zpci_err_insn(u8 cc, u8 status, u64 req, u64 offset) 173d8258e4SSebastian Ott { 183d8258e4SSebastian Ott struct { 193d8258e4SSebastian Ott u64 req; 203d8258e4SSebastian Ott u64 offset; 217cc8944eSSebastian Ott u8 cc; 227cc8944eSSebastian Ott u8 status; 237cc8944eSSebastian Ott } __packed data = {req, offset, cc, status}; 243d8258e4SSebastian Ott 253d8258e4SSebastian Ott zpci_err_hex(&data, sizeof(data)); 263d8258e4SSebastian Ott } 273d8258e4SSebastian Ott 28cbcca5d0SSebastian Ott /* Modify PCI Function Controls */ 29cbcca5d0SSebastian Ott static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status) 30cbcca5d0SSebastian Ott { 31cbcca5d0SSebastian Ott u8 cc; 32cbcca5d0SSebastian Ott 33cbcca5d0SSebastian Ott asm volatile ( 34cbcca5d0SSebastian Ott " .insn rxy,0xe300000000d0,%[req],%[fib]\n" 35cbcca5d0SSebastian Ott " ipm %[cc]\n" 36cbcca5d0SSebastian Ott " srl %[cc],28\n" 37cbcca5d0SSebastian Ott : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib) 38cbcca5d0SSebastian Ott : : "cc"); 39cbcca5d0SSebastian Ott *status = req >> 24 & 0xff; 40cbcca5d0SSebastian Ott return cc; 41cbcca5d0SSebastian Ott } 42cbcca5d0SSebastian Ott 43*4dfbd3efSSebastian Ott u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status) 44cbcca5d0SSebastian Ott { 45*4dfbd3efSSebastian Ott u8 cc; 46cbcca5d0SSebastian Ott 47cbcca5d0SSebastian Ott do { 48*4dfbd3efSSebastian Ott cc = __mpcifc(req, fib, status); 49cbcca5d0SSebastian Ott if (cc == 2) 50cbcca5d0SSebastian Ott msleep(ZPCI_INSN_BUSY_DELAY); 51cbcca5d0SSebastian Ott } while (cc == 2); 52cbcca5d0SSebastian Ott 53cbcca5d0SSebastian Ott if (cc) 54*4dfbd3efSSebastian Ott zpci_err_insn(cc, *status, req, 0); 553d8258e4SSebastian Ott 56*4dfbd3efSSebastian Ott return cc; 57cbcca5d0SSebastian Ott } 58cbcca5d0SSebastian Ott 59cbcca5d0SSebastian Ott /* Refresh PCI Translations */ 60cbcca5d0SSebastian Ott static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status) 61cbcca5d0SSebastian Ott { 62cbcca5d0SSebastian Ott register u64 __addr asm("2") = addr; 63cbcca5d0SSebastian Ott register u64 __range asm("3") = range; 64cbcca5d0SSebastian Ott u8 cc; 65cbcca5d0SSebastian Ott 66cbcca5d0SSebastian Ott asm volatile ( 67cbcca5d0SSebastian Ott " .insn rre,0xb9d30000,%[fn],%[addr]\n" 68cbcca5d0SSebastian Ott " ipm %[cc]\n" 69cbcca5d0SSebastian Ott " srl %[cc],28\n" 70cbcca5d0SSebastian Ott : [cc] "=d" (cc), [fn] "+d" (fn) 71cbcca5d0SSebastian Ott : [addr] "d" (__addr), "d" (__range) 72cbcca5d0SSebastian Ott : "cc"); 73cbcca5d0SSebastian Ott *status = fn >> 24 & 0xff; 74cbcca5d0SSebastian Ott return cc; 75cbcca5d0SSebastian Ott } 76cbcca5d0SSebastian Ott 779389339fSMartin Schwidefsky int zpci_refresh_trans(u64 fn, u64 addr, u64 range) 78cbcca5d0SSebastian Ott { 79cbcca5d0SSebastian Ott u8 cc, status; 80cbcca5d0SSebastian Ott 81cbcca5d0SSebastian Ott do { 82cbcca5d0SSebastian Ott cc = __rpcit(fn, addr, range, &status); 83cbcca5d0SSebastian Ott if (cc == 2) 84cbcca5d0SSebastian Ott udelay(ZPCI_INSN_BUSY_DELAY); 85cbcca5d0SSebastian Ott } while (cc == 2); 86cbcca5d0SSebastian Ott 87cbcca5d0SSebastian Ott if (cc) 883d8258e4SSebastian Ott zpci_err_insn(cc, status, addr, range); 893d8258e4SSebastian Ott 90cbcca5d0SSebastian Ott return (cc) ? -EIO : 0; 91cbcca5d0SSebastian Ott } 92cbcca5d0SSebastian Ott 93cbcca5d0SSebastian Ott /* Set Interruption Controls */ 949389339fSMartin Schwidefsky void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc) 95cbcca5d0SSebastian Ott { 96cbcca5d0SSebastian Ott asm volatile ( 97cbcca5d0SSebastian Ott " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n" 98cbcca5d0SSebastian Ott : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused)); 99cbcca5d0SSebastian Ott } 100cbcca5d0SSebastian Ott 101cbcca5d0SSebastian Ott /* PCI Load */ 1027b411ac6SHeiko Carstens static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status) 103cbcca5d0SSebastian Ott { 104cbcca5d0SSebastian Ott register u64 __req asm("2") = req; 105cbcca5d0SSebastian Ott register u64 __offset asm("3") = offset; 106f0bacb7fSSebastian Ott int cc = -ENXIO; 107cbcca5d0SSebastian Ott u64 __data; 108cbcca5d0SSebastian Ott 109cbcca5d0SSebastian Ott asm volatile ( 110cbcca5d0SSebastian Ott " .insn rre,0xb9d20000,%[data],%[req]\n" 111f0bacb7fSSebastian Ott "0: ipm %[cc]\n" 112cbcca5d0SSebastian Ott " srl %[cc],28\n" 113f0bacb7fSSebastian Ott "1:\n" 114f0bacb7fSSebastian Ott EX_TABLE(0b, 1b) 115f0bacb7fSSebastian Ott : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req) 116cbcca5d0SSebastian Ott : "d" (__offset) 117cbcca5d0SSebastian Ott : "cc"); 118cbcca5d0SSebastian Ott *status = __req >> 24 & 0xff; 1197b411ac6SHeiko Carstens *data = __data; 1207b411ac6SHeiko Carstens return cc; 1217b411ac6SHeiko Carstens } 1227b411ac6SHeiko Carstens 1237b411ac6SHeiko Carstens static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status) 1247b411ac6SHeiko Carstens { 1257b411ac6SHeiko Carstens u64 __data; 1267b411ac6SHeiko Carstens int cc; 1277b411ac6SHeiko Carstens 1287b411ac6SHeiko Carstens cc = ____pcilg(&__data, req, offset, status); 129b170bad4SSebastian Ott if (!cc) 130cbcca5d0SSebastian Ott *data = __data; 131b170bad4SSebastian Ott 132cbcca5d0SSebastian Ott return cc; 133cbcca5d0SSebastian Ott } 134cbcca5d0SSebastian Ott 1359389339fSMartin Schwidefsky int zpci_load(u64 *data, u64 req, u64 offset) 136cbcca5d0SSebastian Ott { 137f0bacb7fSSebastian Ott u8 status; 138f0bacb7fSSebastian Ott int cc; 139cbcca5d0SSebastian Ott 140cbcca5d0SSebastian Ott do { 141cbcca5d0SSebastian Ott cc = __pcilg(data, req, offset, &status); 142cbcca5d0SSebastian Ott if (cc == 2) 143cbcca5d0SSebastian Ott udelay(ZPCI_INSN_BUSY_DELAY); 144cbcca5d0SSebastian Ott } while (cc == 2); 145cbcca5d0SSebastian Ott 146f0bacb7fSSebastian Ott if (cc) 1473d8258e4SSebastian Ott zpci_err_insn(cc, status, req, offset); 1483d8258e4SSebastian Ott 149f0bacb7fSSebastian Ott return (cc > 0) ? -EIO : cc; 150cbcca5d0SSebastian Ott } 1519389339fSMartin Schwidefsky EXPORT_SYMBOL_GPL(zpci_load); 152cbcca5d0SSebastian Ott 153cbcca5d0SSebastian Ott /* PCI Store */ 154f0bacb7fSSebastian Ott static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status) 155cbcca5d0SSebastian Ott { 156cbcca5d0SSebastian Ott register u64 __req asm("2") = req; 157cbcca5d0SSebastian Ott register u64 __offset asm("3") = offset; 158f0bacb7fSSebastian Ott int cc = -ENXIO; 159cbcca5d0SSebastian Ott 160cbcca5d0SSebastian Ott asm volatile ( 161cbcca5d0SSebastian Ott " .insn rre,0xb9d00000,%[data],%[req]\n" 162f0bacb7fSSebastian Ott "0: ipm %[cc]\n" 163cbcca5d0SSebastian Ott " srl %[cc],28\n" 164f0bacb7fSSebastian Ott "1:\n" 165f0bacb7fSSebastian Ott EX_TABLE(0b, 1b) 166f0bacb7fSSebastian Ott : [cc] "+d" (cc), [req] "+d" (__req) 167cbcca5d0SSebastian Ott : "d" (__offset), [data] "d" (data) 168cbcca5d0SSebastian Ott : "cc"); 169cbcca5d0SSebastian Ott *status = __req >> 24 & 0xff; 170cbcca5d0SSebastian Ott return cc; 171cbcca5d0SSebastian Ott } 172cbcca5d0SSebastian Ott 1739389339fSMartin Schwidefsky int zpci_store(u64 data, u64 req, u64 offset) 174cbcca5d0SSebastian Ott { 175f0bacb7fSSebastian Ott u8 status; 176f0bacb7fSSebastian Ott int cc; 177cbcca5d0SSebastian Ott 178cbcca5d0SSebastian Ott do { 179cbcca5d0SSebastian Ott cc = __pcistg(data, req, offset, &status); 180cbcca5d0SSebastian Ott if (cc == 2) 181cbcca5d0SSebastian Ott udelay(ZPCI_INSN_BUSY_DELAY); 182cbcca5d0SSebastian Ott } while (cc == 2); 183cbcca5d0SSebastian Ott 184cbcca5d0SSebastian Ott if (cc) 1853d8258e4SSebastian Ott zpci_err_insn(cc, status, req, offset); 1863d8258e4SSebastian Ott 187f0bacb7fSSebastian Ott return (cc > 0) ? -EIO : cc; 188cbcca5d0SSebastian Ott } 1899389339fSMartin Schwidefsky EXPORT_SYMBOL_GPL(zpci_store); 190cbcca5d0SSebastian Ott 191cbcca5d0SSebastian Ott /* PCI Store Block */ 192f0bacb7fSSebastian Ott static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) 193cbcca5d0SSebastian Ott { 194f0bacb7fSSebastian Ott int cc = -ENXIO; 195cbcca5d0SSebastian Ott 196cbcca5d0SSebastian Ott asm volatile ( 197cbcca5d0SSebastian Ott " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" 198f0bacb7fSSebastian Ott "0: ipm %[cc]\n" 199cbcca5d0SSebastian Ott " srl %[cc],28\n" 200f0bacb7fSSebastian Ott "1:\n" 201f0bacb7fSSebastian Ott EX_TABLE(0b, 1b) 202f0bacb7fSSebastian Ott : [cc] "+d" (cc), [req] "+d" (req) 203cbcca5d0SSebastian Ott : [offset] "d" (offset), [data] "Q" (*data) 204cbcca5d0SSebastian Ott : "cc"); 205cbcca5d0SSebastian Ott *status = req >> 24 & 0xff; 206cbcca5d0SSebastian Ott return cc; 207cbcca5d0SSebastian Ott } 208cbcca5d0SSebastian Ott 2099389339fSMartin Schwidefsky int zpci_store_block(const u64 *data, u64 req, u64 offset) 210cbcca5d0SSebastian Ott { 211f0bacb7fSSebastian Ott u8 status; 212f0bacb7fSSebastian Ott int cc; 213cbcca5d0SSebastian Ott 214cbcca5d0SSebastian Ott do { 215cbcca5d0SSebastian Ott cc = __pcistb(data, req, offset, &status); 216cbcca5d0SSebastian Ott if (cc == 2) 217cbcca5d0SSebastian Ott udelay(ZPCI_INSN_BUSY_DELAY); 218cbcca5d0SSebastian Ott } while (cc == 2); 219cbcca5d0SSebastian Ott 220cbcca5d0SSebastian Ott if (cc) 2213d8258e4SSebastian Ott zpci_err_insn(cc, status, req, offset); 2223d8258e4SSebastian Ott 223f0bacb7fSSebastian Ott return (cc > 0) ? -EIO : cc; 224cbcca5d0SSebastian Ott } 2259389339fSMartin Schwidefsky EXPORT_SYMBOL_GPL(zpci_store_block); 226