diff options
Diffstat (limited to 'drivers/bcma/scan.c')
-rw-r--r-- | drivers/bcma/scan.c | 348 |
1 files changed, 237 insertions, 111 deletions
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 40d7dcce8933..0ea390f9aa9e 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c | |||
@@ -200,18 +200,162 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr, | |||
200 | return addrl; | 200 | return addrl; |
201 | } | 201 | } |
202 | 202 | ||
203 | int bcma_bus_scan(struct bcma_bus *bus) | 203 | static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus, |
204 | u16 index) | ||
204 | { | 205 | { |
205 | u32 erombase; | 206 | struct bcma_device *core; |
206 | u32 __iomem *eromptr, *eromend; | ||
207 | 207 | ||
208 | list_for_each_entry(core, &bus->cores, list) { | ||
209 | if (core->core_index == index) | ||
210 | return core; | ||
211 | } | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, | ||
216 | struct bcma_device_id *match, int core_num, | ||
217 | struct bcma_device *core) | ||
218 | { | ||
219 | s32 tmp; | ||
220 | u8 i, j; | ||
208 | s32 cia, cib; | 221 | s32 cia, cib; |
209 | u8 ports[2], wrappers[2]; | 222 | u8 ports[2], wrappers[2]; |
210 | 223 | ||
224 | /* get CIs */ | ||
225 | cia = bcma_erom_get_ci(bus, eromptr); | ||
226 | if (cia < 0) { | ||
227 | bcma_erom_push_ent(eromptr); | ||
228 | if (bcma_erom_is_end(bus, eromptr)) | ||
229 | return -ESPIPE; | ||
230 | return -EILSEQ; | ||
231 | } | ||
232 | cib = bcma_erom_get_ci(bus, eromptr); | ||
233 | if (cib < 0) | ||
234 | return -EILSEQ; | ||
235 | |||
236 | /* parse CIs */ | ||
237 | core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; | ||
238 | core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; | ||
239 | core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; | ||
240 | ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; | ||
241 | ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; | ||
242 | wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; | ||
243 | wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; | ||
244 | core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; | ||
245 | |||
246 | if (((core->id.manuf == BCMA_MANUF_ARM) && | ||
247 | (core->id.id == 0xFFF)) || | ||
248 | (ports[1] == 0)) { | ||
249 | bcma_erom_skip_component(bus, eromptr); | ||
250 | return -ENXIO; | ||
251 | } | ||
252 | |||
253 | /* check if component is a core at all */ | ||
254 | if (wrappers[0] + wrappers[1] == 0) { | ||
255 | /* we could save addrl of the router | ||
256 | if (cid == BCMA_CORE_OOB_ROUTER) | ||
257 | */ | ||
258 | bcma_erom_skip_component(bus, eromptr); | ||
259 | return -ENXIO; | ||
260 | } | ||
261 | |||
262 | if (bcma_erom_is_bridge(bus, eromptr)) { | ||
263 | bcma_erom_skip_component(bus, eromptr); | ||
264 | return -ENXIO; | ||
265 | } | ||
266 | |||
267 | if (bcma_find_core_by_index(bus, core_num)) { | ||
268 | bcma_erom_skip_component(bus, eromptr); | ||
269 | return -ENODEV; | ||
270 | } | ||
271 | |||
272 | if (match && ((match->manuf != BCMA_ANY_MANUF && | ||
273 | match->manuf != core->id.manuf) || | ||
274 | (match->id != BCMA_ANY_ID && match->id != core->id.id) || | ||
275 | (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) || | ||
276 | (match->class != BCMA_ANY_CLASS && match->class != core->id.class) | ||
277 | )) { | ||
278 | bcma_erom_skip_component(bus, eromptr); | ||
279 | return -ENODEV; | ||
280 | } | ||
281 | |||
282 | /* get & parse master ports */ | ||
283 | for (i = 0; i < ports[0]; i++) { | ||
284 | u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr); | ||
285 | if (mst_port_d < 0) | ||
286 | return -EILSEQ; | ||
287 | } | ||
288 | |||
289 | /* get & parse slave ports */ | ||
290 | for (i = 0; i < ports[1]; i++) { | ||
291 | for (j = 0; ; j++) { | ||
292 | tmp = bcma_erom_get_addr_desc(bus, eromptr, | ||
293 | SCAN_ADDR_TYPE_SLAVE, i); | ||
294 | if (tmp < 0) { | ||
295 | /* no more entries for port _i_ */ | ||
296 | /* pr_debug("erom: slave port %d " | ||
297 | * "has %d descriptors\n", i, j); */ | ||
298 | break; | ||
299 | } else { | ||
300 | if (i == 0 && j == 0) | ||
301 | core->addr = tmp; | ||
302 | } | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* get & parse master wrappers */ | ||
307 | for (i = 0; i < wrappers[0]; i++) { | ||
308 | for (j = 0; ; j++) { | ||
309 | tmp = bcma_erom_get_addr_desc(bus, eromptr, | ||
310 | SCAN_ADDR_TYPE_MWRAP, i); | ||
311 | if (tmp < 0) { | ||
312 | /* no more entries for port _i_ */ | ||
313 | /* pr_debug("erom: master wrapper %d " | ||
314 | * "has %d descriptors\n", i, j); */ | ||
315 | break; | ||
316 | } else { | ||
317 | if (i == 0 && j == 0) | ||
318 | core->wrap = tmp; | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | |||
323 | /* get & parse slave wrappers */ | ||
324 | for (i = 0; i < wrappers[1]; i++) { | ||
325 | u8 hack = (ports[1] == 1) ? 0 : 1; | ||
326 | for (j = 0; ; j++) { | ||
327 | tmp = bcma_erom_get_addr_desc(bus, eromptr, | ||
328 | SCAN_ADDR_TYPE_SWRAP, i + hack); | ||
329 | if (tmp < 0) { | ||
330 | /* no more entries for port _i_ */ | ||
331 | /* pr_debug("erom: master wrapper %d " | ||
332 | * has %d descriptors\n", i, j); */ | ||
333 | break; | ||
334 | } else { | ||
335 | if (wrappers[0] == 0 && !i && !j) | ||
336 | core->wrap = tmp; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { | ||
341 | core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE); | ||
342 | if (!core->io_addr) | ||
343 | return -ENOMEM; | ||
344 | core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE); | ||
345 | if (!core->io_wrap) { | ||
346 | iounmap(core->io_addr); | ||
347 | return -ENOMEM; | ||
348 | } | ||
349 | } | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | void bcma_init_bus(struct bcma_bus *bus) | ||
354 | { | ||
211 | s32 tmp; | 355 | s32 tmp; |
212 | u8 i, j; | ||
213 | 356 | ||
214 | int err; | 357 | if (bus->init_done) |
358 | return; | ||
215 | 359 | ||
216 | INIT_LIST_HEAD(&bus->cores); | 360 | INIT_LIST_HEAD(&bus->cores); |
217 | bus->nr_cores = 0; | 361 | bus->nr_cores = 0; |
@@ -222,9 +366,27 @@ int bcma_bus_scan(struct bcma_bus *bus) | |||
222 | bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; | 366 | bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; |
223 | bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; | 367 | bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; |
224 | bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; | 368 | bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; |
369 | bus->init_done = true; | ||
370 | } | ||
371 | |||
372 | int bcma_bus_scan(struct bcma_bus *bus) | ||
373 | { | ||
374 | u32 erombase; | ||
375 | u32 __iomem *eromptr, *eromend; | ||
376 | |||
377 | int err, core_num = 0; | ||
378 | |||
379 | bcma_init_bus(bus); | ||
225 | 380 | ||
226 | erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); | 381 | erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); |
227 | eromptr = bus->mmio; | 382 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
383 | eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); | ||
384 | if (!eromptr) | ||
385 | return -ENOMEM; | ||
386 | } else { | ||
387 | eromptr = bus->mmio; | ||
388 | } | ||
389 | |||
228 | eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); | 390 | eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); |
229 | 391 | ||
230 | bcma_scan_switch_core(bus, erombase); | 392 | bcma_scan_switch_core(bus, erombase); |
@@ -236,125 +398,89 @@ int bcma_bus_scan(struct bcma_bus *bus) | |||
236 | INIT_LIST_HEAD(&core->list); | 398 | INIT_LIST_HEAD(&core->list); |
237 | core->bus = bus; | 399 | core->bus = bus; |
238 | 400 | ||
239 | /* get CIs */ | 401 | err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core); |
240 | cia = bcma_erom_get_ci(bus, &eromptr); | 402 | if (err == -ENODEV) { |
241 | if (cia < 0) { | 403 | core_num++; |
242 | bcma_erom_push_ent(&eromptr); | ||
243 | if (bcma_erom_is_end(bus, &eromptr)) | ||
244 | break; | ||
245 | err= -EILSEQ; | ||
246 | goto out; | ||
247 | } | ||
248 | cib = bcma_erom_get_ci(bus, &eromptr); | ||
249 | if (cib < 0) { | ||
250 | err= -EILSEQ; | ||
251 | goto out; | ||
252 | } | ||
253 | |||
254 | /* parse CIs */ | ||
255 | core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; | ||
256 | core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; | ||
257 | core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; | ||
258 | ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; | ||
259 | ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; | ||
260 | wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; | ||
261 | wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; | ||
262 | core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; | ||
263 | |||
264 | if (((core->id.manuf == BCMA_MANUF_ARM) && | ||
265 | (core->id.id == 0xFFF)) || | ||
266 | (ports[1] == 0)) { | ||
267 | bcma_erom_skip_component(bus, &eromptr); | ||
268 | continue; | 404 | continue; |
269 | } | 405 | } else if (err == -ENXIO) |
270 | |||
271 | /* check if component is a core at all */ | ||
272 | if (wrappers[0] + wrappers[1] == 0) { | ||
273 | /* we could save addrl of the router | ||
274 | if (cid == BCMA_CORE_OOB_ROUTER) | ||
275 | */ | ||
276 | bcma_erom_skip_component(bus, &eromptr); | ||
277 | continue; | 406 | continue; |
278 | } | 407 | else if (err == -ESPIPE) |
408 | break; | ||
409 | else if (err < 0) | ||
410 | return err; | ||
279 | 411 | ||
280 | if (bcma_erom_is_bridge(bus, &eromptr)) { | 412 | core->core_index = core_num++; |
281 | bcma_erom_skip_component(bus, &eromptr); | 413 | bus->nr_cores++; |
282 | continue; | ||
283 | } | ||
284 | 414 | ||
285 | /* get & parse master ports */ | 415 | pr_info("Core %d found: %s " |
286 | for (i = 0; i < ports[0]; i++) { | 416 | "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", |
287 | u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr); | 417 | core->core_index, bcma_device_name(&core->id), |
288 | if (mst_port_d < 0) { | 418 | core->id.manuf, core->id.id, core->id.rev, |
289 | err= -EILSEQ; | 419 | core->id.class); |
290 | goto out; | ||
291 | } | ||
292 | } | ||
293 | 420 | ||
294 | /* get & parse slave ports */ | 421 | list_add(&core->list, &bus->cores); |
295 | for (i = 0; i < ports[1]; i++) { | 422 | } |
296 | for (j = 0; ; j++) { | ||
297 | tmp = bcma_erom_get_addr_desc(bus, &eromptr, | ||
298 | SCAN_ADDR_TYPE_SLAVE, i); | ||
299 | if (tmp < 0) { | ||
300 | /* no more entries for port _i_ */ | ||
301 | /* pr_debug("erom: slave port %d " | ||
302 | * "has %d descriptors\n", i, j); */ | ||
303 | break; | ||
304 | } else { | ||
305 | if (i == 0 && j == 0) | ||
306 | core->addr = tmp; | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | 423 | ||
311 | /* get & parse master wrappers */ | 424 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) |
312 | for (i = 0; i < wrappers[0]; i++) { | 425 | iounmap(eromptr); |
313 | for (j = 0; ; j++) { | ||
314 | tmp = bcma_erom_get_addr_desc(bus, &eromptr, | ||
315 | SCAN_ADDR_TYPE_MWRAP, i); | ||
316 | if (tmp < 0) { | ||
317 | /* no more entries for port _i_ */ | ||
318 | /* pr_debug("erom: master wrapper %d " | ||
319 | * "has %d descriptors\n", i, j); */ | ||
320 | break; | ||
321 | } else { | ||
322 | if (i == 0 && j == 0) | ||
323 | core->wrap = tmp; | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | 426 | ||
328 | /* get & parse slave wrappers */ | 427 | return 0; |
329 | for (i = 0; i < wrappers[1]; i++) { | 428 | } |
330 | u8 hack = (ports[1] == 1) ? 0 : 1; | 429 | |
331 | for (j = 0; ; j++) { | 430 | int __init bcma_bus_scan_early(struct bcma_bus *bus, |
332 | tmp = bcma_erom_get_addr_desc(bus, &eromptr, | 431 | struct bcma_device_id *match, |
333 | SCAN_ADDR_TYPE_SWRAP, i + hack); | 432 | struct bcma_device *core) |
334 | if (tmp < 0) { | 433 | { |
335 | /* no more entries for port _i_ */ | 434 | u32 erombase; |
336 | /* pr_debug("erom: master wrapper %d " | 435 | u32 __iomem *eromptr, *eromend; |
337 | * has %d descriptors\n", i, j); */ | 436 | |
338 | break; | 437 | int err = -ENODEV; |
339 | } else { | 438 | int core_num = 0; |
340 | if (wrappers[0] == 0 && !i && !j) | 439 | |
341 | core->wrap = tmp; | 440 | erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); |
342 | } | 441 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
343 | } | 442 | eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); |
344 | } | 443 | if (!eromptr) |
444 | return -ENOMEM; | ||
445 | } else { | ||
446 | eromptr = bus->mmio; | ||
447 | } | ||
448 | |||
449 | eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); | ||
450 | |||
451 | bcma_scan_switch_core(bus, erombase); | ||
452 | |||
453 | while (eromptr < eromend) { | ||
454 | memset(core, 0, sizeof(*core)); | ||
455 | INIT_LIST_HEAD(&core->list); | ||
456 | core->bus = bus; | ||
345 | 457 | ||
458 | err = bcma_get_next_core(bus, &eromptr, match, core_num, core); | ||
459 | if (err == -ENODEV) { | ||
460 | core_num++; | ||
461 | continue; | ||
462 | } else if (err == -ENXIO) | ||
463 | continue; | ||
464 | else if (err == -ESPIPE) | ||
465 | break; | ||
466 | else if (err < 0) | ||
467 | return err; | ||
468 | |||
469 | core->core_index = core_num++; | ||
470 | bus->nr_cores++; | ||
346 | pr_info("Core %d found: %s " | 471 | pr_info("Core %d found: %s " |
347 | "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", | 472 | "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", |
348 | bus->nr_cores, bcma_device_name(&core->id), | 473 | core->core_index, bcma_device_name(&core->id), |
349 | core->id.manuf, core->id.id, core->id.rev, | 474 | core->id.manuf, core->id.id, core->id.rev, |
350 | core->id.class); | 475 | core->id.class); |
351 | 476 | ||
352 | core->core_index = bus->nr_cores++; | ||
353 | list_add(&core->list, &bus->cores); | 477 | list_add(&core->list, &bus->cores); |
354 | continue; | 478 | err = 0; |
355 | out: | 479 | break; |
356 | return err; | ||
357 | } | 480 | } |
358 | 481 | ||
359 | return 0; | 482 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) |
483 | iounmap(eromptr); | ||
484 | |||
485 | return err; | ||
360 | } | 486 | } |