Commit | Line | Data |
---|---|---|
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 */ | |
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 | ||
9389339f | 30 | int zpci_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 */ | |
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 | ||
9389339f | 64 | int zpci_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 */ | |
9389339f | 81 | void zpci_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 | 89 | static 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; | |
b170bad4 SO |
106 | if (!cc) |
107 | *data = __data; | |
108 | ||
cbcca5d0 SO |
109 | return cc; |
110 | } | |
111 | ||
9389339f | 112 | int zpci_load(u64 *data, u64 req, u64 offset) |
cbcca5d0 | 113 | { |
f0bacb7f SO |
114 | u8 status; |
115 | int cc; | |
cbcca5d0 SO |
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 | ||
f0bacb7f | 123 | if (cc) |
cbcca5d0 SO |
124 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", |
125 | __func__, cc, status, req, offset); | |
f0bacb7f | 126 | return (cc > 0) ? -EIO : cc; |
cbcca5d0 | 127 | } |
9389339f | 128 | EXPORT_SYMBOL_GPL(zpci_load); |
cbcca5d0 SO |
129 | |
130 | /* PCI Store */ | |
f0bacb7f | 131 | static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status) |
cbcca5d0 SO |
132 | { |
133 | register u64 __req asm("2") = req; | |
134 | register u64 __offset asm("3") = offset; | |
f0bacb7f | 135 | int cc = -ENXIO; |
cbcca5d0 SO |
136 | |
137 | asm volatile ( | |
138 | " .insn rre,0xb9d00000,%[data],%[req]\n" | |
f0bacb7f | 139 | "0: ipm %[cc]\n" |
cbcca5d0 | 140 | " srl %[cc],28\n" |
f0bacb7f SO |
141 | "1:\n" |
142 | EX_TABLE(0b, 1b) | |
143 | : [cc] "+d" (cc), [req] "+d" (__req) | |
cbcca5d0 SO |
144 | : "d" (__offset), [data] "d" (data) |
145 | : "cc"); | |
146 | *status = __req >> 24 & 0xff; | |
147 | return cc; | |
148 | } | |
149 | ||
9389339f | 150 | int zpci_store(u64 data, u64 req, u64 offset) |
cbcca5d0 | 151 | { |
f0bacb7f SO |
152 | u8 status; |
153 | int cc; | |
cbcca5d0 SO |
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); | |
f0bacb7f | 164 | return (cc > 0) ? -EIO : cc; |
cbcca5d0 | 165 | } |
9389339f | 166 | EXPORT_SYMBOL_GPL(zpci_store); |
cbcca5d0 SO |
167 | |
168 | /* PCI Store Block */ | |
f0bacb7f | 169 | static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) |
cbcca5d0 | 170 | { |
f0bacb7f | 171 | int cc = -ENXIO; |
cbcca5d0 SO |
172 | |
173 | asm volatile ( | |
174 | " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" | |
f0bacb7f | 175 | "0: ipm %[cc]\n" |
cbcca5d0 | 176 | " srl %[cc],28\n" |
f0bacb7f SO |
177 | "1:\n" |
178 | EX_TABLE(0b, 1b) | |
179 | : [cc] "+d" (cc), [req] "+d" (req) | |
cbcca5d0 SO |
180 | : [offset] "d" (offset), [data] "Q" (*data) |
181 | : "cc"); | |
182 | *status = req >> 24 & 0xff; | |
183 | return cc; | |
184 | } | |
185 | ||
9389339f | 186 | int zpci_store_block(const u64 *data, u64 req, u64 offset) |
cbcca5d0 | 187 | { |
f0bacb7f SO |
188 | u8 status; |
189 | int cc; | |
cbcca5d0 SO |
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); | |
f0bacb7f | 200 | return (cc > 0) ? -EIO : cc; |
cbcca5d0 | 201 | } |
9389339f | 202 | EXPORT_SYMBOL_GPL(zpci_store_block); |