linux/arch/s390/pci/pci_insn.c
<<
>>
Prefs
   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/processor.h>
  12
  13#define ZPCI_INSN_BUSY_DELAY    1       /* 1 microsecond */
  14
  15/* Modify PCI Function Controls */
  16static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
  17{
  18        u8 cc;
  19
  20        asm volatile (
  21                "       .insn   rxy,0xe300000000d0,%[req],%[fib]\n"
  22                "       ipm     %[cc]\n"
  23                "       srl     %[cc],28\n"
  24                : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
  25                : : "cc");
  26        *status = req >> 24 & 0xff;
  27        return cc;
  28}
  29
  30int zpci_mod_fc(u64 req, struct zpci_fib *fib)
  31{
  32        u8 cc, status;
  33
  34        do {
  35                cc = __mpcifc(req, fib, &status);
  36                if (cc == 2)
  37                        msleep(ZPCI_INSN_BUSY_DELAY);
  38        } while (cc == 2);
  39
  40        if (cc)
  41                printk_once(KERN_ERR "%s: error cc: %d  status: %d\n",
  42                             __func__, cc, status);
  43        return (cc) ? -EIO : 0;
  44}
  45
  46/* Refresh PCI Translations */
  47static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
  48{
  49        register u64 __addr asm("2") = addr;
  50        register u64 __range asm("3") = range;
  51        u8 cc;
  52
  53        asm volatile (
  54                "       .insn   rre,0xb9d30000,%[fn],%[addr]\n"
  55                "       ipm     %[cc]\n"
  56                "       srl     %[cc],28\n"
  57                : [cc] "=d" (cc), [fn] "+d" (fn)
  58                : [addr] "d" (__addr), "d" (__range)
  59                : "cc");
  60        *status = fn >> 24 & 0xff;
  61        return cc;
  62}
  63
  64int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
  65{
  66        u8 cc, status;
  67
  68        do {
  69                cc = __rpcit(fn, addr, range, &status);
  70                if (cc == 2)
  71                        udelay(ZPCI_INSN_BUSY_DELAY);
  72        } while (cc == 2);
  73
  74        if (cc)
  75                printk_once(KERN_ERR "%s: error cc: %d  status: %d  dma_addr: %Lx  size: %Lx\n",
  76                            __func__, cc, status, addr, range);
  77        return (cc) ? -EIO : 0;
  78}
  79
  80/* Set Interruption Controls */
  81void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
  82{
  83        asm volatile (
  84                "       .insn   rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
  85                : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
  86}
  87
  88/* PCI Load */
  89static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
  90{
  91        register u64 __req asm("2") = req;
  92        register u64 __offset asm("3") = offset;
  93        int cc = -ENXIO;
  94        u64 __data;
  95
  96        asm volatile (
  97                "       .insn   rre,0xb9d20000,%[data],%[req]\n"
  98                "0:     ipm     %[cc]\n"
  99                "       srl     %[cc],28\n"
 100                "1:\n"
 101                EX_TABLE(0b, 1b)
 102                : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req)
 103                :  "d" (__offset)
 104                : "cc");
 105        *status = __req >> 24 & 0xff;
 106        if (!cc)
 107                *data = __data;
 108
 109        return cc;
 110}
 111
 112int zpci_load(u64 *data, u64 req, u64 offset)
 113{
 114        u8 status;
 115        int cc;
 116
 117        do {
 118                cc = __pcilg(data, req, offset, &status);
 119                if (cc == 2)
 120                        udelay(ZPCI_INSN_BUSY_DELAY);
 121        } while (cc == 2);
 122
 123        if (cc)
 124                printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
 125                            __func__, cc, status, req, offset);
 126        return (cc > 0) ? -EIO : cc;
 127}
 128EXPORT_SYMBOL_GPL(zpci_load);
 129
 130/* PCI Store */
 131static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
 132{
 133        register u64 __req asm("2") = req;
 134        register u64 __offset asm("3") = offset;
 135        int cc = -ENXIO;
 136
 137        asm volatile (
 138                "       .insn   rre,0xb9d00000,%[data],%[req]\n"
 139                "0:     ipm     %[cc]\n"
 140                "       srl     %[cc],28\n"
 141                "1:\n"
 142                EX_TABLE(0b, 1b)
 143                : [cc] "+d" (cc), [req] "+d" (__req)
 144                : "d" (__offset), [data] "d" (data)
 145                : "cc");
 146        *status = __req >> 24 & 0xff;
 147        return cc;
 148}
 149
 150int zpci_store(u64 data, u64 req, u64 offset)
 151{
 152        u8 status;
 153        int cc;
 154
 155        do {
 156                cc = __pcistg(data, req, offset, &status);
 157                if (cc == 2)
 158                        udelay(ZPCI_INSN_BUSY_DELAY);
 159        } while (cc == 2);
 160
 161        if (cc)
 162                printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
 163                        __func__, cc, status, req, offset);
 164        return (cc > 0) ? -EIO : cc;
 165}
 166EXPORT_SYMBOL_GPL(zpci_store);
 167
 168/* PCI Store Block */
 169static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
 170{
 171        int cc = -ENXIO;
 172
 173        asm volatile (
 174                "       .insn   rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
 175                "0:     ipm     %[cc]\n"
 176                "       srl     %[cc],28\n"
 177                "1:\n"
 178                EX_TABLE(0b, 1b)
 179                : [cc] "+d" (cc), [req] "+d" (req)
 180                : [offset] "d" (offset), [data] "Q" (*data)
 181                : "cc");
 182        *status = req >> 24 & 0xff;
 183        return cc;
 184}
 185
 186int zpci_store_block(const u64 *data, u64 req, u64 offset)
 187{
 188        u8 status;
 189        int cc;
 190
 191        do {
 192                cc = __pcistb(data, req, offset, &status);
 193                if (cc == 2)
 194                        udelay(ZPCI_INSN_BUSY_DELAY);
 195        } while (cc == 2);
 196
 197        if (cc)
 198                printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
 199                            __func__, cc, status, req, offset);
 200        return (cc > 0) ? -EIO : cc;
 201}
 202EXPORT_SYMBOL_GPL(zpci_store_block);
 203