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