1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2015, 2016 Cavium, Inc. |
4 | */ |
5 | |
6 | #include <linux/kernel.h> |
7 | #include <linux/init.h> |
8 | #include <linux/ioport.h> |
9 | #include <linux/of_pci.h> |
10 | #include <linux/of.h> |
11 | #include <linux/pci-ecam.h> |
12 | #include <linux/platform_device.h> |
13 | |
14 | #if defined(CONFIG_PCI_HOST_THUNDER_ECAM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) |
15 | |
16 | static void set_val(u32 v, int where, int size, u32 *val) |
17 | { |
18 | int shift = (where & 3) * 8; |
19 | |
20 | pr_debug("set_val %04x: %08x\n" , (unsigned int)(where & ~3), v); |
21 | v >>= shift; |
22 | if (size == 1) |
23 | v &= 0xff; |
24 | else if (size == 2) |
25 | v &= 0xffff; |
26 | *val = v; |
27 | } |
28 | |
29 | static int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus, |
30 | unsigned int devfn, int where, int size, u32 *val) |
31 | { |
32 | void __iomem *addr; |
33 | u32 v; |
34 | |
35 | /* Entries are 16-byte aligned; bits[2,3] select word in entry */ |
36 | int where_a = where & 0xc; |
37 | |
38 | if (where_a == 0) { |
39 | set_val(v: e0, where, size, val); |
40 | return PCIBIOS_SUCCESSFUL; |
41 | } |
42 | if (where_a == 0x4) { |
43 | addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */ |
44 | if (!addr) |
45 | return PCIBIOS_DEVICE_NOT_FOUND; |
46 | |
47 | v = readl(addr); |
48 | v &= ~0xf; |
49 | v |= 2; /* EA entry-1. Base-L */ |
50 | set_val(v, where, size, val); |
51 | return PCIBIOS_SUCCESSFUL; |
52 | } |
53 | if (where_a == 0x8) { |
54 | u32 barl_orig; |
55 | u32 barl_rb; |
56 | |
57 | addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */ |
58 | if (!addr) |
59 | return PCIBIOS_DEVICE_NOT_FOUND; |
60 | |
61 | barl_orig = readl(addr: addr + 0); |
62 | writel(val: 0xffffffff, addr: addr + 0); |
63 | barl_rb = readl(addr: addr + 0); |
64 | writel(val: barl_orig, addr: addr + 0); |
65 | /* zeros in unsettable bits */ |
66 | v = ~barl_rb & ~3; |
67 | v |= 0xc; /* EA entry-2. Offset-L */ |
68 | set_val(v, where, size, val); |
69 | return PCIBIOS_SUCCESSFUL; |
70 | } |
71 | if (where_a == 0xc) { |
72 | addr = bus->ops->map_bus(bus, devfn, bar + 4); /* BAR 1 */ |
73 | if (!addr) |
74 | return PCIBIOS_DEVICE_NOT_FOUND; |
75 | |
76 | v = readl(addr); /* EA entry-3. Base-H */ |
77 | set_val(v, where, size, val); |
78 | return PCIBIOS_SUCCESSFUL; |
79 | } |
80 | return PCIBIOS_DEVICE_NOT_FOUND; |
81 | } |
82 | |
83 | static int thunder_ecam_p2_config_read(struct pci_bus *bus, unsigned int devfn, |
84 | int where, int size, u32 *val) |
85 | { |
86 | struct pci_config_window *cfg = bus->sysdata; |
87 | int where_a = where & ~3; |
88 | void __iomem *addr; |
89 | u32 node_bits; |
90 | u32 v; |
91 | |
92 | /* EA Base[63:32] may be missing some bits ... */ |
93 | switch (where_a) { |
94 | case 0xa8: |
95 | case 0xbc: |
96 | case 0xd0: |
97 | case 0xe4: |
98 | break; |
99 | default: |
100 | return pci_generic_config_read(bus, devfn, where, size, val); |
101 | } |
102 | |
103 | addr = bus->ops->map_bus(bus, devfn, where_a); |
104 | if (!addr) |
105 | return PCIBIOS_DEVICE_NOT_FOUND; |
106 | |
107 | v = readl(addr); |
108 | |
109 | /* |
110 | * Bit 44 of the 64-bit Base must match the same bit in |
111 | * the config space access window. Since we are working with |
112 | * the high-order 32 bits, shift everything down by 32 bits. |
113 | */ |
114 | node_bits = upper_32_bits(cfg->res.start) & (1 << 12); |
115 | |
116 | v |= node_bits; |
117 | set_val(v, where, size, val); |
118 | |
119 | return PCIBIOS_SUCCESSFUL; |
120 | } |
121 | |
122 | static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn, |
123 | int where, int size, u32 *val) |
124 | { |
125 | u32 v; |
126 | u32 vendor_device; |
127 | u32 class_rev; |
128 | void __iomem *addr; |
129 | int cfg_type; |
130 | int where_a = where & ~3; |
131 | |
132 | addr = bus->ops->map_bus(bus, devfn, 0xc); |
133 | if (!addr) |
134 | return PCIBIOS_DEVICE_NOT_FOUND; |
135 | |
136 | v = readl(addr); |
137 | |
138 | /* Check for non type-00 header */ |
139 | cfg_type = (v >> 16) & 0x7f; |
140 | |
141 | addr = bus->ops->map_bus(bus, devfn, 8); |
142 | if (!addr) |
143 | return PCIBIOS_DEVICE_NOT_FOUND; |
144 | |
145 | class_rev = readl(addr); |
146 | if (class_rev == 0xffffffff) |
147 | goto no_emulation; |
148 | |
149 | if ((class_rev & 0xff) >= 8) { |
150 | /* Pass-2 handling */ |
151 | if (cfg_type) |
152 | goto no_emulation; |
153 | return thunder_ecam_p2_config_read(bus, devfn, where, |
154 | size, val); |
155 | } |
156 | |
157 | /* |
158 | * All BARs have fixed addresses specified by the EA |
159 | * capability; they must return zero on read. |
160 | */ |
161 | if (cfg_type == 0 && |
162 | ((where >= 0x10 && where < 0x2c) || |
163 | (where >= 0x1a4 && where < 0x1bc))) { |
164 | /* BAR or SR-IOV BAR */ |
165 | *val = 0; |
166 | return PCIBIOS_SUCCESSFUL; |
167 | } |
168 | |
169 | addr = bus->ops->map_bus(bus, devfn, 0); |
170 | if (!addr) |
171 | return PCIBIOS_DEVICE_NOT_FOUND; |
172 | |
173 | vendor_device = readl(addr); |
174 | if (vendor_device == 0xffffffff) |
175 | goto no_emulation; |
176 | |
177 | pr_debug("%04x:%04x - Fix pass#: %08x, where: %03x, devfn: %03x\n" , |
178 | vendor_device & 0xffff, vendor_device >> 16, class_rev, |
179 | (unsigned int)where, devfn); |
180 | |
181 | /* Check for non type-00 header */ |
182 | if (cfg_type == 0) { |
183 | bool has_msix; |
184 | bool is_nic = (vendor_device == 0xa01e177d); |
185 | bool is_tns = (vendor_device == 0xa01f177d); |
186 | |
187 | addr = bus->ops->map_bus(bus, devfn, 0x70); |
188 | if (!addr) |
189 | return PCIBIOS_DEVICE_NOT_FOUND; |
190 | |
191 | /* E_CAP */ |
192 | v = readl(addr); |
193 | has_msix = (v & 0xff00) != 0; |
194 | |
195 | if (!has_msix && where_a == 0x70) { |
196 | v |= 0xbc00; /* next capability is EA at 0xbc */ |
197 | set_val(v, where, size, val); |
198 | return PCIBIOS_SUCCESSFUL; |
199 | } |
200 | if (where_a == 0xb0) { |
201 | addr = bus->ops->map_bus(bus, devfn, where_a); |
202 | if (!addr) |
203 | return PCIBIOS_DEVICE_NOT_FOUND; |
204 | |
205 | v = readl(addr); |
206 | if (v & 0xff00) |
207 | pr_err("Bad MSIX cap header: %08x\n" , v); |
208 | v |= 0xbc00; /* next capability is EA at 0xbc */ |
209 | set_val(v, where, size, val); |
210 | return PCIBIOS_SUCCESSFUL; |
211 | } |
212 | if (where_a == 0xbc) { |
213 | if (is_nic) |
214 | v = 0x40014; /* EA last in chain, 4 entries */ |
215 | else if (is_tns) |
216 | v = 0x30014; /* EA last in chain, 3 entries */ |
217 | else if (has_msix) |
218 | v = 0x20014; /* EA last in chain, 2 entries */ |
219 | else |
220 | v = 0x10014; /* EA last in chain, 1 entry */ |
221 | set_val(v, where, size, val); |
222 | return PCIBIOS_SUCCESSFUL; |
223 | } |
224 | if (where_a >= 0xc0 && where_a < 0xd0) |
225 | /* EA entry-0. PP=0, BAR0 Size:3 */ |
226 | return handle_ea_bar(e0: 0x80ff0003, |
227 | bar: 0x10, bus, devfn, where, |
228 | size, val); |
229 | if (where_a >= 0xd0 && where_a < 0xe0 && has_msix) |
230 | /* EA entry-1. PP=0, BAR4 Size:3 */ |
231 | return handle_ea_bar(e0: 0x80ff0043, |
232 | bar: 0x20, bus, devfn, where, |
233 | size, val); |
234 | if (where_a >= 0xe0 && where_a < 0xf0 && is_tns) |
235 | /* EA entry-2. PP=0, BAR2, Size:3 */ |
236 | return handle_ea_bar(e0: 0x80ff0023, |
237 | bar: 0x18, bus, devfn, where, |
238 | size, val); |
239 | if (where_a >= 0xe0 && where_a < 0xf0 && is_nic) |
240 | /* EA entry-2. PP=4, VF_BAR0 (9), Size:3 */ |
241 | return handle_ea_bar(e0: 0x80ff0493, |
242 | bar: 0x1a4, bus, devfn, where, |
243 | size, val); |
244 | if (where_a >= 0xf0 && where_a < 0x100 && is_nic) |
245 | /* EA entry-3. PP=4, VF_BAR4 (d), Size:3 */ |
246 | return handle_ea_bar(e0: 0x80ff04d3, |
247 | bar: 0x1b4, bus, devfn, where, |
248 | size, val); |
249 | } else if (cfg_type == 1) { |
250 | bool is_rsl_bridge = devfn == 0x08; |
251 | bool is_rad_bridge = devfn == 0xa0; |
252 | bool is_zip_bridge = devfn == 0xa8; |
253 | bool is_dfa_bridge = devfn == 0xb0; |
254 | bool is_nic_bridge = devfn == 0x10; |
255 | |
256 | if (where_a == 0x70) { |
257 | addr = bus->ops->map_bus(bus, devfn, where_a); |
258 | if (!addr) |
259 | return PCIBIOS_DEVICE_NOT_FOUND; |
260 | |
261 | v = readl(addr); |
262 | if (v & 0xff00) |
263 | pr_err("Bad PCIe cap header: %08x\n" , v); |
264 | v |= 0xbc00; /* next capability is EA at 0xbc */ |
265 | set_val(v, where, size, val); |
266 | return PCIBIOS_SUCCESSFUL; |
267 | } |
268 | if (where_a == 0xbc) { |
269 | if (is_nic_bridge) |
270 | v = 0x10014; /* EA last in chain, 1 entry */ |
271 | else |
272 | v = 0x00014; /* EA last in chain, no entries */ |
273 | set_val(v, where, size, val); |
274 | return PCIBIOS_SUCCESSFUL; |
275 | } |
276 | if (where_a == 0xc0) { |
277 | if (is_rsl_bridge || is_nic_bridge) |
278 | v = 0x0101; /* subordinate:secondary = 1:1 */ |
279 | else if (is_rad_bridge) |
280 | v = 0x0202; /* subordinate:secondary = 2:2 */ |
281 | else if (is_zip_bridge) |
282 | v = 0x0303; /* subordinate:secondary = 3:3 */ |
283 | else if (is_dfa_bridge) |
284 | v = 0x0404; /* subordinate:secondary = 4:4 */ |
285 | set_val(v, where, size, val); |
286 | return PCIBIOS_SUCCESSFUL; |
287 | } |
288 | if (where_a == 0xc4 && is_nic_bridge) { |
289 | /* Enabled, not-Write, SP=ff, PP=05, BEI=6, ES=4 */ |
290 | v = 0x80ff0564; |
291 | set_val(v, where, size, val); |
292 | return PCIBIOS_SUCCESSFUL; |
293 | } |
294 | if (where_a == 0xc8 && is_nic_bridge) { |
295 | v = 0x00000002; /* Base-L 64-bit */ |
296 | set_val(v, where, size, val); |
297 | return PCIBIOS_SUCCESSFUL; |
298 | } |
299 | if (where_a == 0xcc && is_nic_bridge) { |
300 | v = 0xfffffffe; /* MaxOffset-L 64-bit */ |
301 | set_val(v, where, size, val); |
302 | return PCIBIOS_SUCCESSFUL; |
303 | } |
304 | if (where_a == 0xd0 && is_nic_bridge) { |
305 | v = 0x00008430; /* NIC Base-H */ |
306 | set_val(v, where, size, val); |
307 | return PCIBIOS_SUCCESSFUL; |
308 | } |
309 | if (where_a == 0xd4 && is_nic_bridge) { |
310 | v = 0x0000000f; /* MaxOffset-H */ |
311 | set_val(v, where, size, val); |
312 | return PCIBIOS_SUCCESSFUL; |
313 | } |
314 | } |
315 | no_emulation: |
316 | return pci_generic_config_read(bus, devfn, where, size, val); |
317 | } |
318 | |
319 | static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn, |
320 | int where, int size, u32 val) |
321 | { |
322 | /* |
323 | * All BARs have fixed addresses; ignore BAR writes so they |
324 | * don't get corrupted. |
325 | */ |
326 | if ((where >= 0x10 && where < 0x2c) || |
327 | (where >= 0x1a4 && where < 0x1bc)) |
328 | /* BAR or SR-IOV BAR */ |
329 | return PCIBIOS_SUCCESSFUL; |
330 | |
331 | return pci_generic_config_write(bus, devfn, where, size, val); |
332 | } |
333 | |
334 | const struct pci_ecam_ops pci_thunder_ecam_ops = { |
335 | .pci_ops = { |
336 | .map_bus = pci_ecam_map_bus, |
337 | .read = thunder_ecam_config_read, |
338 | .write = thunder_ecam_config_write, |
339 | } |
340 | }; |
341 | |
342 | #ifdef CONFIG_PCI_HOST_THUNDER_ECAM |
343 | |
344 | static const struct of_device_id thunder_ecam_of_match[] = { |
345 | { |
346 | .compatible = "cavium,pci-host-thunder-ecam" , |
347 | .data = &pci_thunder_ecam_ops, |
348 | }, |
349 | { }, |
350 | }; |
351 | |
352 | static struct platform_driver thunder_ecam_driver = { |
353 | .driver = { |
354 | .name = KBUILD_MODNAME, |
355 | .of_match_table = thunder_ecam_of_match, |
356 | .suppress_bind_attrs = true, |
357 | }, |
358 | .probe = pci_host_common_probe, |
359 | }; |
360 | builtin_platform_driver(thunder_ecam_driver); |
361 | |
362 | #endif |
363 | #endif |
364 | |