static int bcma_get_next_core()

in scan.c [271:435]


static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
			      struct bcma_device_id *match, int core_num,
			      struct bcma_device *core)
{
	u32 tmp;
	u8 i, j, k;
	s32 cia, cib;
	u8 ports[2], wrappers[2];

	/* get CIs */
	cia = bcma_erom_get_ci(bus, eromptr);
	if (cia < 0) {
		bcma_erom_push_ent(eromptr);
		if (bcma_erom_is_end(bus, eromptr))
			return -ESPIPE;
		return -EILSEQ;
	}
	cib = bcma_erom_get_ci(bus, eromptr);
	if (cib < 0)
		return -EILSEQ;

	/* parse CIs */
	core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
	core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
	core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
	ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
	ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
	wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
	wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
	core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;

	if (((core->id.manuf == BCMA_MANUF_ARM) &&
	     (core->id.id == 0xFFF)) ||
	    (ports[1] == 0)) {
		bcma_erom_skip_component(bus, eromptr);
		return -ENXIO;
	}

	/* check if component is a core at all */
	if (wrappers[0] + wrappers[1] == 0) {
		/* Some specific cores don't need wrappers */
		switch (core->id.id) {
		case BCMA_CORE_4706_MAC_GBIT_COMMON:
		case BCMA_CORE_NS_CHIPCOMMON_B:
		case BCMA_CORE_PMU:
		case BCMA_CORE_GCI:
		/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
			break;
		default:
			bcma_erom_skip_component(bus, eromptr);
			return -ENXIO;
		}
	}

	if (bcma_erom_is_bridge(bus, eromptr)) {
		bcma_erom_skip_component(bus, eromptr);
		return -ENXIO;
	}

	if (bcma_find_core_by_index(bus, core_num)) {
		bcma_erom_skip_component(bus, eromptr);
		return -ENODEV;
	}

	if (match && ((match->manuf != BCMA_ANY_MANUF &&
	      match->manuf != core->id.manuf) ||
	     (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
	     (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
	     (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
	    )) {
		bcma_erom_skip_component(bus, eromptr);
		return -ENODEV;
	}

	/* get & parse master ports */
	for (i = 0; i < ports[0]; i++) {
		s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
		if (mst_port_d < 0)
			return -EILSEQ;
	}

	/* First Slave Address Descriptor should be port 0:
	 * the main register space for the core
	 */
	tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
	if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
		/* Try again to see if it is a bridge */
		tmp = bcma_erom_get_addr_desc(bus, eromptr,
					      SCAN_ADDR_TYPE_BRIDGE, 0);
		if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
			return -EILSEQ;
		} else {
			bcma_info(bus, "Bridge found\n");
			return -ENXIO;
		}
	}
	core->addr = tmp;

	/* get & parse slave ports */
	k = 0;
	for (i = 0; i < ports[1]; i++) {
		for (j = 0; ; j++) {
			tmp = bcma_erom_get_addr_desc(bus, eromptr,
				SCAN_ADDR_TYPE_SLAVE, i);
			if (IS_ERR_VALUE_U32(tmp)) {
				/* no more entries for port _i_ */
				/* pr_debug("erom: slave port %d "
				 * "has %d descriptors\n", i, j); */
				break;
			} else if (k < ARRAY_SIZE(core->addr_s)) {
				core->addr_s[k] = tmp;
				k++;
			}
		}
	}

	/* get & parse master wrappers */
	for (i = 0; i < wrappers[0]; i++) {
		for (j = 0; ; j++) {
			tmp = bcma_erom_get_addr_desc(bus, eromptr,
				SCAN_ADDR_TYPE_MWRAP, i);
			if (IS_ERR_VALUE_U32(tmp)) {
				/* no more entries for port _i_ */
				/* pr_debug("erom: master wrapper %d "
				 * "has %d descriptors\n", i, j); */
				break;
			} else {
				if (i == 0 && j == 0)
					core->wrap = tmp;
			}
		}
	}

	/* get & parse slave wrappers */
	for (i = 0; i < wrappers[1]; i++) {
		u8 hack = (ports[1] == 1) ? 0 : 1;
		for (j = 0; ; j++) {
			tmp = bcma_erom_get_addr_desc(bus, eromptr,
				SCAN_ADDR_TYPE_SWRAP, i + hack);
			if (IS_ERR_VALUE_U32(tmp)) {
				/* no more entries for port _i_ */
				/* pr_debug("erom: master wrapper %d "
				 * has %d descriptors\n", i, j); */
				break;
			} else {
				if (wrappers[0] == 0 && !i && !j)
					core->wrap = tmp;
			}
		}
	}
	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
		core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE);
		if (!core->io_addr)
			return -ENOMEM;
		if (core->wrap) {
			core->io_wrap = ioremap(core->wrap,
							BCMA_CORE_SIZE);
			if (!core->io_wrap) {
				iounmap(core->io_addr);
				return -ENOMEM;
			}
		}
	}
	return 0;
}