作者
彭东林
软件环境
Linux-4.10.17
Qemu+vexpress
概述
在设备树中有时会看到ranges属性,这个ranges属性可以达到什么效果呢? 今天看到宋宝华老师的设备树讲座,才知道。为了有一个直观的印象,下面我们结合一个实际的例子来看看
正文
一、设备树
下面是我们将要实验的设备树的例子:
1 / {
2 #address-cells = <1>;
3 #size-cells = <1>;
4
5 demo_level0 {
6 compatible = "simple-bus";
7 ranges = <0x0 0x3000000 0x3000>;
8 #address-cells = <1>;
9 #size-cells = <1>;
10
11 range@0 {
12 compatible = "range";
13 reg = <0x100 0x200>;
14 reg-names = "range0";
15 };
16
17 range@1 {
18 compatible = "range";
19 reg = <0x300 0x200>;
20 reg-names = "range1";
21 };
22
23 range@2 {
24 compatible = "range";
25 reg = <0x600 0x200>;
26 reg-names = "range2";
27 };
28
29 demo_level1 {
30 compatible = "simple-bus";
31 ranges = <0x0 0x1000 0x1000>;
32 #address-cells = <1>;
33 #size-cells = <1>;
34
35 range@3 {
36 compatible = "range";
37 reg = <0x100 0x200>;
38 reg-names = "range3";
39 };
40
41 demo_level1-1 {
42 compatible = "simple-bus";
43 ranges = <0x0 0x300 0x500>;
44 #address-cells = <1>;
45 #size-cells = <1>;
46
47 range@4 {
48 compatible = "range";
49 reg = <0x100 0x200>;
50 reg-names = "range4";
51 };
52
53 range@5 {
54 compatible = "range";
55 reg = <0x300 0x100>;
56 reg-names = "range5";
57 };
58
59 demo_level1-1-1 {
60 compatible = "simple-bus";
61 ranges = <0x0 0x400 0x100>;
62 #address-cells = <1>;
63 #size-cells = <1>;
64
65 range@6 {
66 compatible = "range";
67 reg = <0x50 0x30>;
68 reg-names = "range6";
69 };
70
71 demo_level1-1-1-1 {
72 compatible = "simple-bus";
73 ranges = <0x0 0x20 0x20>;
74 #address-cells = <1>;
75 #size-cells = <1>;
76
77 range@7 {
78 compatible = "range";
79 reg = <0x10 0x10>;
80 reg-names = "range7";
81 };
82
83 range@8 {
84 compatible = "range";
85 reg = <0x0 0x10>;
86 reg-names = "range8";
87 };
88 };
89 };
90 };
91
92 range@9 {
93 compatible = "range";
94 reg = <0x800 0x50>;
95 reg-names = "range9";
96 };
97
98 demo_level1-2 {
99 compatible = "simple-bus";
100 ranges = <0x0 0x900 0x100>;
101 #address-cells = <1>;
102 #size-cells = <1>;
103
104 range@10 {
105 compatible = "range";
106 reg = <0x0 0x50>;
107 reg-names = "range10";
108 };
109
110 demo_level1-2-1 {
111 compatible = "simple-bus";
112 ranges;
113 #address-cells = <1>;
114 #size-cells = <1>;
115
116 range@11 {
117 compatible = "range";
118 reg = <0x50 0x30>;
119 reg-names = "range11";
120 };
121 };
122 };
123 };
124
125 demo_level2 {
126 compatible = "simple-bus";
127 ranges;
128 #address-cells = <1>;
129 #size-cells = <1>;
130
131 range@12 {
132 compatible = "range";
133 reg = <0x2000 0x1000>;
134 reg-names = "range12";
135 };
136 };
137 }
138 };
二、驱动
下面是一个简单的驱动,功能很简单,只是在probe函数中将memory资源的start和(end+1)打印出来.
demo_range.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
static int demo_range_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
printk(KERN_INFO "%s start: 0x%x, end: 0x%x\n",
res->name, res->start, res->end + 1);
return 0;
}
static int demo_range_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id demo_range_of_match[] = {
{ .compatible = "range"},
{},
};
static struct platform_driver demo_range_driver = {
.driver = {
.name = "demo_range",
.owner = THIS_MODULE,
.of_match_table = demo_range_of_match,
},
.probe = demo_range_probe,
.remove = demo_range_remove,
};
module_platform_driver(demo_range_driver);
MODULE_LICENSE("GPL v2");
在驱动中会获得memory资源,然后将start和(end+1)打印出来,之所以这里用(end+1),仅仅是为了便于理解下面的kernel log。
三、验证
编译驱动,然后加载,可以看到下面的打印信息:
[root@vexpress mnt]# insmod demo_range.ko
[ 382.940402] range0 start: 0x3000100, end: 0x3000300
[ 382.940697] range1 start: 0x3000300, end: 0x3000500
[ 382.941448] range2 start: 0x3000600, end: 0x3000800
[ 382.941657] range3 start: 0x3001100, end: 0x3001300
[ 382.941855] range4 start: 0x3001400, end: 0x3001600
[ 382.942057] range5 start: 0x3001600, end: 0x3001700
[ 382.942262] range6 start: 0x3001750, end: 0x3001780
[ 382.942470] range7 start: 0x3001730, end: 0x3001740
[ 382.942684] range8 start: 0x3001720, end: 0x3001730
[ 382.949796] range9 start: 0x3001800, end: 0x3001850
[ 382.950023] range10 start: 0x3001900, end: 0x3001950
[ 382.950603] range11 start: 0x3001950, end: 0x3001980
[ 382.950805] range12 start: 0x3002000, end: 0x3003000
总结:
1、ranges属性值的格式 <local地址, parent地址, size>, 表示将local地址向parent地址的转换。
比如对于#address-cells和#size-cells都为1的话,以<0x0 0x10 0x20>为例,表示将local的从0x0~(0x0 + 0x20)的地址空间映射到parent的0x10~(0x10 + 0x20)
其中,local地址的个数取决于当前含有ranges属性的节点的#address-cells属性的值,size取决于当前含有ranges属性的节点的#size-cells属性的值。
而parent地址的个数取决于当前含有ranges属性的节点的parent节点的#address-cells的值。
2、对于含有ranges属性的节点的子节点来说,其reg都是基于local地址的
3、ranges属性值为空的话,表示1:1映射
4、对于没有ranges属性的节点,代表不是memory map区域
四、示意图
对照上面的log理解下面的框图
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CN3cjMxcjYxgjZzMWN3EWOhRGN2YTNjljZiRTZxATY28CXxMzLcdDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL4M3Lc9CX6MHc0RHaiojIsJye.png)
完。