platform_get_resource=NULL内核源码分析

news2025/1/11 8:18:58

platform_get_resource=NULL内核源码分析


文章目录

  • platform_get_resource=NULL内核源码分析
  • 1.第一步,我们看一下什么情况下platform_get_resource函才会返回NULL,也就是没有获取到资源。
  • 2.第二步,因为myled这个设节点会转成了platform_device,所以我们只需要分忻构建resources赋值的代码即可。
  • 总结


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属性即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/514949.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

suricata中DPDK收发包线程模型和配置说明

《基于DPDK收包的suricata的安装和运行》中已经讲过基于DPDK收发包的suricata的安装过程&#xff0c;今天我们来看一下&#xff0c;suricata中DPDK的收发包线程模型以及相关的配置。 1、收发包线程模型&#xff1a; 通过分析代码&#xff0c;suricata中DPDK收发包线程模型如下…

C高级 day03

1.编写一个名为myfirstshell.sh的脚本&#xff0c;它包括以下内容。 1、包含一段注释&#xff0c;列出您的姓名、脚本的名称和编写这个脚本的目的 2、和当前用户说“hello 用户名” 3、显示您的机器名 hostname 4、显示上一级目录中的所有文件的列表 5、显示变量PATH和HOM…

采药 DP 裸01背包 java

&#x1f351; 采药 import java.util.*;class Main{static int N 1010;static int[] f new int[N];public static void main(String[] aaa){Scanner sc new Scanner(System.in);int m sc.nextInt();int n sc.nextInt();for(int i 0; i < n; i){int v sc.nextInt()…

s2021ss62找规律

代码&#xff1a; #include<bits/stdc.h> using namespace std; int n,m,ans; int main() {cin>>n>>m;for(int i1;i<n-1;i)ansi;cout<<ansm;return 0; }

一文了解支付卡行业数据安全标准(PCI DSS 4.0)新要求

在接下来不到一年的时间里&#xff0c;将有越来越多的企业要遵守支付卡行业数据安全标准 (PCI DSS) 4.0 版的多项新要求。 关于 PCI DSS PCI DSS 包含 12 项保护支付卡数据的要求&#xff0c;在过去十年中都没有更新。但经过三年的商讨&#xff0c;现在已经进行了重大改革。 …

JavaScript基础语法篇超详解

目录 一. 什么是JavaScript? 概念 JavaScript可以做的事情 JavaScript和HTML, CSS之间的关系 JavaScript运行过程 二. 基础语法篇 第一个JavaScript程序 JS的书写形式 JS的代码注释 输入输出 变量的使用 变量命名 数据类型 变量的声明和使用 理解动态类型 JS变量类型 JS数组…

一百一十一、Hive——从HDFS到Hive的数据导入(静态分区、动态分区)

一、分区的定义 分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹&#xff0c; Hive 中的分区就是分目录 &#xff0c;把一个大的数据集根据业务需要分割成小的数据集。 在查询时通过 where 子句中的表达式选择查询所需要的指定的分区&#xff0c;这样的查询效率 会…

【教程】手把手教你用Clion进行STM32开发【如何优雅の进行嵌入式开发】

通过Clion进行嵌入式开发 一、工具安装 1、安装Clion 因为众所周知的原因&#xff0c;Clion的安装就不解释了&#xff0c;有需要的同学自行检索 2、安装STM32CubeMX 正常去官网下载最新版的安装就行了&#xff1a;STM32CubeMX - STM32Cube initialization code generator …

2673. 使二叉树所有路径值相等的最小代价(dfs+bfs)

题目描述 评论 (23) 题解 (54) 提交记录 2673. 使二叉树所有路径值相等的最小代价 难度 中等 14 给你一个整数 n 表示一棵 满二叉树 里面节点的数目&#xff0c;节点编号从 1 到 n 。根节点编号为 1 &#xff0c;树中每个非叶子节点 i 都有两个孩子&#xff0c;分别是左孩子 2 …

image adaptive 3dlut based on deep learning

文章目录 image adaptive 3dlut based on deep learning1. Learning Image-adaptive 3D Lookup Tables for High Performance Photo Enhancement in Real-time2. CLUT-Net: Learning Adaptively Compressed Representations of 3DLUTs for Lightweight Image Enhancement2.1 3d…

