Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48819
  • 博文数量: 13
  • 博客积分: 25
  • 博客等级: 民兵
  • 技术积分: 20
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-08 19:06
文章分类
文章存档

2013年(13)

我的朋友

分类: 嵌入式

2013-07-15 00:48:26

原文地址:地址映射分析 作者:lwchsz

//以/soc@ffe00000/ethernet@b0000/queue-group@0为例子,此时np为该节点
static int gfar_parse_group(struct device_node *np,
        struct gfar_private *priv, const char *model)
{
    u32 *queue_mask;
#ifdef CONFIG_GFAR_SW_PKT_STEERING
    int i;
    int cpus = num_online_cpus();
#endif
    priv->gfargrp[priv->num_grps].regs = of_iomap(np, 0);//映射
    if (!priv->gfargrp[priv->num_grps].regs)
        return -ENOMEM;

    priv->gfargrp[priv->num_grps].interruptTransmit =
            irq_of_parse_and_map(np, 0);

    /* If we aren't the FEC we have multiple interrupts */
    if (model && strcasecmp(model, "FEC")) {
        priv->gfargrp[priv->num_grps].interruptReceive =
            irq_of_parse_and_map(np, 1);
        priv->gfargrp[priv->num_grps].interruptError =
            irq_of_parse_and_map(np,2);
        if (priv->gfargrp[priv->num_grps].interruptTransmit < 0 ||
            priv->gfargrp[priv->num_grps].interruptReceive < 0 ||
            priv->gfargrp[priv->num_grps].interruptError < 0) {
            return -EINVAL;
        }
    }

    priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
    priv->gfargrp[priv->num_grps].priv = priv;
    spin_lock_init(&priv->gfargrp[priv->num_grps].grplock);
    if(priv->mode == MQ_MG_MODE) {
        queue_mask = (u32 *)of_get_property(np,
                    "rx-bit-map", NULL);
        priv->gfargrp[priv->num_grps].rx_bit_map =
            queue_mask ?  *queue_mask :(DEFAULT_MAPPING >> priv->num_grps);
        queue_mask = (u32 *)of_get_property(np,
                    "tx-bit-map", NULL);
        priv->gfargrp[priv->num_grps].tx_bit_map =
            queue_mask ? *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
    } else {
        priv->gfargrp[priv->num_grps].rx_bit_map = 0xFF;
        priv->gfargrp[priv->num_grps].tx_bit_map = 0xFF;
    }
#ifdef CONFIG_GFAR_SW_PKT_STEERING
    if (priv->sps) {
        /* register msg unit for virtual tx interrupt for each cpu */
        for (i = 0; i < cpus; i++) { /* for each cpu */
            priv->gfargrp[priv->num_grps].msg_virtual_tx[i]
                = fsl_get_msg_unit();
            if (IS_ERR
            (priv->gfargrp[priv->num_grps].msg_virtual_tx[i])) {
                priv->sps = 0;
                printk(KERN_WARNING
                "%s: unable to allocate msg interrupt for pkt"
                "steering, error = %ld!\n", __func__,
                PTR_ERR(priv->gfargrp[priv->num_grps].
                msg_virtual_tx[i]));
            }
        }
    }
#endif
    priv->num_grps++;

    return 0;
}

//arch/powerpc/kernel/prom_parse.c
void __iomem *of_iomap(struct device_node *np, int index)
{
    struct resource res;

    if (of_address_to_resource(np, index, &res))
        return NULL;

    return ioremap(res.start, 1 + res.end - res.start);//进行物理地址映射
}

int of_address_to_resource(struct device_node *dev, int index,
               struct resource *r)
{
    const u32    *addrp;
    u64        size;
    unsigned int    flags;

    addrp = of_get_address(dev, index, &size, &flags);//查找设备的地址,返回值为指向设备地址属性的指针,以及地址空间大小和标志
    if (addrp == NULL)
        return -EINVAL;
    return __of_address_to_resource(dev, addrp, size, flags, r);//把地址属性转换的r中保存
}

const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
            unsigned int *flags)
{
    const u32 *prop;
    unsigned int psize;
    struct device_node *parent;
    struct of_bus *bus;
    int onesize, i, na, ns;

    /* Get parent & match bus type */
    parent = of_get_parent(dev);
    if (parent == NULL)
        return NULL;
    bus = of_match_bus(parent);//查找父节点所在的bus
    bus->count_cells(dev, &na, &ns);//调用bus的函数,其实就是of_bus_default_count_cells,此时得到na,ns都是1,表示地址和长度都是占一个整数
    of_node_put(parent);
    if (!OF_CHECK_COUNTS(na, ns))
        return NULL;

    /* Get "reg" or "assigned-addresses" property */
    prop = of_get_property(dev, bus->addresses, &psize);//获取设备的地址属性,bus->addresses为"reg"
    if (prop == NULL)
        return NULL;
    psize /= 4;

    onesize = na + ns;
    for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
        if (i == index) {
            if (size)
                *size = of_read_number(prop + na, ns);//获取size为0x1000
            if (flags)
                *flags = bus->get_flags(prop);//其实是of_bus_default_get_flags,所以标志为IORESOURCE_MEM
            return prop;
        }
    return NULL;
}


