| .. | .. |
|---|
| 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); |
|---|