linux 设备树-of_address_to_resource

news2024/9/20 2:56:20

实例分析-reg 属性解析(基于ranges属性)

/{
	#address-cells = <0x01>;
	#size-cells = <0x01>;
	soc {
		compatible = "simple-bus";
		#address-cells = <0x01>;
		#size-cells = <0x01>;
		ranges = <0x7e000000 0x3f000000 0x1000000 0x40000000 0x40000000 0x1000>;
		dma@7e007000 {
			compatible = "brcm,bcm2835-dma";
			reg = <0x7e007000 0xf00>;
			......
		};
	}
	......
}

struct resource {

        resource_size_t start; // 0x3f007000

        resource_size_t end; // 0x3f007eff

        const char *name;     // dma@7e007000 (reg-names 或者device_node->full_name)

        unsigned long flags;   //   0x200 IORESOURCE_MEM

        unsigned long desc;

        struct resource *parent, *sibling, *child;

};

1. of_address_to_resource 整体分析


of_address_to_resource(np, num_reg, &temp_res)  
分析:获取节点的reg 属性,生成struct resource
	 最终填充到platfor_device 结构体的pdev->num_resources和 pdev->resource

核心的三步操作:

1. addrp = of_get_address(dev, index, &size, &flags);   	     
 分析: 获取reg 属性的 第index组的信息(addrp:基地址  size: 大小  flags:默认) 

2. of_property_read_string_index(dev, "reg-names",index, &name); 
 分析: 从reg-names 属性中获取index组的名称


3. return __of_address_to_resource(dev, addrp, size, flags, name, r); 
 分析: 进行地址转换(基于父节点的ranges属性),并存储到struct resource *r 结构体中

 第一步: of_get_address

const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
		    unsigned int *flags)
{
	const __be32 *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); 
    // 获取 of_bus 结构体:static struct of_bus of_busses[]
    // 匹配方式:np->type 或者 np->name 
	
    bus->count_cells(dev, &na, &ns);
    // 提取父节点或更高层节点的#address-cells和 #size-cells
	
    of_node_put(parent);
	if (!OF_CHECK_ADDR_COUNT(na))
		return NULL;

	/* Get "reg" or "assigned-addresses" property */
	prop = of_get_property(dev, bus->addresses, &psize); //prop 是基地址,
                                                         //psize 是字节流的长度,
	if (prop == NULL)
		return NULL;
	psize /= 4;                                          // psize/4 是cell 的长度

	onesize = na + ns;                                   //一组 (addr size) 的长度
	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
		if (i == index) {
			if (size)
				*size = of_read_number(prop + na, ns);
			if (flags)
				*flags = bus->get_flags(prop);
			return prop;
		}
	return NULL;
}

第二步:of_property_read_string_index()

        略

 第三步:__of_address_to_resource()

        __of_address_to_resource(dev, addrp, size, flags, name, r);



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_MEM)
		taddr = of_translate_address(dev, addrp);      //进行地址转换,获取转换后的地址
	else if (flags & IORESOURCE_IO)
		taddr = of_translate_ioport(dev, addrp, size);
	else
		return -EINVAL;

	if (taddr == OF_BAD_ADDR)
		return -EINVAL;
	memset(r, 0, sizeof(struct resource));

	r->start = taddr;					//填充到struct resource 结构体中
	r->end = taddr + size - 1;
	r->flags = flags;
	r->name = name ? name : dev->full_name;

	return 0;
}

u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
{
	struct device_node *host;
	u64 ret;

	ret = __of_translate_address(dev, in_addr, "ranges", &host);  根据父节点的ranges 进行多次转换(比如父节点的父节点)
 	if (host) {
		of_node_put(host);
		return OF_BAD_ADDR;
	}

	return ret;
}

static u64 __of_translate_address(struct device_node *dev,
				  const __be32 *in_addr, const char *rprop,
				  struct device_node **host)
{
	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("** translation for device %pOF **\n", dev);

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

