1 | /* |
2 | * Broadcom specific AMBA |
3 | * Bus scanning |
4 | * |
5 | * Licensed under the GNU/GPL. See COPYING for details. |
6 | */ |
7 | |
8 | #include "scan.h" |
9 | #include "bcma_private.h" |
10 | |
11 | #include <linux/bcma/bcma.h> |
12 | #include <linux/bcma/bcma_regs.h> |
13 | #include <linux/pci.h> |
14 | #include <linux/io.h> |
15 | #include <linux/dma-mapping.h> |
16 | #include <linux/slab.h> |
17 | |
18 | struct bcma_device_id_name { |
19 | u16 id; |
20 | const char *name; |
21 | }; |
22 | |
23 | static const struct bcma_device_id_name bcma_arm_device_names[] = { |
24 | { BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" }, |
25 | { BCMA_CORE_ARM_1176, "ARM 1176" }, |
26 | { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" }, |
27 | { BCMA_CORE_ARM_CM3, "ARM CM3" }, |
28 | }; |
29 | |
30 | static const struct bcma_device_id_name bcma_bcm_device_names[] = { |
31 | { BCMA_CORE_OOB_ROUTER, "OOB Router" }, |
32 | { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" }, |
33 | { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" }, |
34 | { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" }, |
35 | { BCMA_CORE_NS_PCIEG2, "PCIe Gen 2" }, |
36 | { BCMA_CORE_NS_DMA, "DMA" }, |
37 | { BCMA_CORE_NS_SDIO3, "SDIO3" }, |
38 | { BCMA_CORE_NS_USB20, "USB 2.0" }, |
39 | { BCMA_CORE_NS_USB30, "USB 3.0" }, |
40 | { BCMA_CORE_NS_A9JTAG, "ARM Cortex A9 JTAG" }, |
41 | { BCMA_CORE_NS_DDR23, "Denali DDR2/DDR3 memory controller" }, |
42 | { BCMA_CORE_NS_ROM, "ROM" }, |
43 | { BCMA_CORE_NS_NAND, "NAND flash controller" }, |
44 | { BCMA_CORE_NS_QSPI, "SPI flash controller" }, |
45 | { BCMA_CORE_NS_CHIPCOMMON_B, "Chipcommon B" }, |
46 | { BCMA_CORE_ARMCA9, "ARM Cortex A9 core (ihost)" }, |
47 | { BCMA_CORE_AMEMC, "AMEMC (DDR)" }, |
48 | { BCMA_CORE_ALTA, "ALTA (I2S)" }, |
49 | { BCMA_CORE_INVALID, "Invalid" }, |
50 | { BCMA_CORE_CHIPCOMMON, "ChipCommon" }, |
51 | { BCMA_CORE_ILINE20, "ILine 20" }, |
52 | { BCMA_CORE_SRAM, "SRAM" }, |
53 | { BCMA_CORE_SDRAM, "SDRAM" }, |
54 | { BCMA_CORE_PCI, "PCI" }, |
55 | { BCMA_CORE_ETHERNET, "Fast Ethernet" }, |
56 | { BCMA_CORE_V90, "V90" }, |
57 | { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" }, |
58 | { BCMA_CORE_ADSL, "ADSL" }, |
59 | { BCMA_CORE_ILINE100, "ILine 100" }, |
60 | { BCMA_CORE_IPSEC, "IPSEC" }, |
61 | { BCMA_CORE_UTOPIA, "UTOPIA" }, |
62 | { BCMA_CORE_PCMCIA, "PCMCIA" }, |
63 | { BCMA_CORE_INTERNAL_MEM, "Internal Memory" }, |
64 | { BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" }, |
65 | { BCMA_CORE_OFDM, "OFDM" }, |
66 | { BCMA_CORE_EXTIF, "EXTIF" }, |
67 | { BCMA_CORE_80211, "IEEE 802.11" }, |
68 | { BCMA_CORE_PHY_A, "PHY A" }, |
69 | { BCMA_CORE_PHY_B, "PHY B" }, |
70 | { BCMA_CORE_PHY_G, "PHY G" }, |
71 | { BCMA_CORE_USB11_HOST, "USB 1.1 Host" }, |
72 | { BCMA_CORE_USB11_DEV, "USB 1.1 Device" }, |
73 | { BCMA_CORE_USB20_HOST, "USB 2.0 Host" }, |
74 | { BCMA_CORE_USB20_DEV, "USB 2.0 Device" }, |
75 | { BCMA_CORE_SDIO_HOST, "SDIO Host" }, |
76 | { BCMA_CORE_ROBOSWITCH, "Roboswitch" }, |
77 | { BCMA_CORE_PARA_ATA, "PATA" }, |
78 | { BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" }, |
79 | { BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" }, |
80 | { BCMA_CORE_PCIE, "PCIe" }, |
81 | { BCMA_CORE_PHY_N, "PHY N" }, |
82 | { BCMA_CORE_SRAM_CTL, "SRAM Controller" }, |
83 | { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" }, |
84 | { BCMA_CORE_PHY_LP, "PHY LP" }, |
85 | { BCMA_CORE_PMU, "PMU" }, |
86 | { BCMA_CORE_PHY_SSN, "PHY SSN" }, |
87 | { BCMA_CORE_SDIO_DEV, "SDIO Device" }, |
88 | { BCMA_CORE_PHY_HT, "PHY HT" }, |
89 | { BCMA_CORE_MAC_GBIT, "GBit MAC" }, |
90 | { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" }, |
91 | { BCMA_CORE_PCIE_RC, "PCIe Root Complex" }, |
92 | { BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" }, |
93 | { BCMA_CORE_SHARED_COMMON, "Common Shared" }, |
94 | { BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" }, |
95 | { BCMA_CORE_SPI_HOST, "SPI Host" }, |
96 | { BCMA_CORE_I2S, "I2S" }, |
97 | { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" }, |
98 | { BCMA_CORE_SHIM, "SHIM" }, |
99 | { BCMA_CORE_PCIE2, "PCIe Gen2" }, |
100 | { BCMA_CORE_ARM_CR4, "ARM CR4" }, |
101 | { BCMA_CORE_GCI, "GCI" }, |
102 | { BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" }, |
103 | { BCMA_CORE_ARM_CA7, "ARM CA7" }, |
104 | { BCMA_CORE_DEFAULT, "Default" }, |
105 | }; |
106 | |
107 | static const struct bcma_device_id_name bcma_mips_device_names[] = { |
108 | { BCMA_CORE_MIPS, "MIPS" }, |
109 | { BCMA_CORE_MIPS_3302, "MIPS 3302" }, |
110 | { BCMA_CORE_MIPS_74K, "MIPS 74K" }, |
111 | }; |
112 | |
113 | static const char *bcma_device_name(const struct bcma_device_id *id) |
114 | { |
115 | const struct bcma_device_id_name *names; |
116 | int size, i; |
117 | |
118 | /* search manufacturer specific names */ |
119 | switch (id->manuf) { |
120 | case BCMA_MANUF_ARM: |
121 | names = bcma_arm_device_names; |
122 | size = ARRAY_SIZE(bcma_arm_device_names); |
123 | break; |
124 | case BCMA_MANUF_BCM: |
125 | names = bcma_bcm_device_names; |
126 | size = ARRAY_SIZE(bcma_bcm_device_names); |
127 | break; |
128 | case BCMA_MANUF_MIPS: |
129 | names = bcma_mips_device_names; |
130 | size = ARRAY_SIZE(bcma_mips_device_names); |
131 | break; |
132 | default: |
133 | return "UNKNOWN" ; |
134 | } |
135 | |
136 | for (i = 0; i < size; i++) { |
137 | if (names[i].id == id->id) |
138 | return names[i].name; |
139 | } |
140 | |
141 | return "UNKNOWN" ; |
142 | } |
143 | |
144 | static u32 bcma_scan_read32(struct bcma_bus *bus, u16 offset) |
145 | { |
146 | return readl(addr: bus->mmio + offset); |
147 | } |
148 | |
149 | static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr) |
150 | { |
151 | if (bus->hosttype == BCMA_HOSTTYPE_PCI) |
152 | pci_write_config_dword(dev: bus->host_pci, BCMA_PCI_BAR0_WIN, |
153 | val: addr); |
154 | } |
155 | |
156 | static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr) |
157 | { |
158 | u32 ent = readl(addr: *eromptr); |
159 | (*eromptr)++; |
160 | return ent; |
161 | } |
162 | |
163 | static void bcma_erom_push_ent(u32 __iomem **eromptr) |
164 | { |
165 | (*eromptr)--; |
166 | } |
167 | |
168 | static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 __iomem **eromptr) |
169 | { |
170 | u32 ent = bcma_erom_get_ent(bus, eromptr); |
171 | if (!(ent & SCAN_ER_VALID)) |
172 | return -ENOENT; |
173 | if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI) |
174 | return -ENOENT; |
175 | return ent; |
176 | } |
177 | |
178 | static bool bcma_erom_is_end(struct bcma_bus *bus, u32 __iomem **eromptr) |
179 | { |
180 | u32 ent = bcma_erom_get_ent(bus, eromptr); |
181 | bcma_erom_push_ent(eromptr); |
182 | return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID)); |
183 | } |
184 | |
185 | static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 __iomem **eromptr) |
186 | { |
187 | u32 ent = bcma_erom_get_ent(bus, eromptr); |
188 | bcma_erom_push_ent(eromptr); |
189 | return (((ent & SCAN_ER_VALID)) && |
190 | ((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) && |
191 | ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE)); |
192 | } |
193 | |
194 | static void bcma_erom_skip_component(struct bcma_bus *bus, u32 __iomem **eromptr) |
195 | { |
196 | u32 ent; |
197 | while (1) { |
198 | ent = bcma_erom_get_ent(bus, eromptr); |
199 | if ((ent & SCAN_ER_VALID) && |
200 | ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI)) |
201 | break; |
202 | if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID)) |
203 | break; |
204 | } |
205 | bcma_erom_push_ent(eromptr); |
206 | } |
207 | |
208 | static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr) |
209 | { |
210 | u32 ent = bcma_erom_get_ent(bus, eromptr); |
211 | if (!(ent & SCAN_ER_VALID)) |
212 | return -ENOENT; |
213 | if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP) |
214 | return -ENOENT; |
215 | return ent; |
216 | } |
217 | |
218 | static u32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr, |
219 | u32 type, u8 port) |
220 | { |
221 | u32 addrl; |
222 | u32 size; |
223 | |
224 | u32 ent = bcma_erom_get_ent(bus, eromptr); |
225 | if ((!(ent & SCAN_ER_VALID)) || |
226 | ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) || |
227 | ((ent & SCAN_ADDR_TYPE) != type) || |
228 | (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) { |
229 | bcma_erom_push_ent(eromptr); |
230 | return (u32)-EINVAL; |
231 | } |
232 | |
233 | addrl = ent & SCAN_ADDR_ADDR; |
234 | if (ent & SCAN_ADDR_AG32) |
235 | bcma_erom_get_ent(bus, eromptr); |
236 | |
237 | if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) { |
238 | size = bcma_erom_get_ent(bus, eromptr); |
239 | if (size & SCAN_SIZE_SG32) |
240 | bcma_erom_get_ent(bus, eromptr); |
241 | } |
242 | |
243 | return addrl; |
244 | } |
245 | |
246 | static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus, |
247 | u16 index) |
248 | { |
249 | struct bcma_device *core; |
250 | |
251 | list_for_each_entry(core, &bus->cores, list) { |
252 | if (core->core_index == index) |
253 | return core; |
254 | } |
255 | return NULL; |
256 | } |
257 | |
258 | static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid) |
259 | { |
260 | struct bcma_device *core; |
261 | |
262 | list_for_each_entry_reverse(core, &bus->cores, list) { |
263 | if (core->id.id == coreid) |
264 | return core; |
265 | } |
266 | return NULL; |
267 | } |
268 | |
269 | #define IS_ERR_VALUE_U32(x) ((x) >= (u32)-MAX_ERRNO) |
270 | |
271 | static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, |
272 | struct bcma_device_id *match, int core_num, |
273 | struct bcma_device *core) |
274 | { |
275 | u32 tmp; |
276 | u8 i, j, k; |
277 | s32 cia, cib; |
278 | u8 ports[2], wrappers[2]; |
279 | |
280 | /* get CIs */ |
281 | cia = bcma_erom_get_ci(bus, eromptr); |
282 | if (cia < 0) { |
283 | bcma_erom_push_ent(eromptr); |
284 | if (bcma_erom_is_end(bus, eromptr)) |
285 | return -ESPIPE; |
286 | return -EILSEQ; |
287 | } |
288 | cib = bcma_erom_get_ci(bus, eromptr); |
289 | if (cib < 0) |
290 | return -EILSEQ; |
291 | |
292 | /* parse CIs */ |
293 | core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; |
294 | core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; |
295 | core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; |
296 | ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; |
297 | ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; |
298 | wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; |
299 | wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; |
300 | core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; |
301 | |
302 | if (((core->id.manuf == BCMA_MANUF_ARM) && |
303 | (core->id.id == 0xFFF)) || |
304 | (ports[1] == 0)) { |
305 | bcma_erom_skip_component(bus, eromptr); |
306 | return -ENXIO; |
307 | } |
308 | |
309 | /* check if component is a core at all */ |
310 | if (wrappers[0] + wrappers[1] == 0) { |
311 | /* Some specific cores don't need wrappers */ |
312 | switch (core->id.id) { |
313 | case BCMA_CORE_4706_MAC_GBIT_COMMON: |
314 | case BCMA_CORE_NS_CHIPCOMMON_B: |
315 | case BCMA_CORE_PMU: |
316 | case BCMA_CORE_GCI: |
317 | /* Not used yet: case BCMA_CORE_OOB_ROUTER: */ |
318 | break; |
319 | default: |
320 | bcma_erom_skip_component(bus, eromptr); |
321 | return -ENXIO; |
322 | } |
323 | } |
324 | |
325 | if (bcma_erom_is_bridge(bus, eromptr)) { |
326 | bcma_erom_skip_component(bus, eromptr); |
327 | return -ENXIO; |
328 | } |
329 | |
330 | if (bcma_find_core_by_index(bus, index: core_num)) { |
331 | bcma_erom_skip_component(bus, eromptr); |
332 | return -ENODEV; |
333 | } |
334 | |
335 | if (match && ((match->manuf != BCMA_ANY_MANUF && |
336 | match->manuf != core->id.manuf) || |
337 | (match->id != BCMA_ANY_ID && match->id != core->id.id) || |
338 | (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) || |
339 | (match->class != BCMA_ANY_CLASS && match->class != core->id.class) |
340 | )) { |
341 | bcma_erom_skip_component(bus, eromptr); |
342 | return -ENODEV; |
343 | } |
344 | |
345 | /* get & parse master ports */ |
346 | for (i = 0; i < ports[0]; i++) { |
347 | s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr); |
348 | if (mst_port_d < 0) |
349 | return -EILSEQ; |
350 | } |
351 | |
352 | /* First Slave Address Descriptor should be port 0: |
353 | * the main register space for the core |
354 | */ |
355 | tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, port: 0); |
356 | if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) { |
357 | /* Try again to see if it is a bridge */ |
358 | tmp = bcma_erom_get_addr_desc(bus, eromptr, |
359 | SCAN_ADDR_TYPE_BRIDGE, port: 0); |
360 | if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) { |
361 | return -EILSEQ; |
362 | } else { |
363 | bcma_info(bus, "Bridge found\n" ); |
364 | return -ENXIO; |
365 | } |
366 | } |
367 | core->addr = tmp; |
368 | |
369 | /* get & parse slave ports */ |
370 | k = 0; |
371 | for (i = 0; i < ports[1]; i++) { |
372 | for (j = 0; ; j++) { |
373 | tmp = bcma_erom_get_addr_desc(bus, eromptr, |
374 | SCAN_ADDR_TYPE_SLAVE, port: i); |
375 | if (IS_ERR_VALUE_U32(tmp)) { |
376 | /* no more entries for port _i_ */ |
377 | /* pr_debug("erom: slave port %d " |
378 | * "has %d descriptors\n", i, j); */ |
379 | break; |
380 | } else if (k < ARRAY_SIZE(core->addr_s)) { |
381 | core->addr_s[k] = tmp; |
382 | k++; |
383 | } |
384 | } |
385 | } |
386 | |
387 | /* get & parse master wrappers */ |
388 | for (i = 0; i < wrappers[0]; i++) { |
389 | for (j = 0; ; j++) { |
390 | tmp = bcma_erom_get_addr_desc(bus, eromptr, |
391 | SCAN_ADDR_TYPE_MWRAP, port: i); |
392 | if (IS_ERR_VALUE_U32(tmp)) { |
393 | /* no more entries for port _i_ */ |
394 | /* pr_debug("erom: master wrapper %d " |
395 | * "has %d descriptors\n", i, j); */ |
396 | break; |
397 | } else { |
398 | if (i == 0 && j == 0) |
399 | core->wrap = tmp; |
400 | } |
401 | } |
402 | } |
403 | |
404 | /* get & parse slave wrappers */ |
405 | for (i = 0; i < wrappers[1]; i++) { |
406 | u8 hack = (ports[1] == 1) ? 0 : 1; |
407 | for (j = 0; ; j++) { |
408 | tmp = bcma_erom_get_addr_desc(bus, eromptr, |
409 | SCAN_ADDR_TYPE_SWRAP, port: i + hack); |
410 | if (IS_ERR_VALUE_U32(tmp)) { |
411 | /* no more entries for port _i_ */ |
412 | /* pr_debug("erom: master wrapper %d " |
413 | * has %d descriptors\n", i, j); */ |
414 | break; |
415 | } else { |
416 | if (wrappers[0] == 0 && !i && !j) |
417 | core->wrap = tmp; |
418 | } |
419 | } |
420 | } |
421 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
422 | core->io_addr = ioremap(offset: core->addr, BCMA_CORE_SIZE); |
423 | if (!core->io_addr) |
424 | return -ENOMEM; |
425 | if (core->wrap) { |
426 | core->io_wrap = ioremap(offset: core->wrap, |
427 | BCMA_CORE_SIZE); |
428 | if (!core->io_wrap) { |
429 | iounmap(addr: core->io_addr); |
430 | return -ENOMEM; |
431 | } |
432 | } |
433 | } |
434 | return 0; |
435 | } |
436 | |
437 | void bcma_detect_chip(struct bcma_bus *bus) |
438 | { |
439 | s32 tmp; |
440 | struct bcma_chipinfo *chipinfo = &(bus->chipinfo); |
441 | char chip_id[8]; |
442 | |
443 | bcma_scan_switch_core(bus, BCMA_ADDR_BASE); |
444 | |
445 | tmp = bcma_scan_read32(bus, BCMA_CC_ID); |
446 | chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; |
447 | chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; |
448 | chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; |
449 | |
450 | snprintf(buf: chip_id, ARRAY_SIZE(chip_id), |
451 | fmt: (chipinfo->id > 0x9999) ? "%d" : "0x%04X" , chipinfo->id); |
452 | bcma_info(bus, "Found chip with id %s, rev 0x%02X and package 0x%02X\n" , |
453 | chip_id, chipinfo->rev, chipinfo->pkg); |
454 | } |
455 | |
456 | int bcma_bus_scan(struct bcma_bus *bus) |
457 | { |
458 | u32 erombase; |
459 | u32 __iomem *eromptr, *eromend; |
460 | |
461 | int err, core_num = 0; |
462 | |
463 | /* Skip if bus was already scanned (e.g. during early register) */ |
464 | if (bus->nr_cores) |
465 | return 0; |
466 | |
467 | erombase = bcma_scan_read32(bus, BCMA_CC_EROM); |
468 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
469 | eromptr = ioremap(offset: erombase, BCMA_CORE_SIZE); |
470 | if (!eromptr) |
471 | return -ENOMEM; |
472 | } else { |
473 | eromptr = bus->mmio; |
474 | } |
475 | |
476 | eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); |
477 | |
478 | bcma_scan_switch_core(bus, addr: erombase); |
479 | |
480 | while (eromptr < eromend) { |
481 | struct bcma_device *other_core; |
482 | struct bcma_device *core = kzalloc(size: sizeof(*core), GFP_KERNEL); |
483 | if (!core) { |
484 | err = -ENOMEM; |
485 | goto out; |
486 | } |
487 | INIT_LIST_HEAD(list: &core->list); |
488 | core->bus = bus; |
489 | |
490 | err = bcma_get_next_core(bus, eromptr: &eromptr, NULL, core_num, core); |
491 | if (err < 0) { |
492 | kfree(objp: core); |
493 | if (err == -ENODEV) { |
494 | core_num++; |
495 | continue; |
496 | } else if (err == -ENXIO) { |
497 | continue; |
498 | } else if (err == -ESPIPE) { |
499 | break; |
500 | } |
501 | goto out; |
502 | } |
503 | |
504 | core->core_index = core_num++; |
505 | bus->nr_cores++; |
506 | other_core = bcma_find_core_reverse(bus, coreid: core->id.id); |
507 | core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1; |
508 | bcma_prepare_core(bus, core); |
509 | |
510 | bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n" , |
511 | core->core_index, bcma_device_name(&core->id), |
512 | core->id.manuf, core->id.id, core->id.rev, |
513 | core->id.class); |
514 | |
515 | list_add_tail(new: &core->list, head: &bus->cores); |
516 | } |
517 | |
518 | err = 0; |
519 | out: |
520 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) |
521 | iounmap(addr: eromptr); |
522 | |
523 | return err; |
524 | } |
525 | |