linux/arch/s390/pci/pci_insn.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * s390 specific pci instructions
   4 *
   5 * Copyright IBM Corp. 2013
   6 */
   7
   8#include <linux/export.h>
   9#include <linux/errno.h>
  10#include <linux/delay.h>
  11#include <linux/jump_label.h>
  12#include <asm/facility.h>
  13#include <asm/pci_insn.h>
  14#include <asm/pci_debug.h>
  15#include <asm/pci_io.h>
  16#include <asm/processor.h>
  17
  18#define ZPCI_INSN_BUSY_DELAY    1       /* 1 microsecond */
  19
  20static inline void zpci_err_insn(u8 cc, u8 status, u64 req, u64 offset)
  21{
  22        struct {
  23                u64 req;
  24                u64 offset;
  25                u8 cc;
  26                u8 status;
  27        } __packed data = {req, offset, cc, status};
  28
  29        zpci_err_hex(&data, sizeof(data));
  30}
  31
  32/* Modify PCI Function Controls */
  33static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
  34{
  35        u8 cc;
  36
  37        asm volatile (
  38                "       .insn   rxy,0xe300000000d0,%[req],%[fib]\n"
  39                "       ipm     %[cc]\n"
  40                "       srl     %[cc],28\n"
  41                : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
  42                : : "cc");
  43        *status = req >> 24 & 0xff;
  44        return cc;
  45}
  46
  47u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status)
  48{
  49        u8 cc;
  50
  51        do {
  52                cc = __mpcifc(req, fib, status);
  53                if (cc == 2)
  54                        msleep(ZPCI_INSN_BUSY_DELAY);
  55        } while (cc == 2);
  56
  57        if (cc)
  58                zpci_err_insn(cc, *status, req, 0);
  59
  60        return cc;
  61}
  62
  63/* Refresh PCI Translations */
  64static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
  65{
  66        register u64 __addr asm("2") = addr;
  67        register u64 __range asm("3") = range;
  68        u8 cc;
  69
  70        asm volatile (
  71                "       .insn   rre,0xb9d30000,%[fn],%[addr]\n"
  72                "       ipm     %[cc]\n"
  73                "       srl     %[cc],28\n"
  74                : [cc] "=d" (cc), [fn] "+d" (fn)
  75                : [addr] "d" (__addr), "d" (__range)
  76                : "cc");
  77        *status = fn >> 24 & 0xff;
  78        return cc;
  79}
  80
  81int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
  82{
  83        u8 cc, status;
  84
  85        do {
  86                cc = __rpcit(fn, addr, range, &status);
  87                if (cc == 2)
  88                        udelay(ZPCI_INSN_BUSY_DELAY);
  89        } while (cc == 2);
  90
  91        if (cc)
  92                zpci_err_insn(cc, status, addr, range);
  93
  94        if (cc == 1 && (status == 4 || status == 16))
  95                return -ENOMEM;
  96
  97        return (cc) ? -EIO : 0;
  98}
  99
 100/* Set Interruption Controls */
 101int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib)
 102{
 103        if (!test_facility(72))
 104                return -EIO;
 105
 106        asm volatile(
 107                ".insn  rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]\n"
 108                : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [iib] "Q" (*iib));
 109
 110        return 0;
 111}
 112
 113/* PCI Load */
 114static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status)
 115{
 116        register u64 __req asm("2") = req;
 117        register u64 __offset asm("3") = offset;
 118        int cc = -ENXIO;
 119        u64 __data;
 120
 121        asm volatile (
 122                "       .insn   rre,0xb9d20000,%[data],%[req]\n"
 123                "0:     ipm     %[cc]\n"
 124                "       srl     %[cc],28\n"
 125                "1:\n"
 126                EX_TABLE(0b, 1b)
 127                : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req)
 128                :  "d" (__offset)
 129                : "cc");
 130        *status = __req >> 24 & 0xff;
 131        *data = __data;
 132        return cc;
 133}
 134
 135static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
 136{
 137        u64 __data;
 138        int cc;
 139
 140        cc = ____pcilg(&__data, req, offset, status);
 141        if (!cc)
 142                *data = __data;
 143
 144        return cc;
 145}
 146
 147int __zpci_load(u64 *data, u64 req, u64 offset)
 148{
 149        u8 status;
 150        int cc;
 151
 152        do {
 153                cc = __pcilg(data, req, offset, &status);
 154                if (cc == 2)
 155                        udelay(ZPCI_INSN_BUSY_DELAY);
 156        } while (cc == 2);
 157
 158        if (cc)
 159                zpci_err_insn(cc, status, req, offset);
 160
 161        return (cc > 0) ? -EIO : cc;
 162}
 163EXPORT_SYMBOL_GPL(__zpci_load);
 164
 165static 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
 174static 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
 195int 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);
 206
 207        return (cc > 0) ? -EIO : cc;
 208}
 209EXPORT_SYMBOL_GPL(zpci_load);
 210
 211/* PCI Store */
 212static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
 213{
 214        register u64 __req asm("2") = req;
 215        register u64 __offset asm("3") = offset;
 216        int cc = -ENXIO;
 217
 218        asm volatile (
 219                "       .insn   rre,0xb9d00000,%[data],%[req]\n"
 220                "0:     ipm     %[cc]\n"
 221                "       srl     %[cc],28\n"
 222                "1:\n"
 223                EX_TABLE(0b, 1b)
 224                : [cc] "+d" (cc), [req] "+d" (__req)
 225                : "d" (__offset), [data] "d" (data)
 226                : "cc");
 227        *status = __req >> 24 & 0xff;
 228        return cc;
 229}
 230
 231int __zpci_store(u64 data, u64 req, u64 offset)
 232{
 233        u8 status;
 234        int cc;
 235
 236        do {
 237                cc = __pcistg(data, req, offset, &status);
 238                if (cc == 2)
 239                        udelay(ZPCI_INSN_BUSY_DELAY);
 240        } while (cc == 2);
 241
 242        if (cc)
 243                zpci_err_insn(cc, status, req, offset);
 244
 245        return (cc > 0) ? -EIO : cc;
 246}
 247EXPORT_SYMBOL_GPL(__zpci_store);
 248
 249static 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
 258static 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
 277int 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);
 288
 289        return (cc > 0) ? -EIO : cc;
 290}
 291EXPORT_SYMBOL_GPL(zpci_store);
 292
 293/* PCI Store Block */
 294static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
 295{
 296        int cc = -ENXIO;
 297
 298        asm volatile (
 299                "       .insn   rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
 300                "0:     ipm     %[cc]\n"
 301                "       srl     %[cc],28\n"
 302                "1:\n"
 303                EX_TABLE(0b, 1b)
 304                : [cc] "+d" (cc), [req] "+d" (req)
 305                : [offset] "d" (offset), [data] "Q" (*data)
 306                : "cc");
 307        *status = req >> 24 & 0xff;
 308        return cc;
 309}
 310
 311int __zpci_store_block(const u64 *data, u64 req, u64 offset)
 312{
 313        u8 status;
 314        int cc;
 315
 316        do {
 317                cc = __pcistb(data, req, offset, &status);
 318                if (cc == 2)
 319                        udelay(ZPCI_INSN_BUSY_DELAY);
 320        } while (cc == 2);
 321
 322        if (cc)
 323                zpci_err_insn(cc, status, req, offset);
 324
 325        return (cc > 0) ? -EIO : cc;
 326}
 327EXPORT_SYMBOL_GPL(__zpci_store_block);
 328
 329static 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
 339static 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
 356int 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}
 371EXPORT_SYMBOL_GPL(zpci_write_block);
 372
 373static 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
 381void zpci_barrier(void)
 382{
 383        if (static_branch_likely(&have_mio))
 384                __pciwb_mio();
 385}
 386EXPORT_SYMBOL_GPL(zpci_barrier);
 387