平安大视野解读主动健康:以运动改变生命轨迹,以名医权益为健康保驾护航

“每个人都会老&#xff0c;这不可避免&#xff0c;但是能不能老的迟一点&#xff1f;让我们能够活到一百岁还能够运动&#xff0c;不需要别人照顾&#xff0c;这是最大的成功&#xff1b;而科学运动是最关键的方式。”5月6日&#xff0c;在平安私人银行联合平安健康举办的“平…

Echarts使用本地JSON文件加载不出图表的解决方法以及Jquery访问本地JSON文件跨域的解决方法

前言 最近需要做一个大屏展示&#xff0c;需要用原生html5cssjs来写&#xff0c;所以去学了一下echarts的使用。在使用的过程中难免碰到许多BUG&#xff0c;百度那是必不可少的&#xff0c;可是这些人写的牛头不对马嘴&#xff0c;简直是标题党一大堆&#xff0c;令我作呕&…

使用pytest和allure框架实现自动化测试报告优化

目录 -x出现一条测试用例失败就退出测试 生成测试报告json pytest&#xff1a; 需要安装pytest和pytest-html(生成html测试报告&#xff09; pip install pytest 和 pip install pytest-html 命名规则 Pytest单元测试中的类名和方法名必须是以test开头,执行中只能找到test开头…

DeepLab v1

SEMANTIC IMAGE SEGMENTATION WITH DEEP CONVOLUTIONAL NETS AND FULLY CONNECTED CRFS 基于深度卷积网络和全连通CRFS的语义图像分割 ABSTRACT 深度卷积神经网络&#xff08;DCNNs&#xff09;最近在高级视觉任务中表现出了最新的性能&#xff0c;如图像分类和物体检测。这…

Docker | docker安装MySQL

知识目录 一、前言二、安装Docker镜像2.1 什么是docker2.2 为什么安装docker2.3 安装docker 三、Docker安装MySQL3.1 常用docker命令3.2 docker安装MySQL 四、结语 一、前言 大家好&#xff01;这篇文章主要讲解 如何在Centos7中安装Docker以及Docker安装MySQL:5.7.42 。 ✨本…

深度学习模型复杂度评估(时间复杂度、空间复杂度)

目录 1、两个指标 2、复杂度对模型的影响 1、两个指标 时间复杂度和空间复杂度是衡量一个算法的两个重要指标,用于表示算法的最差状态所需的时间增长量和所需辅助空间. 在深度学习神经网络模型中我们也通过&#xff1a; 计算量/FLOPS&#xff08;时间复杂度&#xff09;即…

VS Code 常用插件推荐

VS Code 常用插件推荐 1. Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code 适用于 VS Code 的中文&#xff08;简体&#xff09;语言包 2. Auto Rename Tag 自动关闭标签&#xff0c;写 html 标签的时候可以重命名标签名。 现在 vscode 已经内置了&…

大项目内训 2023.5.11

目录 分别介绍一下消息处理相关的MQ、WebSocket、分布式事务 介绍一下异步消息传输 如何配置websocket ​编辑 oatpp是什么&#xff1f; cinatra是什么&#xff1f; 我们教育最大的缺失, 是缺乏阅读、写作和逻辑训练 佳作推荐 分别介绍一下消息处理相关的MQ、WebSocket、…

CTF-PWN学习-为缺少指导的同学而生

很抱歉&#xff0c;博主也是个PWN的入门者。PWN的入门不可能是无痛的。能做到的只是减少一点初学者的痛苦。这篇博客会长期维护&#xff0c;也会越来越好。后期还可能会在B站出视频&#xff08;博主社恐&#xff0c;要迈出这一步可能需要好长时间&#xff09;。 PWN是个啥&…

QT + OpenGL + FFmpeg写的一个全景视频播放器

临时被分配了一个任务 写一个C版本的全景视频播放器 网上搜了搜 基于前辈的基础上 写的差不多了 测试视频源是用ffmpeg拉RTSP的流 最终是要嵌入到别的一个视频播放器模块 所以解码这块我不用太关注 只要实现渲染就可以了 效果如下 左边的窗口用于输入视频源 以及显示…