static struct of_bus *of_match_bus(struct device_node *np)
{
    int i;

    for (i = 0; i < ARRAY_SIZE(of_busses); i ++)//在所有的bus总线查找匹配的总线
        if (!of_busses[i].match || of_busses[i].match(np))
            return &of_busses[i];
    BUG();
    return NULL;
}
/*
 * Array of bus specific translators
 */

static struct of_bus of_busses[] = {
#ifdef CONFIG_PCI
    /* PCI */
    {
        .name = "pci",
        .addresses = "assigned-addresses",
        .match = of_bus_pci_match,
        .count_cells = of_bus_pci_count_cells,
        .map = of_bus_pci_map,
        .translate = of_bus_pci_translate,
        .get_flags = of_bus_pci_get_flags,
    },
#endif /* CONFIG_PCI */
    /* ISA */
    {
        .name = "isa",
        .addresses = "reg",
        .match = of_bus_isa_match,
        .count_cells = of_bus_isa_count_cells,
        .map = of_bus_isa_map,
        .translate = of_bus_isa_translate,
        .get_flags = of_bus_isa_get_flags,
    },
    /* Default */
    {
        .name = "default",
        .addresses = "reg",
        .match = NULL,
        .count_cells = of_bus_default_count_cells,
        .map = of_bus_default_map,
        .translate = of_bus_default_translate,
        .get_flags = of_bus_default_get_flags,
    },
};

static void of_bus_default_count_cells(struct device_node *dev,
                       int *addrc, int *sizec)
{
    if (addrc)
        *addrc = of_n_addr_cells(dev);//获取dev父节点的#address-cells属性,所以对于/soc@ffe00000/ethernet@b0000/queue-group@0,其实是获取/soc@ffe00000/ethernet@b0000节点的
    if (sizec)
        *sizec = of_n_size_cells(dev);获取dev父节点的#size-cells属性
}

int of_n_addr_cells(struct device_node *np)
{
    const int *ip;

    do {
        if (np->parent)
            np = np->parent;
        ip = of_get_property(np, "#address-cells", NULL);
        if (ip)
            return be32_to_cpup(ip);
    } while (np->parent);
    /* No #address-cells property for the root node */
    return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
}
EXPORT_SYMBOL(of_n_addr_cells);

int of_n_size_cells(struct device_node *np)
{
    const int *ip;

    do {
        if (np->parent)
            np = np->parent;
        ip = of_get_property(np, "#size-cells", NULL);
        if (ip)
            return be32_to_cpup(ip);
    } while (np->parent);
    /* No #size-cells property for the root node */
    return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
}

static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
                    u64 size, unsigned int flags,
                    struct resource *r)
{
    u64 taddr;

    if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
        return -EINVAL;
    taddr = of_translate_address(dev, addrp);//分析地址属性,转换为64位的实际物理地址
    if (taddr == OF_BAD_ADDR)
        return -EINVAL;
    memset(r, 0, sizeof(struct resource));
    if (flags & IORESOURCE_IO) {
        unsigned long port;
        port = pci_address_to_pio(taddr);
        if (port == (unsigned long)-1)
            return -EINVAL;
        r->start = port;
        r->end = port + size - 1;
    } else {
        r->start = taddr;//把起始地址存放到start
        r->end = taddr + size - 1;
    }
    r->flags = flags;
    r->name = dev->name;
    return 0;
}

u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
{
    return __of_translate_address(dev, in_addr, "ranges");
}

