int ssb_bus_scan()

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;
}