//以/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) |