platform_get_resource=NULL内核源码分析

简介: platform_get_resource=NULL内核源码分析

platform_get_resource获取设备树资源出现失败,确保参数没有错误,且设备树中确实有对应device,举例如下:

代码如下

设备树内容如下

通过代码我们知当没有获取到资源的时候,就会报错。

1.第一步,我们看一下什么情况下platform_get_resource函才会返回NULL,也就是没有获取到资源。

platform_get_resource函数定又在drivers/base/platform.c中

struct resource *platform_get_resource(struct platform_device *dev,
                       unsigned int type, unsigned int num)
{
    int i;
    for (i = 0; i < dev->num_resources; i++) {
        struct resource *r = &dev->resource[i];
        if (type == resource_type(r) && num-- == 0)
            return r;
    }
    return NULL;
}

说明根本没有进入for循环,为什么?也就是说dev->num_resources为0,为什么为0?正常的话dev->num_resources应该为1。

通过代码我们可知,当for循环不成立的时候,也就是为时,才会返回NULL。

所以我们要分析为什么dev->num_resources为0?

通过之前的内容我们知道设备树最终转换成platform_device(并不是所有节点都会转),在转成platform_device的时候,会对num_resources进行值,所以跟踪下设备的转换流程,看一下什么情况下会被值成0。

2.第二步,因为myled这个设节点会转成了platform_device,所以我们只需要分忻构建resources赋值的代码即可。

通过的面的学习我们知道:

在drivers/of/platform.c下的of_platform_device_create_pdata下的of_device_alloc函数会创建

resources,

struct platform_device *of_device_alloc(struct device_node *np,
                  const char *bus_id,
                  struct device *parent)
{
    struct platform_device *dev;
    int rc, i, num_reg = 0, num_irq;
    struct resource *res, temp_res;
    dev = platform_device_alloc("", -1);
    if (!dev)
        return NULL;
    /* count the io and irq resources */
    while (of_address_to_resource(np, num_reg, &temp_res) == 0)
        num_reg++;
    num_irq = of_irq_count(np);
    /* Populate the resource table */
    if (num_irq || num_reg) {
        res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
        if (!res) {
            platform_device_put(dev);
            return NULL;
        }
        dev->num_resources = num_reg + num_irq;
        dev->resource = res;
        for (i = 0; i < num_reg; i++, res++) {
            rc = of_address_to_resource(np, i, res);
            WARN_ON(rc);
        }
        if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
            pr_debug("not all legacy IRQ resources mapped for %s\n",
                 np->name);
    }
    dev->dev.of_node = of_node_get(np);
    dev->dev.parent = parent ? : &platform_bus;
    if (bus_id)
        dev_set_name(&dev->dev, "%s", bus_id);
    else
        of_device_make_bus_id(&dev->dev);
    return dev;
}
dev->num_resources = num_reg + num_irq;

节点中没有中断资源,所以num_irq为0,num_reg初始化是0,下面代码统计num_reg数量

/* count the io and irq resources */

while (of_address_to_resource(np, num_reg, &temp_res) == 0)

num_reg++;

of_device_alloc

of_address_to_resource

int of_address_to_resource(struct device_node *dev, int index,
               struct resource *r)
{
    const __be32    *addrp;
    u64        size;
    unsigned int    flags;
    const char    *name = NULL;
    addrp = of_get_address(dev, index, &size, &flags);
    if (addrp == NULL)
        return -EINVAL;
    /* Get optional "reg-names" property to add a name to a resource */
    of_property_read_string_index(dev, "reg-names",    index, &name);
    return __of_address_to_resource(dev, addrp, size, flags, name, r);
}

EXPORT_SYMBOL_GPL(of_address_to_resource);

of_device_alloc

of_address_to_resource

__of_address_to_resource

static int __of_address_to_resource(struct device_node *dev,
        const __be32 *addrp, u64 size, unsigned int flags,
        const char *name, struct resource *r)
{
    u64 taddr;
    if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
        return -EINVAL;
    taddr = of_translate_address(dev, addrp);
    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;
        r->end = taddr + size - 1;
    }
    r->flags = flags;
    r->name = name ? name : dev->full_name;
    return 0;
}

taddr = of_translate_address(dev, addrp);

of_device_alloc

of_address_to_resource

__of_address_to_resource

of_translate_address(传入了ranges属性)

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

__of_translate_address