	*host = NULL;
	/* 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("Bad cell count for %pOF\n", dev);
		goto bail;
	}
	memcpy(addr, in_addr, na * 4);

	pr_debug("bus is %s (na=%d, ns=%d) on %pOF\n",
	    bus->name, na, ns, parent);
	of_dump_addr("translating address:", addr, na);

	/* Translate */
	for (;;) {
		struct logic_pio_hwaddr *iorange;

		/* 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("reached root node\n");
			result = of_read_number(addr, na); //最终,根据addr这个地址 生成整数,然后返回整数
			break;
		}

		/*
		 * For indirectIO device which has no ranges property, get
		 * the address from reg directly.
		 */
		iorange = find_io_range_by_fwnode(&dev->fwnode);
		if (iorange && (iorange->flags != LOGIC_PIO_CPU_MMIO)) {
			result = of_read_number(addr + 1, na - 1);
			pr_debug("indirectIO matched(%pOF) 0x%llx\n",
				 dev, result);
			*host = of_node_get(dev);
			break;
		}

		/* Get new parent bus and counts */
		pbus = of_match_bus(parent);
		pbus->count_cells(dev, &pna, &pns);
		if (!OF_CHECK_COUNTS(pna, pns)) {
			pr_err("Bad cell count for %pOF\n", dev);
			break;
		}

		pr_debug("parent bus is %s (na=%d, ns=%d) on %pOF\n",
		    pbus->name, pna, pns, 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("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, __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 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("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("empty ranges; 1:1 translation\n");
		goto finish;
	}

	pr_debug("walking ranges...\n");
    
	/* Now walk through the ranges */
    // ranges 中存在多组转换, 选择正确的转换(ranges 地址为正确的一组的基地址)
    //offset = da- cp
	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("not found !\n");
		return 1;
	}
	memcpy(addr, ranges + na, 4 * pna);  //addr= 转换后的基地址

 finish:
	of_dump_addr("parent translation for:", addr, pna);
	pr_debug("with offset: %llx\n", (unsigned long long)offset);

	/* Translate it into parent bus space */
	return pbus->translate(addr, offset, pna); //  addr = addr + offset
}

bus->map(addr, ranges, na, ns, pna);

调用 of_bus_default_map

获取偏移(用于转换后的偏移)

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

	cp = of_read_number(range, na); 获取ranges 中的基地址(未转换的)
	s  = of_read_number(range + na + pna, ns); 获取ranges 中基地址的大小
	da = of_read_number(addr, na);//获取reg 中的基地址(未转换的)

	pr_debug("default map, cp=%llx, s=%llx, da=%llx\n",
		 (unsigned long long)cp, (unsigned long long)s,
		 (unsigned long long)da);

	if (da < cp || da >= (cp + s))  //有效: 必须大于 cp, 且小于 cp +s
		return OF_BAD_ADDR;
	return da - cp;   // 计算偏移(未转换前的)
}

 

 pbus->translate(addr, offset, pna);

        调用of_bus_default_translate

static int of_bus_default_translate(__be32 *addr, u64 offset, int na)
{
	u64 a = of_read_number(addr, na);
	memset(addr, 0, na * 4);
	a += offset;
	if (na > 1)
		addr[na - 2] = cpu_to_be32(a >> 32);
	addr[na - 1] = cpu_to_be32(a & 0xffffffffu);

	return 0;
}

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

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

相关文章

lesson03:类和对象(中)

1.类的6个默认的成员函数 2.构造函数 3.析构函数 4.拷贝构造函数 1.类的6个默认的成员函数 空类&#xff08;类中一个成员都没没有&#xff09;会有成员函数吗&#xff1f; 其实是有的&#xff01;如果我们在类中什么都不写&#xff0c;编译器会自动生成6个默认成员函数&a…

HTML的学习-通过创建相册WEB学习HTML-第二部分

文章目录 二、学习开始3.6、form元素示例&#xff1a;添加form元素示例&#xff1a;action属性添加到form属性中 3.7、input元素示例&#xff1a;在input属性中添加参数 3.8、button元素示例&#xff1a;在button中添加type元素示例&#xff1a;定义单选按钮radio 3.9、id属性示…

时序分析基础(6)——input delay时序分析

1 简介 FPGA对于外部的时钟以及数据的延时信息是不知道的&#xff0c;在低速时钟且时钟发射沿在数据正中心的时候&#xff0c;一般可以不做约束来直接使用。但是到了高速时钟或者双沿采样或者发射沿和数据对齐的情况下&#xff0c;这时候就需要告诉VIVADO外部的时钟与数据情况来…

[2021最新]大数据平台CDH存储组件kudu之启用HA高可用(添加多个master)

今天在做kudu高可用的时候没有参考官网&#xff0c;直接按照常规方式&#xff08;添加角色—>编辑属性—>启动&#xff09;结果发现报错&#xff1f;然后参考了一下文档之后发现这玩意儿还有点玄学&#xff0c;做一下记录。 1.添加两个master。kudu master有leader和foll…

革命性创新,实景AI无人自动直播系统,轻松实现24小时日不落直播卖券。

革命性创新&#xff01;实景AI无人自动直播系统&#xff0c;轻松实现24小时日不落直播卖券&#xff01; 最近&#xff0c;越来越多的朋友纷纷关注到了AI自动直播带货的新玩法&#xff0c;并且也都想要开设自己的自动直播间。然而&#xff0c;对于这种自动讲解、自动回复的直播…

docker-003镜像制作

步骤 使用docker commit提交容器使之成为镜像以ubuntu安装vim后的容器为例 1 ubuntu安装vim 启动容器 docker run -it --nameubuntu-vim ubuntu /bin/bash安装vim apt-get update apt-get install vim2 提交容器作为镜像 查看容器 docker ps -a提交容器作为镜像 命令格式&…

js 打印网页时没有背景色,window.print打印背景色丢失

