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

相关