|
| 1 | +.. SPDX-License-Identifier: GPL-2.0 |
| 2 | +.. include:: ../disclaimer-zh_CN.rst |
| 3 | + |
| 4 | +:Original: Documentation/Devicetree/of_unittest.rst |
| 5 | + |
| 6 | +:翻译: |
| 7 | + |
| 8 | + 司延腾 Yanteng Si <siyanteng@loongson.cn> |
| 9 | + |
| 10 | +:校译: |
| 11 | + |
| 12 | +================================= |
| 13 | +Open Firmware Devicetree 单元测试 |
| 14 | +================================= |
| 15 | + |
| 16 | +作者: Gaurav Minocha <gaurav.minocha.os@gmail.com> |
| 17 | + |
| 18 | +1. 概述 |
| 19 | +======= |
| 20 | + |
| 21 | +本文档解释了执行 OF 单元测试所需的测试数据是如何动态地附加到实时树上的,与机器的架构无关。 |
| 22 | + |
| 23 | +建议在继续读下去之前,先阅读以下文件。 |
| 24 | + |
| 25 | +(1) Documentation/devicetree/usage-model.rst |
| 26 | +(2) http://www.devicetree.org/Device_Tree_Usage |
| 27 | + |
| 28 | +OF Selftest被设计用来测试提供给设备驱动开发者的接口(include/linux/of.h),以从未扁平 |
| 29 | +化的设备树数据结构中获取设备信息等。这个接口被大多数设备驱动在各种使用情况下使用。 |
| 30 | + |
| 31 | + |
| 32 | +2. 测试数据 |
| 33 | +=========== |
| 34 | + |
| 35 | +设备树源文件(drivers/of/unittest-data/testcases.dts)包含执行drivers/of/unittest.c |
| 36 | +中自动化单元测试所需的测试数据。目前,以下设备树源包含文件(.dtsi)被包含在testcases.dt中:: |
| 37 | + |
| 38 | + drivers/of/unittest-data/tests-interrupts.dtsi |
| 39 | + drivers/of/unittest-data/tests-platform.dtsi |
| 40 | + drivers/of/unittest-data/tests-phandle.dtsi |
| 41 | + drivers/of/unittest-data/tests-match.dtsi |
| 42 | + |
| 43 | +当内核在启用OF_SELFTEST的情况下被构建时,那么下面的make规则:: |
| 44 | + |
| 45 | + $(obj)/%.dtb: $(src)/%.dts FORCE |
| 46 | + $(call if_changed_dep, dtc) |
| 47 | + |
| 48 | +用于将DT源文件(testcases.dts)编译成二进制blob(testcases.dtb),也被称为扁平化的DT。 |
| 49 | + |
| 50 | +之后,使用以下规则将上述二进制blob包装成一个汇编文件(testcases.dtb.S):: |
| 51 | + |
| 52 | + $(obj)/%.dtb.S: $(obj)/%.dtb |
| 53 | + $(call cmd, dt_S_dtb) |
| 54 | + |
| 55 | +汇编文件被编译成一个对象文件(testcases.dtb.o),并被链接到内核镜像中。 |
| 56 | + |
| 57 | + |
| 58 | +2.1. 添加测试数据 |
| 59 | +----------------- |
| 60 | + |
| 61 | +未扁平化的设备树结构体: |
| 62 | + |
| 63 | +未扁平化的设备树由连接的设备节点组成,其树状结构形式如下所述:: |
| 64 | + |
| 65 | + // following struct members are used to construct the tree |
| 66 | + struct device_node { |
| 67 | + ... |
| 68 | + struct device_node *parent; |
| 69 | + struct device_node *child; |
| 70 | + struct device_node *sibling; |
| 71 | + ... |
| 72 | + }; |
| 73 | + |
| 74 | +图1描述了一个机器的未扁平化设备树的通用结构,只考虑了子节点和同级指针。存在另一个指针, |
| 75 | +``*parent`` ,用于反向遍历该树。因此,在一个特定的层次上,子节点和所有的兄弟姐妹节点将 |
| 76 | +有一个指向共同节点的父指针(例如,child1、sibling2、sibling3、sibling4的父指针指向 |
| 77 | +根节点):: |
| 78 | + |
| 79 | + root ('/') |
| 80 | + | |
| 81 | + child1 -> sibling2 -> sibling3 -> sibling4 -> null |
| 82 | + | | | | |
| 83 | + | | | null |
| 84 | + | | | |
| 85 | + | | child31 -> sibling32 -> null |
| 86 | + | | | | |
| 87 | + | | null null |
| 88 | + | | |
| 89 | + | child21 -> sibling22 -> sibling23 -> null |
| 90 | + | | | | |
| 91 | + | null null null |
| 92 | + | |
| 93 | + child11 -> sibling12 -> sibling13 -> sibling14 -> null |
| 94 | + | | | | |
| 95 | + | | | null |
| 96 | + | | | |
| 97 | + null null child131 -> null |
| 98 | + | |
| 99 | + null |
| 100 | + |
| 101 | +Figure 1: 未扁平化的设备树的通用结构 |
| 102 | + |
| 103 | + |
| 104 | +在执行OF单元测试之前,需要将测试数据附加到机器的设备树上(如果存在)。因此,当调用 |
| 105 | +selftest_data_add()时,首先会读取通过以下内核符号链接到内核镜像中的扁平化设备树 |
| 106 | +数据:: |
| 107 | + |
| 108 | + __dtb_testcases_begin - address marking the start of test data blob |
| 109 | + __dtb_testcases_end - address marking the end of test data blob |
| 110 | + |
| 111 | +其次,它调用of_fdt_unflatten_tree()来解除扁平化的blob。最后,如果机器的设备树 |
| 112 | +(即实时树)是存在的,那么它将未扁平化的测试数据树附加到实时树上,否则它将自己作为 |
| 113 | +实时设备树附加。 |
| 114 | + |
| 115 | +attach_node_and_children()使用of_attach_node()将节点附加到实时树上,如下所 |
| 116 | +述。为了解释这一点,图2中描述的测试数据树被附加到图1中描述的实时树上:: |
| 117 | + |
| 118 | + root ('/') |
| 119 | + | |
| 120 | + testcase-data |
| 121 | + | |
| 122 | + test-child0 -> test-sibling1 -> test-sibling2 -> test-sibling3 -> null |
| 123 | + | | | | |
| 124 | + test-child01 null null null |
| 125 | + |
| 126 | + |
| 127 | +Figure 2: 将测试数据树附在实时树上的例子。 |
| 128 | + |
| 129 | +根据上面的方案,实时树已经存在,所以不需要附加根('/')节点。所有其他节点都是通过在 |
| 130 | +每个节点上调用of_attach_node()来附加的。 |
| 131 | + |
| 132 | +在函数of_attach_node()中,新的节点被附在实时树中给定的父节点的子节点上。但是,如 |
| 133 | +果父节点已经有了一个孩子,那么新节点就会取代当前的孩子,并将其变成其兄弟姐妹。因此, |
| 134 | +当测试案例的数据节点被连接到上面的实时树(图1)时,最终的结构如图3所示:: |
| 135 | + |
| 136 | + root ('/') |
| 137 | + | |
| 138 | + testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null |
| 139 | + | | | | | |
| 140 | + (...) | | | null |
| 141 | + | | child31 -> sibling32 -> null |
| 142 | + | | | | |
| 143 | + | | null null |
| 144 | + | | |
| 145 | + | child21 -> sibling22 -> sibling23 -> null |
| 146 | + | | | | |
| 147 | + | null null null |
| 148 | + | |
| 149 | + child11 -> sibling12 -> sibling13 -> sibling14 -> null |
| 150 | + | | | | |
| 151 | + null null | null |
| 152 | + | |
| 153 | + child131 -> null |
| 154 | + | |
| 155 | + null |
| 156 | + ----------------------------------------------------------------------- |
| 157 | + |
| 158 | + root ('/') |
| 159 | + | |
| 160 | + testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null |
| 161 | + | | | | | |
| 162 | + | (...) (...) (...) null |
| 163 | + | |
| 164 | + test-sibling3 -> test-sibling2 -> test-sibling1 -> test-child0 -> null |
| 165 | + | | | | |
| 166 | + null null null test-child01 |
| 167 | + |
| 168 | + |
| 169 | +Figure 3: 附加测试案例数据后的实时设备树结构。 |
| 170 | + |
| 171 | + |
| 172 | +聪明的读者会注意到,与先前的结构相比,test-child0节点成为最后一个兄弟姐妹(图2)。 |
| 173 | +在连接了第一个test-child0节点之后,又连接了test-sibling1节点,该节点推动子节点 |
| 174 | +(即test-child0)成为兄弟姐妹,并使自己成为子节点,如上所述。 |
| 175 | + |
| 176 | +如果发现一个重复的节点(即如果一个具有相同full_name属性的节点已经存在于实时树中), |
| 177 | +那么该节点不会被附加,而是通过调用函数update_node_properties()将其属性更新到活 |
| 178 | +树的节点中。 |
| 179 | + |
| 180 | + |
| 181 | +2.2. 删除测试数据 |
| 182 | +----------------- |
| 183 | + |
| 184 | +一旦测试用例执行完,selftest_data_remove被调用,以移除最初连接的设备节点(首先是 |
| 185 | +叶子节点被分离,然后向上移动父节点被移除,最后是整个树)。selftest_data_remove() |
| 186 | +调用detach_node_and_children(),使用of_detach_node()将节点从实时设备树上分离。 |
| 187 | + |
| 188 | +为了分离一个节点,of_detach_node()要么将给定节点的父节点的子节点指针更新为其同级节 |
| 189 | +点,要么根据情况将前一个同级节点附在给定节点的同级节点上。就这样吧。 :) |
0 commit comments