转自:https://www.cnblogs.com/pengdonglin137/p/7401049.html
作者
彭东林
pengdonglin137@163.com
软件环境
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理解下面的框图
完。