u-boot of_translate_address函数

/*
 * Translate an address from the device-tree into a CPU physical address,
 * this walks up the tree and applies the various bus mappings on the
 * way.
 *
 * Note: We consider that crossing any level with #size-cells == 0 to mean
 * that translation is impossible (that is we are not dealing with a value
 * that can be mapped to a cpu physical address). This is not really specified
 * that way, but this is traditionally the way IBM at least do things
 */
static u64 __of_translate_address(const void *blob, int node_offset,
                  const fdt32_t *in_addr, const char *rprop)
{
    int parent;
    struct of_bus *bus, *pbus;
    fdt32_t addr[OF_MAX_ADDR_CELLS];
    int na, ns, pna, pns;
    u64 result = OF_BAD_ADDR;

 

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

 

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

 

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

 

    debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
        bus->name, na, ns, fdt_get_name(blob, parent, NULL));
    of_dump_addr("OF: 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) {
            debug("OF: reached root node\n");
            result = fdt_read_number(addr, na);
            break;
        }

 

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

 

        debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
            pbus->name, pna, pns, fdt_get_name(blob, parent, NULL));

 

        /* Apply bus translation */
        if (of_translate_one(blob, node_offset, bus, pbus,
                    addr, na, ns, pna, rprop))
            break;

 

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

 

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

 

    return result;
}
 
 
int fdt_parent_offset(const void *fdt, int nodeoffset)
{
    int nodedepth = fdt_node_depth(fdt, nodeoffset);

    if (nodedepth < 0)
        return nodedepth;
    return fdt_supernode_atdepth_offset(fdt, nodeoffset,
                        nodedepth - 1, NULL);
}
 
 
int fdt_node_depth(const void *fdt, int nodeoffset)
{
    int nodedepth;
    int err;

    err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
    if (err)
        return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL;
    return nodedepth;
}
 
 
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
                 int supernodedepth, int *nodedepth)
{
    int offset, depth;
    int supernodeoffset = -FDT_ERR_INTERNAL;

    FDT_RO_PROBE(fdt);

    if (supernodedepth < 0)
        return -FDT_ERR_NOTFOUND;

    for (offset = 0, depth = 0;
         (offset >= 0) && (offset <= nodeoffset);
         offset = fdt_next_node(fdt, offset, &depth)) {
        if (depth == supernodedepth)
            supernodeoffset = offset;

        if (offset == nodeoffset) {
            if (nodedepth)
                *nodedepth = depth;

            if (supernodedepth > depth)
                return -FDT_ERR_NOTFOUND;
            else
                return supernodeoffset;
        }
    }

    if (fdt_chk_extra()) {
        if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
            return -FDT_ERR_BADOFFSET;
        else if (offset == -FDT_ERR_BADOFFSET)
            return -FDT_ERR_BADSTRUCTURE;
    }

    return offset; /* error from fdt_next_node() */
}
 
static int of_translate_one(const void *blob, int parent, struct of_bus *bus,
                struct of_bus *pbus, fdt32_t *addr,
                int na, int ns, int pna, const char *rprop)
{
    const fdt32_t *ranges;
    int rlen;
    int rone;
    u64 offset = OF_BAD_ADDR;

    /* Normally, an absence of a "ranges" property means we are
     * crossing a non-translatable boundary, and thus the addresses
     * below the current not cannot be converted to CPU physical ones.
     * Unfortunately, while this is very clear in the spec, it's not
     * what Apple understood, and they do have things like /uni-n or
     * /ht nodes with no "ranges" property and a lot of perfectly
     * useable mapped devices below them. Thus we treat the absence of
     * "ranges" as equivalent to an empty "ranges" property which means
     * a 1:1 translation at that level. It's up to the caller not to try
     * to translate addresses that aren't supposed to be translated in
     * the first place. --BenH.
     */
    ranges = fdt_getprop(blob, parent, rprop, &rlen);
    if (ranges == NULL || rlen == 0) {
        offset = fdt_read_number(addr, na);
        memset(addr, 0, pna * 4);
        debug("OF: no ranges, 1:1 translation\n");
        goto finish;
    }

    debug("OF: walking ranges...\n");

    /* Now walk through the ranges */
    rlen /= 4;
    rone = na + pna + ns;
    for (; rlen >= rone; rlen -= rone, ranges += rone) {
        offset = bus->map(addr, ranges, na, ns, pna);
        if (offset != OF_BAD_ADDR)
            break;
    }
    if (offset == OF_BAD_ADDR) {
        debug("OF: not found !\n");
        return 1;
    }
    memcpy(addr, ranges + na, 4 * pna);

 finish:
    of_dump_addr("OF: parent translation for:", addr, pna);
    debug("OF: with offset: %llu\n", offset);

    /* Translate it into parent bus space */
    return pbus->translate(addr, offset, pna);
}
 
 
posted @ 2022-02-23 21:07  liujunhuasd  阅读(203)  评论(0编辑  收藏  举报