Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / s390 / pci / pci_insn.c
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 */
16 static 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
30 int 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 */
47 static 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
64 int 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 */
81 void 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 */
89 static 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
112 int 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 }
128 EXPORT_SYMBOL_GPL(zpci_load);
129
130 /* PCI Store */
131 static 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
150 int 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 }
166 EXPORT_SYMBOL_GPL(zpci_store);
167
168 /* PCI Store Block */
169 static 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
186 int 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 }
202 EXPORT_SYMBOL_GPL(zpci_store_block);