static u64 __of_translate_address(struct device_node *dev,
                  const __be32 *in_addr, const char *rprop)
{
    struct device_node *parent = NULL;
    struct of_bus *bus, *pbus;
    __be32 addr[OF_MAX_ADDR_CELLS];
    int na, ns, pna, pns;
    u64 result = OF_BAD_ADDR;
    pr_debug("OF: ** translation for device %s **\n", of_node_full_name(dev));
    /* Increase refcount at current level */
    of_node_get(dev);
    /* Get parent & match bus type */
    parent = of_get_parent(dev);
    if (parent == NULL)
        goto bail;
    bus = of_match_bus(parent);
    /* Count address cells & copy address locally */
    bus->count_cells(dev, &na, &ns);
    if (!OF_CHECK_COUNTS(na, ns)) {
        pr_debug("OF: Bad cell count for %s\n", of_node_full_name(dev));
        goto bail;
    }
    memcpy(addr, in_addr, na * 4);
    pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
        bus->name, na, ns, of_node_full_name(parent));
    of_dump_addr("OF: translating address:", addr, na);
    /* Translate */
    for (;;) {
        /* Switch to parent bus */
        of_node_put(dev);
        dev = parent;
        parent = of_get_parent(dev);
        /* If root, we have finished */
        if (parent == NULL) {
            pr_debug("OF: reached root node\n");
            result = of_read_number(addr, na);
            break;
        }
        /* Get new parent bus and counts */
        pbus = of_match_bus(parent);
        pbus->count_cells(dev, &pna, &pns);
        if (!OF_CHECK_COUNTS(pna, pns)) {
            printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
                   of_node_full_name(dev));
            break;
        }
        pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
            pbus->name, pna, pns, of_node_full_name(parent));
        /* Apply bus translation */
        if (of_translate_one(dev, 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:
    of_node_put(parent);
    of_node_put(dev);
    return result;
}
/* Apply bus translation */
if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
    break;

注意:of_translate_one参数rprop为“ranges"

static int of_translate_one(struct device_node *parent, struct of_bus *bus,
                struct of_bus *pbus, __be32 *addr,
                int na, int ns, int pna, const char *rprop)
{
    const __be32 *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.
     *
     * As far as we know, this damage only exists on Apple machines, so
     * This code is only enabled on powerpc. --gcl
     */
    ranges = of_get_property(parent, rprop, &rlen);
    if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
        pr_debug("OF: no ranges; cannot translate\n");
        return 1;
    }
    if (ranges == NULL || rlen == 0) {
        offset = of_read_number(addr, na);
        memset(addr, 0, pna * 4);
        pr_debug("OF: empty ranges; 1:1 translation\n");
        goto finish;
    }
    pr_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) {
        pr_debug("OF: not found !\n");
        return 1;
    }
    memcpy(addr, ranges + na, 4 * pna);
 finish:
    of_dump_addr("OF: parent translation for:", addr, pna);
    pr_debug("OF: with offset: %llx\n", (unsigned long long)offset);
    /* Translate it into parent bus space */
    return pbus->translate(addr, offset, pna);
}

由于属性中没有ranges属性,所以ranges=NULL

ranges = of_get_property(parent, rprop, &rlen);
    if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
        pr_debug("OF: no ranges; cannot translate\n");
        return 1;

导致of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)=1

if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
    break;

导致函数直接返回result

return result;

而result的值如下

u64 result = OF_BAD_ADDR;

所以

u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
{
    return __of_translate_address(dev, in_addr, "dma-ranges");
}

返回OF_BAD_ADDR

taddr = of_translate_address(dev, addrp);

if (taddr == OF_BAD_ADDR)

return -EINVAL;

int of_address_to_resource(struct device_node *dev, int index,
               struct resource *r)
{
    const __be32    *addrp;
    u64        size;
    unsigned int    flags;
    const char    *name = NULL;
    addrp = of_get_address(dev, index, &size, &flags);
    if (addrp == NULL)
        return -EINVAL;
    /* Get optional "reg-names" property to add a name to a resource */
    of_property_read_string_index(dev, "reg-names",    index, &name);
    return __of_address_to_resource(dev, addrp, size, flags, name, r);
}

返回-EINVAL

while (of_address_to_resource(np, num_reg, &temp_res) == 0)
    num_reg++;

所以不会进入while循环,也就是说num_reg=0;所以num_resources=0;

总结

of_translateone返回1

of_translate_address回OFBAD_ADDR

ofaddresstoresource返回EINVAL

ofaddresstoresource返回EINVAL

所以numreg为0,

通过代码的分折,当有ranges属性的时,但是属性值为0,则不对地址进行转,所以在设备节点中添加ranges属性即可。

如果文章对您有帮助,点赞👍支持,感谢🤝


目录
相关文章
|
7天前
|
存储 Java Android开发
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
27 1
|
7天前
|
Java Android开发
Rockchip系列之VendorStorage 新增framework系统jni+service接口访问(3)
Rockchip系列之VendorStorage 新增framework系统jni+service接口访问(3)
25 0
|
8月前
|
C语言 索引
09-iOS之load和initialize底层调用原理分析
09-iOS之load和initialize底层调用原理分析
61 0
|
7天前
|
安全 数据安全/隐私保护
SAP ABAP Gateway 系统接口 /IWBEP/IF_MGW_APPL_SRV_RUNTIME 的作用介绍
SAP ABAP Gateway 系统接口 /IWBEP/IF_MGW_APPL_SRV_RUNTIME 的作用介绍
36 0
|
10月前
|
Java
SpringBoot导入第三方jar方法打包报错Failed to load ApplicationContext Failed to determine a suitable driver cla
这是第一篇博客,很早想写了,只不过每次解决问题后都觉得人家写的蛮好的,自己无须再写了,不过昨天打包时遇到的这个问题,自己找半天解决了,看很多博客也是许久才解决,不说了我的方法如下:
101 0
|
7月前
|
Java API
SAP UI5 Library Resource Bundle 的设计原理
SAP UI5 Library Resource Bundle 的设计原理
54 0
RK3399平台开发系列讲解(内核入门篇)1.51、platform_get_resource 函数实现细节
RK3399平台开发系列讲解(内核入门篇)1.51、platform_get_resource 函数实现细节
99 0
RK3399平台开发系列讲解(内核入门篇)1.51、platform_get_resource 函数实现细节
module_platform_driver源码分析
module_platform_driver源码分析
ALSA驱动源码之devm_snd_soc_register_component源码分析
ALSA驱动源码之devm_snd_soc_register_component源码分析
sap gateway data provider - /IWFND/IF_MGW_CORE_RUNTIME
Created by Wang, Jerry, last modified on Mar 24, 2015
104 0
sap gateway data provider - /IWFND/IF_MGW_CORE_RUNTIME

热门文章

最新文章