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