u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
               const char *rprop)
{
    struct device_node *parent = NULL;
    struct of_bus *bus, *pbus;
    u32 addr[OF_MAX_ADDR_CELLS];
    int na, ns, pna, pns;
    u64 result = OF_BAD_ADDR;

    DBG("OF: ** translation for device %s **\n", dev->full_name);//OF: ** translation for device /soc@ffe00000/ethernet@b0000/queue-group@0 **

    /* Increase refcount at current level */
    of_node_get(dev);

    /* Get parent & match bus type */
    parent = of_get_parent(dev);///soc@ffe00000/ethernet@b0000
    if (parent == NULL)
        goto bail;
    bus = of_match_bus(parent);

    /* Cound address cells & copy address locally */
    bus->count_cells(dev, &na, &ns);//得到/soc@ffe00000/ethernet@b0000的 #address-cells = <1>; #size-cells = <1>;
    if (!OF_CHECK_COUNTS(na, ns)) {
        printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
               dev->full_name);
        goto bail;
    }
    memcpy(addr, in_addr, na * 4);//得到地址为0xb0000

    DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
        bus->name, na, ns, parent->full_name);//OF: bus is default (na=1, ns=1) on /soc@ffe00000/ethernet@b0000
    of_dump_addr("OF: translating address:", addr, na);

    /* Translate */
    for (;;) {//循环得到实际的物理地址,其实把偏移地址和上级的基地址相加
        /* Switch to parent bus */
        of_node_put(dev);
        dev = parent;//第一次dev为/soc@ffe00000/ethernet@b0000,第2次为/soc@ffe00000,第3次为根/
        parent = of_get_parent(dev);

        /* If root, we have finished */
        if (parent == NULL) {//到达根时退出
            DBG("OF: reached root node\n");
            result = of_read_number(addr, na);//到达根时候addr【0】=0,addr【1】=0xffeb0000,na=2
            break;
        }

        /* Get new parent bus and counts */
        pbus = of_match_bus(parent);
        pbus->count_cells(dev, &pna, &pns);;//第一次dev为/soc@ffe00000的  #address-cells = <1>; #size-cells = <1>;,第2次为/的  #address-cells = <2>; #size-cells = <2>
        if (!OF_CHECK_COUNTS(pna, pns)) {
            printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
                   dev->full_name);
            break;
        }

        DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
            pbus->name, pna, pns, parent->full_name);//第一次打印OF: parent bus is default (na=1, ns=1) on /soc@ffe00000,/第2次打印OF: parent bus is default (na=2, ns=2) on /

        /* Apply bus translation */
        if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))//把addr在bus上的偏移地址转换为bus相对父亲bus的偏移地址
            break;

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

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

    return result;
}

static int of_translate_one(struct device_node *parent, struct of_bus *bus,
                struct of_bus *pbus, u32 *addr,
                int na, int ns, int pna, const char *rprop)
{
    const u32 *ranges;
    unsigned 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 = of_get_property(parent, rprop, &rlen);//获取‘ranges'属性,第一次为/soc@ffe00000/ethernet@b0000没有该属性,第2次为/soc@ffe00000/ethernet有属性ranges =
//<0x0  0x0 0xffe00000 0x100000>;
    if (ranges == NULL || rlen == 0) {
        offset = of_read_number(addr, na);//计算偏移值
        memset(addr, 0, pna * 4);//同时把基地址置为0
        DBG("OF: no ranges, 1:1 translation\n");//没有基地址所以是同等转换
        goto finish;
    }

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

    /* Now walk through the ranges */
    rlen /= 4;//第2次得到rlen=4
    rone = na + pna + ns;//1+2+1
    for (; rlen >= rone; rlen -= rone, ranges += rone) {
        offset = bus->map(addr, ranges, na, ns, pna);//把addr转换为偏移值,其实是调用static u64 of_bus_default_map(u32 *addr, const u32 *range,
  //      int na, int ns, int pna)
{
    u64 cp, s, da;

    cp = of_read_number(range, na);
    s  = of_read_number(range + na + pna, ns);
    da = of_read_number(addr, na);

    DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
        cp, s, da);

    if (da < cp || da >= (cp + s))
        return OF_BAD_ADDR;
    return da - cp;
}


        if (offset != OF_BAD_ADDR)
            break;
    }
    if (offset == OF_BAD_ADDR) {
        DBG("OF: not found !\n");
        return 1;
    }
    memcpy(addr, ranges + na, 4 * pna);//把基地址拷贝到addr,其实为0x0 0xffe00000

 finish:
    of_dump_addr("OF: parent translation for:", addr, pna);
    DBG("OF: with offset: "PRu64"\n", offset);

    /* Translate it into parent bus space */
    return pbus->translate(addr, offset, pna);//转换为父总线的地址空间,其实是调用of_bus_default_translate
}

static u64 of_bus_default_map(u32 *addr, const u32 *range,
        int na, int ns, int pna)
{
    u64 cp, s, da;

    cp = of_read_number(range, na);//起始偏移,其实是0
    s  = of_read_number(range + na + pna, ns);//长度为0x100000
    da = of_read_number(addr, na);//目的地址为0xb000

    DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
        cp, s, da);//OF: default map, cp=0, s=100000, da=b0000

    if (da < cp || da >= (cp + s))
        return OF_BAD_ADDR;
    return da - cp;
}

static int of_bus_default_translate(u32 *addr, u64 offset, int na)//基地址加偏移地址,并把转换后的地址存到addr
{
    u64 a = of_read_number(addr, na);
    memset(addr, 0, na * 4);
    a += offset;
    if (na > 1)
        addr[na - 2] = a >> 32;
    addr[na - 1] = a & 0xffffffffu;

    return 0;
}

阅读(3354) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~