static u64 __init fdt_translate_address()

in fdt_address.c [163:240]


static u64 __init fdt_translate_address(const void *blob, int node_offset)
{
	int parent, len;
	const struct of_bus *bus, *pbus;
	const __be32 *reg;
	__be32 addr[OF_MAX_ADDR_CELLS];
	int na, ns, pna, pns;
	u64 result = OF_BAD_ADDR;

	pr_debug("** translation for device %s **\n",
		 fdt_get_name(blob, node_offset, NULL));

	reg = fdt_getprop(blob, node_offset, "reg", &len);
	if (!reg) {
		pr_err("warning: device tree node '%s' has no address.\n",
			fdt_get_name(blob, node_offset, NULL));
		goto bail;
	}

	/* Get parent & match bus type */
	parent = fdt_parent_offset(blob, node_offset);
	if (parent < 0)
		goto bail;
	bus = &of_busses[0];

	/* Cound address cells & copy address locally */
	bus->count_cells(blob, parent, &na, &ns);
	if (!OF_CHECK_COUNTS(na, ns)) {
		pr_err("Bad cell count for %s\n",
		       fdt_get_name(blob, node_offset, NULL));
		goto bail;
	}
	memcpy(addr, reg, na * 4);

	pr_debug("bus (na=%d, ns=%d) on %s\n",
		 na, ns, fdt_get_name(blob, parent, NULL));
	of_dump_addr("translating address:", addr, na);

	/* Translate */
	for (;;) {
		/* Switch to parent bus */
		node_offset = parent;
		parent = fdt_parent_offset(blob, node_offset);

		/* If root, we have finished */
		if (parent < 0) {
			pr_debug("reached root node\n");
			result = of_read_number(addr, na);
			break;
		}

		/* Get new parent bus and counts */
		pbus = &of_busses[0];
		pbus->count_cells(blob, parent, &pna, &pns);
		if (!OF_CHECK_COUNTS(pna, pns)) {
			pr_err("Bad cell count for %s\n",
				fdt_get_name(blob, node_offset, NULL));
			break;
		}

		pr_debug("parent bus (na=%d, ns=%d) on %s\n",
			 pna, pns, fdt_get_name(blob, parent, NULL));

		/* Apply bus translation */
		if (fdt_translate_one(blob, node_offset, bus, pbus,
					addr, na, ns, pna, "ranges"))
			break;

		/* Complete the move up one level */
		na = pna;
		ns = pns;
		bus = pbus;

		of_dump_addr("one level translation:", addr, na);
	}
 bail:
	return result;
}