Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.12 225 lines 4.4 kB view raw
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 *data = __data; 120 return cc; 121} 122 123static 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 135int 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} 151EXPORT_SYMBOL_GPL(zpci_load); 152 153/* PCI Store */ 154static 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 173int 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} 189EXPORT_SYMBOL_GPL(zpci_store); 190 191/* PCI Store Block */ 192static 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 209int 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} 225EXPORT_SYMBOL_GPL(zpci_store_block);