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