.. | .. |
---|
8 | 8 | #include <linux/export.h> |
---|
9 | 9 | #include <linux/errno.h> |
---|
10 | 10 | #include <linux/delay.h> |
---|
| 11 | +#include <linux/jump_label.h> |
---|
11 | 12 | #include <asm/facility.h> |
---|
12 | 13 | #include <asm/pci_insn.h> |
---|
13 | 14 | #include <asm/pci_debug.h> |
---|
| 15 | +#include <asm/pci_io.h> |
---|
14 | 16 | #include <asm/processor.h> |
---|
15 | 17 | |
---|
16 | 18 | #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */ |
---|
.. | .. |
---|
96 | 98 | } |
---|
97 | 99 | |
---|
98 | 100 | /* Set Interruption Controls */ |
---|
99 | | -int zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc) |
---|
| 101 | +int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib) |
---|
100 | 102 | { |
---|
101 | 103 | if (!test_facility(72)) |
---|
102 | 104 | return -EIO; |
---|
103 | | - asm volatile ( |
---|
104 | | - " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n" |
---|
105 | | - : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused)); |
---|
| 105 | + |
---|
| 106 | + asm volatile( |
---|
| 107 | + ".insn rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]\n" |
---|
| 108 | + : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [iib] "Q" (*iib)); |
---|
| 109 | + |
---|
106 | 110 | return 0; |
---|
107 | 111 | } |
---|
108 | 112 | |
---|
.. | .. |
---|
140 | 144 | return cc; |
---|
141 | 145 | } |
---|
142 | 146 | |
---|
143 | | -int zpci_load(u64 *data, u64 req, u64 offset) |
---|
| 147 | +int __zpci_load(u64 *data, u64 req, u64 offset) |
---|
144 | 148 | { |
---|
145 | 149 | u8 status; |
---|
146 | 150 | int cc; |
---|
.. | .. |
---|
153 | 157 | |
---|
154 | 158 | if (cc) |
---|
155 | 159 | zpci_err_insn(cc, status, req, offset); |
---|
| 160 | + |
---|
| 161 | + return (cc > 0) ? -EIO : cc; |
---|
| 162 | +} |
---|
| 163 | +EXPORT_SYMBOL_GPL(__zpci_load); |
---|
| 164 | + |
---|
| 165 | +static inline int zpci_load_fh(u64 *data, const volatile void __iomem *addr, |
---|
| 166 | + unsigned long len) |
---|
| 167 | +{ |
---|
| 168 | + struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; |
---|
| 169 | + u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len); |
---|
| 170 | + |
---|
| 171 | + return __zpci_load(data, req, ZPCI_OFFSET(addr)); |
---|
| 172 | +} |
---|
| 173 | + |
---|
| 174 | +static inline int __pcilg_mio(u64 *data, u64 ioaddr, u64 len, u8 *status) |
---|
| 175 | +{ |
---|
| 176 | + register u64 addr asm("2") = ioaddr; |
---|
| 177 | + register u64 r3 asm("3") = len; |
---|
| 178 | + int cc = -ENXIO; |
---|
| 179 | + u64 __data; |
---|
| 180 | + |
---|
| 181 | + asm volatile ( |
---|
| 182 | + " .insn rre,0xb9d60000,%[data],%[ioaddr]\n" |
---|
| 183 | + "0: ipm %[cc]\n" |
---|
| 184 | + " srl %[cc],28\n" |
---|
| 185 | + "1:\n" |
---|
| 186 | + EX_TABLE(0b, 1b) |
---|
| 187 | + : [cc] "+d" (cc), [data] "=d" (__data), "+d" (r3) |
---|
| 188 | + : [ioaddr] "d" (addr) |
---|
| 189 | + : "cc"); |
---|
| 190 | + *status = r3 >> 24 & 0xff; |
---|
| 191 | + *data = __data; |
---|
| 192 | + return cc; |
---|
| 193 | +} |
---|
| 194 | + |
---|
| 195 | +int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len) |
---|
| 196 | +{ |
---|
| 197 | + u8 status; |
---|
| 198 | + int cc; |
---|
| 199 | + |
---|
| 200 | + if (!static_branch_unlikely(&have_mio)) |
---|
| 201 | + return zpci_load_fh(data, addr, len); |
---|
| 202 | + |
---|
| 203 | + cc = __pcilg_mio(data, (__force u64) addr, len, &status); |
---|
| 204 | + if (cc) |
---|
| 205 | + zpci_err_insn(cc, status, 0, (__force u64) addr); |
---|
156 | 206 | |
---|
157 | 207 | return (cc > 0) ? -EIO : cc; |
---|
158 | 208 | } |
---|
.. | .. |
---|
178 | 228 | return cc; |
---|
179 | 229 | } |
---|
180 | 230 | |
---|
181 | | -int zpci_store(u64 data, u64 req, u64 offset) |
---|
| 231 | +int __zpci_store(u64 data, u64 req, u64 offset) |
---|
182 | 232 | { |
---|
183 | 233 | u8 status; |
---|
184 | 234 | int cc; |
---|
.. | .. |
---|
191 | 241 | |
---|
192 | 242 | if (cc) |
---|
193 | 243 | zpci_err_insn(cc, status, req, offset); |
---|
| 244 | + |
---|
| 245 | + return (cc > 0) ? -EIO : cc; |
---|
| 246 | +} |
---|
| 247 | +EXPORT_SYMBOL_GPL(__zpci_store); |
---|
| 248 | + |
---|
| 249 | +static inline int zpci_store_fh(const volatile void __iomem *addr, u64 data, |
---|
| 250 | + unsigned long len) |
---|
| 251 | +{ |
---|
| 252 | + struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; |
---|
| 253 | + u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len); |
---|
| 254 | + |
---|
| 255 | + return __zpci_store(data, req, ZPCI_OFFSET(addr)); |
---|
| 256 | +} |
---|
| 257 | + |
---|
| 258 | +static inline int __pcistg_mio(u64 data, u64 ioaddr, u64 len, u8 *status) |
---|
| 259 | +{ |
---|
| 260 | + register u64 addr asm("2") = ioaddr; |
---|
| 261 | + register u64 r3 asm("3") = len; |
---|
| 262 | + int cc = -ENXIO; |
---|
| 263 | + |
---|
| 264 | + asm volatile ( |
---|
| 265 | + " .insn rre,0xb9d40000,%[data],%[ioaddr]\n" |
---|
| 266 | + "0: ipm %[cc]\n" |
---|
| 267 | + " srl %[cc],28\n" |
---|
| 268 | + "1:\n" |
---|
| 269 | + EX_TABLE(0b, 1b) |
---|
| 270 | + : [cc] "+d" (cc), "+d" (r3) |
---|
| 271 | + : [data] "d" (data), [ioaddr] "d" (addr) |
---|
| 272 | + : "cc"); |
---|
| 273 | + *status = r3 >> 24 & 0xff; |
---|
| 274 | + return cc; |
---|
| 275 | +} |
---|
| 276 | + |
---|
| 277 | +int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len) |
---|
| 278 | +{ |
---|
| 279 | + u8 status; |
---|
| 280 | + int cc; |
---|
| 281 | + |
---|
| 282 | + if (!static_branch_unlikely(&have_mio)) |
---|
| 283 | + return zpci_store_fh(addr, data, len); |
---|
| 284 | + |
---|
| 285 | + cc = __pcistg_mio(data, (__force u64) addr, len, &status); |
---|
| 286 | + if (cc) |
---|
| 287 | + zpci_err_insn(cc, status, 0, (__force u64) addr); |
---|
194 | 288 | |
---|
195 | 289 | return (cc > 0) ? -EIO : cc; |
---|
196 | 290 | } |
---|
.. | .. |
---|
214 | 308 | return cc; |
---|
215 | 309 | } |
---|
216 | 310 | |
---|
217 | | -int zpci_store_block(const u64 *data, u64 req, u64 offset) |
---|
| 311 | +int __zpci_store_block(const u64 *data, u64 req, u64 offset) |
---|
218 | 312 | { |
---|
219 | 313 | u8 status; |
---|
220 | 314 | int cc; |
---|
.. | .. |
---|
230 | 324 | |
---|
231 | 325 | return (cc > 0) ? -EIO : cc; |
---|
232 | 326 | } |
---|
233 | | -EXPORT_SYMBOL_GPL(zpci_store_block); |
---|
| 327 | +EXPORT_SYMBOL_GPL(__zpci_store_block); |
---|
| 328 | + |
---|
| 329 | +static inline int zpci_write_block_fh(volatile void __iomem *dst, |
---|
| 330 | + const void *src, unsigned long len) |
---|
| 331 | +{ |
---|
| 332 | + struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)]; |
---|
| 333 | + u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len); |
---|
| 334 | + u64 offset = ZPCI_OFFSET(dst); |
---|
| 335 | + |
---|
| 336 | + return __zpci_store_block(src, req, offset); |
---|
| 337 | +} |
---|
| 338 | + |
---|
| 339 | +static inline int __pcistb_mio(const u64 *data, u64 ioaddr, u64 len, u8 *status) |
---|
| 340 | +{ |
---|
| 341 | + int cc = -ENXIO; |
---|
| 342 | + |
---|
| 343 | + asm volatile ( |
---|
| 344 | + " .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[data]\n" |
---|
| 345 | + "0: ipm %[cc]\n" |
---|
| 346 | + " srl %[cc],28\n" |
---|
| 347 | + "1:\n" |
---|
| 348 | + EX_TABLE(0b, 1b) |
---|
| 349 | + : [cc] "+d" (cc), [len] "+d" (len) |
---|
| 350 | + : [ioaddr] "d" (ioaddr), [data] "Q" (*data) |
---|
| 351 | + : "cc"); |
---|
| 352 | + *status = len >> 24 & 0xff; |
---|
| 353 | + return cc; |
---|
| 354 | +} |
---|
| 355 | + |
---|
| 356 | +int zpci_write_block(volatile void __iomem *dst, |
---|
| 357 | + const void *src, unsigned long len) |
---|
| 358 | +{ |
---|
| 359 | + u8 status; |
---|
| 360 | + int cc; |
---|
| 361 | + |
---|
| 362 | + if (!static_branch_unlikely(&have_mio)) |
---|
| 363 | + return zpci_write_block_fh(dst, src, len); |
---|
| 364 | + |
---|
| 365 | + cc = __pcistb_mio(src, (__force u64) dst, len, &status); |
---|
| 366 | + if (cc) |
---|
| 367 | + zpci_err_insn(cc, status, 0, (__force u64) dst); |
---|
| 368 | + |
---|
| 369 | + return (cc > 0) ? -EIO : cc; |
---|
| 370 | +} |
---|
| 371 | +EXPORT_SYMBOL_GPL(zpci_write_block); |
---|
| 372 | + |
---|
| 373 | +static inline void __pciwb_mio(void) |
---|
| 374 | +{ |
---|
| 375 | + unsigned long unused = 0; |
---|
| 376 | + |
---|
| 377 | + asm volatile (".insn rre,0xb9d50000,%[op],%[op]\n" |
---|
| 378 | + : [op] "+d" (unused)); |
---|
| 379 | +} |
---|
| 380 | + |
---|
| 381 | +void zpci_barrier(void) |
---|
| 382 | +{ |
---|
| 383 | + if (static_branch_likely(&have_mio)) |
---|
| 384 | + __pciwb_mio(); |
---|
| 385 | +} |
---|
| 386 | +EXPORT_SYMBOL_GPL(zpci_barrier); |
---|