s390/pci: add exception table to load/store instructions
[deliverable/linux.git] / arch / s390 / pci / pci_insn.c
CommitLineData
cbcca5d0
SO
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>
f0bacb7f 11#include <asm/processor.h>
cbcca5d0
SO
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
b2a9e87d 30int s390pci_mod_fc(u64 req, struct zpci_fib *fib)
cbcca5d0
SO
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
b2a9e87d 64int s390pci_refresh_trans(u64 fn, u64 addr, u64 range)
cbcca5d0
SO
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 */
b2a9e87d 81void set_irq_ctrl(u16 ctl, char *unused, u8 isc)
cbcca5d0
SO
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 */
f0bacb7f 89static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
cbcca5d0
SO
90{
91 register u64 __req asm("2") = req;
92 register u64 __offset asm("3") = offset;
f0bacb7f 93 int cc = -ENXIO;
cbcca5d0 94 u64 __data;
cbcca5d0
SO
95
96 asm volatile (
97 " .insn rre,0xb9d20000,%[data],%[req]\n"
f0bacb7f 98 "0: ipm %[cc]\n"
cbcca5d0 99 " srl %[cc],28\n"
f0bacb7f
SO
100 "1:\n"
101 EX_TABLE(0b, 1b)
102 : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req)
cbcca5d0
SO
103 : "d" (__offset)
104 : "cc");
105 *status = __req >> 24 & 0xff;
106 *data = __data;
107 return cc;
108}
109
b2a9e87d 110int s390pci_load(u64 *data, u64 req, u64 offset)
cbcca5d0 111{
f0bacb7f
SO
112 u8 status;
113 int cc;
cbcca5d0
SO
114
115 do {
116 cc = __pcilg(data, req, offset, &status);
117 if (cc == 2)
118 udelay(ZPCI_INSN_BUSY_DELAY);
119 } while (cc == 2);
120
f0bacb7f 121 if (cc)
cbcca5d0
SO
122 printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
123 __func__, cc, status, req, offset);
f0bacb7f 124 return (cc > 0) ? -EIO : cc;
cbcca5d0 125}
b2a9e87d 126EXPORT_SYMBOL_GPL(s390pci_load);
cbcca5d0
SO
127
128/* PCI Store */
f0bacb7f 129static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
cbcca5d0
SO
130{
131 register u64 __req asm("2") = req;
132 register u64 __offset asm("3") = offset;
f0bacb7f 133 int cc = -ENXIO;
cbcca5d0
SO
134
135 asm volatile (
136 " .insn rre,0xb9d00000,%[data],%[req]\n"
f0bacb7f 137 "0: ipm %[cc]\n"
cbcca5d0 138 " srl %[cc],28\n"
f0bacb7f
SO
139 "1:\n"
140 EX_TABLE(0b, 1b)
141 : [cc] "+d" (cc), [req] "+d" (__req)
cbcca5d0
SO
142 : "d" (__offset), [data] "d" (data)
143 : "cc");
144 *status = __req >> 24 & 0xff;
145 return cc;
146}
147
b2a9e87d 148int s390pci_store(u64 data, u64 req, u64 offset)
cbcca5d0 149{
f0bacb7f
SO
150 u8 status;
151 int cc;
cbcca5d0
SO
152
153 do {
154 cc = __pcistg(data, req, offset, &status);
155 if (cc == 2)
156 udelay(ZPCI_INSN_BUSY_DELAY);
157 } while (cc == 2);
158
159 if (cc)
160 printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
161 __func__, cc, status, req, offset);
f0bacb7f 162 return (cc > 0) ? -EIO : cc;
cbcca5d0 163}
b2a9e87d 164EXPORT_SYMBOL_GPL(s390pci_store);
cbcca5d0
SO
165
166/* PCI Store Block */
f0bacb7f 167static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
cbcca5d0 168{
f0bacb7f 169 int cc = -ENXIO;
cbcca5d0
SO
170
171 asm volatile (
172 " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
f0bacb7f 173 "0: ipm %[cc]\n"
cbcca5d0 174 " srl %[cc],28\n"
f0bacb7f
SO
175 "1:\n"
176 EX_TABLE(0b, 1b)
177 : [cc] "+d" (cc), [req] "+d" (req)
cbcca5d0
SO
178 : [offset] "d" (offset), [data] "Q" (*data)
179 : "cc");
180 *status = req >> 24 & 0xff;
181 return cc;
182}
183
b2a9e87d 184int s390pci_store_block(const u64 *data, u64 req, u64 offset)
cbcca5d0 185{
f0bacb7f
SO
186 u8 status;
187 int cc;
cbcca5d0
SO
188
189 do {
190 cc = __pcistb(data, req, offset, &status);
191 if (cc == 2)
192 udelay(ZPCI_INSN_BUSY_DELAY);
193 } while (cc == 2);
194
195 if (cc)
196 printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
197 __func__, cc, status, req, offset);
f0bacb7f 198 return (cc > 0) ? -EIO : cc;
cbcca5d0 199}
b2a9e87d 200EXPORT_SYMBOL_GPL(s390pci_store_block);
This page took 0.034414 seconds and 5 git commands to generate.