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 16static 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 */ 29static 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 43int 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 */ 60static 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 77int 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 */ 94void 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 */ 102static 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 if (!cc) 120 *data = __data; 121 122 return cc; 123} 124 125int zpci_load(u64 *data, u64 req, u64 offset) 126{ 127 u8 status; 128 int cc; 129 130 do { 131 cc = __pcilg(data, req, offset, &status); 132 if (cc == 2) 133 udelay(ZPCI_INSN_BUSY_DELAY); 134 } while (cc == 2); 135 136 if (cc) 137 zpci_err_insn(cc, status, req, offset); 138 139 return (cc > 0) ? -EIO : cc; 140} 141EXPORT_SYMBOL_GPL(zpci_load); 142 143/* PCI Store */ 144static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status) 145{ 146 register u64 __req asm("2") = req; 147 register u64 __offset asm("3") = offset; 148 int cc = -ENXIO; 149 150 asm volatile ( 151 " .insn rre,0xb9d00000,%[data],%[req]\n" 152 "0: ipm %[cc]\n" 153 " srl %[cc],28\n" 154 "1:\n" 155 EX_TABLE(0b, 1b) 156 : [cc] "+d" (cc), [req] "+d" (__req) 157 : "d" (__offset), [data] "d" (data) 158 : "cc"); 159 *status = __req >> 24 & 0xff; 160 return cc; 161} 162 163int zpci_store(u64 data, u64 req, u64 offset) 164{ 165 u8 status; 166 int cc; 167 168 do { 169 cc = __pcistg(data, req, offset, &status); 170 if (cc == 2) 171 udelay(ZPCI_INSN_BUSY_DELAY); 172 } while (cc == 2); 173 174 if (cc) 175 zpci_err_insn(cc, status, req, offset); 176 177 return (cc > 0) ? -EIO : cc; 178} 179EXPORT_SYMBOL_GPL(zpci_store); 180 181/* PCI Store Block */ 182static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) 183{ 184 int cc = -ENXIO; 185 186 asm volatile ( 187 " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" 188 "0: ipm %[cc]\n" 189 " srl %[cc],28\n" 190 "1:\n" 191 EX_TABLE(0b, 1b) 192 : [cc] "+d" (cc), [req] "+d" (req) 193 : [offset] "d" (offset), [data] "Q" (*data) 194 : "cc"); 195 *status = req >> 24 & 0xff; 196 return cc; 197} 198 199int zpci_store_block(const u64 *data, u64 req, u64 offset) 200{ 201 u8 status; 202 int cc; 203 204 do { 205 cc = __pcistb(data, req, offset, &status); 206 if (cc == 2) 207 udelay(ZPCI_INSN_BUSY_DELAY); 208 } while (cc == 2); 209 210 if (cc) 211 zpci_err_insn(cc, status, req, offset); 212 213 return (cc > 0) ? -EIO : cc; 214} 215EXPORT_SYMBOL_GPL(zpci_store_block); 216