页面效果 打印效果 需要在打印的容器里增加下面代码 /*webkit 为Google Chrome、Safari等浏览器内核*/ -webkit-print-color-adjust: exact; /*解决火狐浏览器打印*/ print-color-adjust: exact; color-adjust: exact; 完整写法 我为了方便直接写*&#xff0c;这样所有元素都…

如何设置unbuntu时间及同步时间

文章目录 时区时间同步与服务 时间同步的重要性Ubuntu系统中设置时间和同步时间方法一&#xff1a;通过图形界面设置查看当前时间设置时间和时区设置时区&#xff08;假设设置为UTC&#xff09;&#xff1a;设置本地时间&#xff08;例如&#xff0c;设置时间为2024年4月21日 1…

23.组件注册方式

组件注册方式 一个 Vue 组件在使用前需要先被“注册”&#xff0c;这样 Vue 才能在渲染模板时找到其对应的实现。组件注册有两种方式&#xff1a;全局注册和局部注册 全局注册 import { createApp } from vue import App from ./App.vue import GlobalComponent from ".…

【C++】STL:vector常用接口的使用和模拟实现

Hello everybody!这篇文章主要给大家讲讲vector常用接口的模拟实现&#xff0c;STL库中的实现一层套着一层&#xff0c;十分复杂&#xff0c;目前阶段还不适合看源代码。而模拟实现可以让我们从底层上了解这些接口的原理从而更好的使用这些接口。另外我还会讲一些在vector使用过…

OSPF的学习笔记

1.OSPF &#xff08;1&#xff09;链路状态路由协议的路由信息并不是像距离矢量路由协议那样(邻居告诉的)&#xff0c;通过收集自身以及邻居发出的LSA(原材料)&#xff0c;并LSA放到指定仓库里面(LSDB)&#xff0c;通过SPF算法&#xff0c;以自己为根计算到达网络每个节点的最优…

LeetCode刷题实战5:最长回文子串

题目内容 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同&#xff0c;则该字符串称为回文字符串。 示例 1&#xff1a; 输入&#xff1a;s "babad" 输出&#xff1a;"bab" 解释&#xff1a;"aba"…

虚拟线程的定义及使用

0.前言 长期以来&#xff0c;虚拟线程是 Java 中最重要的创新之一。 它们是在 Project Loom 中开发的&#xff0c;自 Java 19 作为预览功能以来一直包含在 JDK 中&#xff0c;自 Java 21 作为最终版本 (JEP 444) 以来&#xff0c;它们已包含在 JDK 中。 1.虚拟线程的作用 任…

深入OceanBase内部机制:资源隔离实现的方式总结

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 目录 1. 为何HTAP需要资源隔离2. OceanBase的资源隔离机制概述租户间资源隔离租户内资源隔离物理资源隔离大查询请求的隔离优先级…

如何批量给Word文件增加前缀序号?“汇帮批量重命名”帮助你批量给word文件增加前缀序号。

批量给Word文件增加前缀序号的过程&#xff0c;对于经常处理大量文档的人来说&#xff0c;是一项既繁琐又必要的任务。首先&#xff0c;我们需要明确为什么要给Word文件增加前缀序号。在很多情况下&#xff0c;当我们需要按照一定的顺序对多个文档进行管理和归档时&#xff0c;…

【CSS】CSS实现元素逐渐消失(实现元素透明逐渐消失/模糊)

mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 10%);mask-image 属性用于定义一个遮罩&#xff0c;它可以隐藏元素的一部分或全部内容。在这个示例中&#xff0c;我们使用 mask-image 属性来定义一个线性渐变的遮罩&#xff0c;使得列表项的内…

适配器模式【结构型模式C++】

1.概述 适配器模式是一种结构型设计模式&#xff0c; 又称为变压器模式、包装模式&#xff08;Wrapper&#xff09; 将一个类的接口变换成客户端所期待的另一种接口&#xff0c;从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。 2.结构 Target&#xff1a;适配…

Https网站接口被黑被恶意调取

背景&#xff1a; 维护的一个网站最近短信接口被黑&#xff0c;发送大量短信。起初以为是在网站内部操作&#xff0c;优化了发送短信前的操作&#xff0c;如添加图形验证码&#xff0c;屏蔽国外IP等。但后续还存在被调取情况&#xff0c;定位排查到是该接口在外部被恶意调取。 …

Pod 状态 Bsck Off,是什么情况?

k8s项目运维中&#xff0c;相信各位都遇到过 Pod 状态 Bsck Off 的情况&#xff0c;如上图&#xff1a;该情况主要原因是我们 Pod 中没有任何容器运行成功&#xff0c;而能容器能成功运行的前提是&#xff0c;容器内部是有进程的&#xff0c;只要容器中的进程不停止&#xff0c…

ATM第二弹~~~

昨天发现自己电脑的运行速度太慢的问题后&#xff0c;在autodl租了个4090 &#xff08;本来跑了4个小时快好了&#xff0c;但由于没有续上费&#xff0c;断了。。。。&#xff09; ( 2.58 每小时&#xff0c;贵死我了。。。。&#xff09; 又重新开了个4090d&#xff08;409…