in scan.c [271:446]
int ssb_bus_scan(struct ssb_bus *bus,
unsigned long baseaddr)
{
int err = -ENOMEM;
void __iomem *mmio;
u32 idhi, cc, rev, tmp;
int dev_i, i;
struct ssb_device *dev;
int nr_80211_cores = 0;
mmio = ssb_ioremap(bus, baseaddr);
if (!mmio)
goto out;
bus->mmio = mmio;
err = scan_switchcore(bus, 0); /* Switch to first core */
if (err)
goto err_unmap;
idhi = scan_read32(bus, 0, SSB_IDHIGH);
cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
rev = (idhi & SSB_IDHIGH_RCLO);
rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
bus->nr_devices = 0;
if (cc == SSB_DEV_CHIPCOMMON) {
tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
SSB_CHIPCO_REVSHIFT;
bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
SSB_CHIPCO_PACKSHIFT;
if (rev >= 4) {
bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
SSB_CHIPCO_NRCORESSHIFT;
}
tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
bus->chipco.capabilities = tmp;
} else {
if (bus->bustype == SSB_BUSTYPE_PCI) {
bus->chip_id = pcidev_to_chipid(bus->host_pci);
bus->chip_rev = bus->host_pci->revision;
bus->chip_package = 0;
} else {
bus->chip_id = 0x4710;
bus->chip_rev = 0;
bus->chip_package = 0;
}
}
pr_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
bus->chip_id, bus->chip_rev, bus->chip_package);
if (!bus->nr_devices)
bus->nr_devices = chipid_to_nrcores(bus->chip_id);
if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
pr_err("More than %d ssb cores found (%d)\n",
SSB_MAX_NR_CORES, bus->nr_devices);
err = -EINVAL;
goto err_unmap;
}
if (bus->bustype == SSB_BUSTYPE_SSB) {
/* Now that we know the number of cores,
* remap the whole IO space for all cores.
*/
err = -ENOMEM;
iounmap(mmio);
mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
if (!mmio)
goto out;
bus->mmio = mmio;
}
/* Fetch basic information about each core/device */
for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
err = scan_switchcore(bus, i);
if (err)
goto err_unmap;
dev = &(bus->devices[dev_i]);
idhi = scan_read32(bus, i, SSB_IDHIGH);
dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
dev->core_index = i;
dev->bus = bus;
dev->ops = bus->ops;
pr_debug("Core %d found: %s (cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
i, ssb_core_name(dev->id.coreid),
dev->id.coreid, dev->id.revision, dev->id.vendor);
switch (dev->id.coreid) {
case SSB_DEV_80211:
nr_80211_cores++;
if (nr_80211_cores > 1) {
if (!we_support_multiple_80211_cores(bus)) {
pr_debug("Ignoring additional 802.11 core\n");
continue;
}
}
break;
case SSB_DEV_EXTIF:
#ifdef CONFIG_SSB_DRIVER_EXTIF
if (bus->extif.dev) {
pr_warn("WARNING: Multiple EXTIFs found\n");
break;
}
bus->extif.dev = dev;
#endif /* CONFIG_SSB_DRIVER_EXTIF */
break;
case SSB_DEV_CHIPCOMMON:
if (bus->chipco.dev) {
pr_warn("WARNING: Multiple ChipCommon found\n");
break;
}
bus->chipco.dev = dev;
break;
case SSB_DEV_MIPS:
case SSB_DEV_MIPS_3302:
#ifdef CONFIG_SSB_DRIVER_MIPS
if (bus->mipscore.dev) {
pr_warn("WARNING: Multiple MIPS cores found\n");
break;
}
bus->mipscore.dev = dev;
#endif /* CONFIG_SSB_DRIVER_MIPS */
break;
case SSB_DEV_PCI:
case SSB_DEV_PCIE:
#ifdef CONFIG_SSB_DRIVER_PCICORE
if (bus->bustype == SSB_BUSTYPE_PCI) {
/* Ignore PCI cores on PCI-E cards.
* Ignore PCI-E cores on PCI cards.
*/
if (dev->id.coreid == SSB_DEV_PCI) {
if (pci_is_pcie(bus->host_pci))
continue;
} else {
if (!pci_is_pcie(bus->host_pci))
continue;
}
}
if (bus->pcicore.dev) {
pr_warn("WARNING: Multiple PCI(E) cores found\n");
break;
}
bus->pcicore.dev = dev;
#endif /* CONFIG_SSB_DRIVER_PCICORE */
break;
case SSB_DEV_ETHERNET:
if (bus->bustype == SSB_BUSTYPE_PCI) {
if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
(bus->host_pci->device & 0xFF00) == 0x4300) {
/* This is a dangling ethernet core on a
* wireless device. Ignore it.
*/
continue;
}
}
break;
default:
break;
}
dev_i++;
}
bus->nr_devices = dev_i;
err = 0;
out:
return err;
err_unmap:
ssb_iounmap(bus);
goto out;
}