109d4466dSYanteng Si.. SPDX-License-Identifier: GPL-2.0
209d4466dSYanteng Si.. include:: ../disclaimer-zh_CN.rst
309d4466dSYanteng Si
4*e13ce769SMauro Carvalho Chehab:Original: Documentation/devicetree/of_unittest.rst
509d4466dSYanteng Si
609d4466dSYanteng Si:翻译:
709d4466dSYanteng Si
809d4466dSYanteng Si 司延腾 Yanteng Si <siyanteng@loongson.cn>
909d4466dSYanteng Si
1009d4466dSYanteng Si:校译:
1109d4466dSYanteng Si
1209d4466dSYanteng Si=================================
1309d4466dSYanteng SiOpen Firmware Devicetree 单元测试
1409d4466dSYanteng Si=================================
1509d4466dSYanteng Si
1609d4466dSYanteng Si作者: Gaurav Minocha <gaurav.minocha.os@gmail.com>
1709d4466dSYanteng Si
1809d4466dSYanteng Si1. 概述
1909d4466dSYanteng Si=======
2009d4466dSYanteng Si
2109d4466dSYanteng Si本文档解释了执行 OF 单元测试所需的测试数据是如何动态地附加到实时树上的,与机器的架构无关。
2209d4466dSYanteng Si
2309d4466dSYanteng Si建议在继续读下去之前,先阅读以下文件。
2409d4466dSYanteng Si
2509d4466dSYanteng Si(1) Documentation/devicetree/usage-model.rst
2609d4466dSYanteng Si(2) http://www.devicetree.org/Device_Tree_Usage
2709d4466dSYanteng Si
2809d4466dSYanteng SiOF Selftest被设计用来测试提供给设备驱动开发者的接口(include/linux/of.h),以从未扁平
2909d4466dSYanteng Si化的设备树数据结构中获取设备信息等。这个接口被大多数设备驱动在各种使用情况下使用。
3009d4466dSYanteng Si
3109d4466dSYanteng Si
3209d4466dSYanteng Si2. 测试数据
3309d4466dSYanteng Si===========
3409d4466dSYanteng Si
3509d4466dSYanteng Si设备树源文件(drivers/of/unittest-data/testcases.dts)包含执行drivers/of/unittest.c
3609d4466dSYanteng Si中自动化单元测试所需的测试数据。目前,以下设备树源包含文件(.dtsi)被包含在testcases.dt中::
3709d4466dSYanteng Si
3809d4466dSYanteng Si    drivers/of/unittest-data/tests-interrupts.dtsi
3909d4466dSYanteng Si    drivers/of/unittest-data/tests-platform.dtsi
4009d4466dSYanteng Si    drivers/of/unittest-data/tests-phandle.dtsi
4109d4466dSYanteng Si    drivers/of/unittest-data/tests-match.dtsi
4209d4466dSYanteng Si
4309d4466dSYanteng Si当内核在启用OF_SELFTEST的情况下被构建时,那么下面的make规则::
4409d4466dSYanteng Si
4509d4466dSYanteng Si    $(obj)/%.dtb: $(src)/%.dts FORCE
4609d4466dSYanteng Si	    $(call if_changed_dep, dtc)
4709d4466dSYanteng Si
4809d4466dSYanteng Si用于将DT源文件(testcases.dts)编译成二进制blob(testcases.dtb),也被称为扁平化的DT。
4909d4466dSYanteng Si
5009d4466dSYanteng Si之后,使用以下规则将上述二进制blob包装成一个汇编文件(testcases.dtb.S)::
5109d4466dSYanteng Si
5209d4466dSYanteng Si    $(obj)/%.dtb.S: $(obj)/%.dtb
5309d4466dSYanteng Si	    $(call cmd, dt_S_dtb)
5409d4466dSYanteng Si
5509d4466dSYanteng Si汇编文件被编译成一个对象文件(testcases.dtb.o),并被链接到内核镜像中。
5609d4466dSYanteng Si
5709d4466dSYanteng Si
5809d4466dSYanteng Si2.1. 添加测试数据
5909d4466dSYanteng Si-----------------
6009d4466dSYanteng Si
6109d4466dSYanteng Si未扁平化的设备树结构体:
6209d4466dSYanteng Si
6309d4466dSYanteng Si未扁平化的设备树由连接的设备节点组成,其树状结构形式如下所述::
6409d4466dSYanteng Si
6509d4466dSYanteng Si    // following struct members are used to construct the tree
6609d4466dSYanteng Si    struct device_node {
6709d4466dSYanteng Si	...
6809d4466dSYanteng Si	struct  device_node *parent;
6909d4466dSYanteng Si	struct  device_node *child;
7009d4466dSYanteng Si	struct  device_node *sibling;
7109d4466dSYanteng Si	...
7209d4466dSYanteng Si    };
7309d4466dSYanteng Si
7409d4466dSYanteng Si图1描述了一个机器的未扁平化设备树的通用结构,只考虑了子节点和同级指针。存在另一个指针,
7509d4466dSYanteng Si``*parent`` ,用于反向遍历该树。因此,在一个特定的层次上,子节点和所有的兄弟姐妹节点将
7609d4466dSYanteng Si有一个指向共同节点的父指针(例如,child1、sibling2、sibling3、sibling4的父指针指向
7709d4466dSYanteng Si根节点)::
7809d4466dSYanteng Si
7909d4466dSYanteng Si    root ('/')
8009d4466dSYanteng Si    |
8109d4466dSYanteng Si    child1 -> sibling2 -> sibling3 -> sibling4 -> null
8209d4466dSYanteng Si    |         |           |           |
8309d4466dSYanteng Si    |         |           |          null
8409d4466dSYanteng Si    |         |           |
8509d4466dSYanteng Si    |         |        child31 -> sibling32 -> null
8609d4466dSYanteng Si    |         |           |          |
8709d4466dSYanteng Si    |         |          null       null
8809d4466dSYanteng Si    |         |
8909d4466dSYanteng Si    |      child21 -> sibling22 -> sibling23 -> null
9009d4466dSYanteng Si    |         |          |            |
9109d4466dSYanteng Si    |        null       null         null
9209d4466dSYanteng Si    |
9309d4466dSYanteng Si    child11 -> sibling12 -> sibling13 -> sibling14 -> null
9409d4466dSYanteng Si    |           |           |            |
9509d4466dSYanteng Si    |           |           |           null
9609d4466dSYanteng Si    |           |           |
9709d4466dSYanteng Si    null        null       child131 -> null
9809d4466dSYanteng Si			    |
9909d4466dSYanteng Si			    null
10009d4466dSYanteng Si
10109d4466dSYanteng SiFigure 1: 未扁平化的设备树的通用结构
10209d4466dSYanteng Si
10309d4466dSYanteng Si
10409d4466dSYanteng Si在执行OF单元测试之前,需要将测试数据附加到机器的设备树上(如果存在)。因此,当调用
10509d4466dSYanteng Siselftest_data_add()时,首先会读取通过以下内核符号链接到内核镜像中的扁平化设备树
10609d4466dSYanteng Si数据::
10709d4466dSYanteng Si
10809d4466dSYanteng Si    __dtb_testcases_begin - address marking the start of test data blob
10909d4466dSYanteng Si    __dtb_testcases_end   - address marking the end of test data blob
11009d4466dSYanteng Si
11109d4466dSYanteng Si其次,它调用of_fdt_unflatten_tree()来解除扁平化的blob。最后,如果机器的设备树
11209d4466dSYanteng Si(即实时树)是存在的,那么它将未扁平化的测试数据树附加到实时树上,否则它将自己作为
11309d4466dSYanteng Si实时设备树附加。
11409d4466dSYanteng Si
11509d4466dSYanteng Siattach_node_and_children()使用of_attach_node()将节点附加到实时树上,如下所
11609d4466dSYanteng Si述。为了解释这一点,图2中描述的测试数据树被附加到图1中描述的实时树上::
11709d4466dSYanteng Si
11809d4466dSYanteng Si    root ('/')
11909d4466dSYanteng Si	|
12009d4466dSYanteng Si    testcase-data
12109d4466dSYanteng Si	|
12209d4466dSYanteng Si    test-child0 -> test-sibling1 -> test-sibling2 -> test-sibling3 -> null
12309d4466dSYanteng Si	|               |                |                |
12409d4466dSYanteng Si    test-child01      null             null             null
12509d4466dSYanteng Si
12609d4466dSYanteng Si
12709d4466dSYanteng SiFigure 2: 将测试数据树附在实时树上的例子。
12809d4466dSYanteng Si
12909d4466dSYanteng Si根据上面的方案,实时树已经存在,所以不需要附加根('/')节点。所有其他节点都是通过在
13009d4466dSYanteng Si每个节点上调用of_attach_node()来附加的。
13109d4466dSYanteng Si
13209d4466dSYanteng Si在函数of_attach_node()中,新的节点被附在实时树中给定的父节点的子节点上。但是,如
13309d4466dSYanteng Si果父节点已经有了一个孩子,那么新节点就会取代当前的孩子,并将其变成其兄弟姐妹。因此,
13409d4466dSYanteng Si当测试案例的数据节点被连接到上面的实时树(图1)时,最终的结构如图3所示::
13509d4466dSYanteng Si
13609d4466dSYanteng Si    root ('/')
13709d4466dSYanteng Si    |
13809d4466dSYanteng Si    testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
13909d4466dSYanteng Si    |               |          |           |           |
14009d4466dSYanteng Si    (...)             |          |           |          null
14109d4466dSYanteng Si		    |          |         child31 -> sibling32 -> null
14209d4466dSYanteng Si		    |          |           |           |
14309d4466dSYanteng Si		    |          |          null        null
14409d4466dSYanteng Si		    |          |
14509d4466dSYanteng Si		    |        child21 -> sibling22 -> sibling23 -> null
14609d4466dSYanteng Si		    |          |           |            |
14709d4466dSYanteng Si		    |         null        null         null
14809d4466dSYanteng Si		    |
14909d4466dSYanteng Si		    child11 -> sibling12 -> sibling13 -> sibling14 -> null
15009d4466dSYanteng Si		    |          |            |            |
15109d4466dSYanteng Si		    null       null          |           null
15209d4466dSYanteng Si					    |
15309d4466dSYanteng Si					    child131 -> null
15409d4466dSYanteng Si					    |
15509d4466dSYanteng Si					    null
15609d4466dSYanteng Si    -----------------------------------------------------------------------
15709d4466dSYanteng Si
15809d4466dSYanteng Si    root ('/')
15909d4466dSYanteng Si    |
16009d4466dSYanteng Si    testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
16109d4466dSYanteng Si    |               |          |           |           |
16209d4466dSYanteng Si    |             (...)      (...)       (...)        null
16309d4466dSYanteng Si    |
16409d4466dSYanteng Si    test-sibling3 -> test-sibling2 -> test-sibling1 -> test-child0 -> null
16509d4466dSYanteng Si    |                |                   |                |
16609d4466dSYanteng Si    null             null                null         test-child01
16709d4466dSYanteng Si
16809d4466dSYanteng Si
16909d4466dSYanteng SiFigure 3: 附加测试案例数据后的实时设备树结构。
17009d4466dSYanteng Si
17109d4466dSYanteng Si
17209d4466dSYanteng Si聪明的读者会注意到,与先前的结构相比,test-child0节点成为最后一个兄弟姐妹(图2)。
17309d4466dSYanteng Si在连接了第一个test-child0节点之后,又连接了test-sibling1节点,该节点推动子节点
17409d4466dSYanteng Si(即test-child0)成为兄弟姐妹,并使自己成为子节点,如上所述。
17509d4466dSYanteng Si
17609d4466dSYanteng Si如果发现一个重复的节点(即如果一个具有相同full_name属性的节点已经存在于实时树中),
17709d4466dSYanteng Si那么该节点不会被附加,而是通过调用函数update_node_properties()将其属性更新到活
17809d4466dSYanteng Si树的节点中。
17909d4466dSYanteng Si
18009d4466dSYanteng Si
18109d4466dSYanteng Si2.2. 删除测试数据
18209d4466dSYanteng Si-----------------
18309d4466dSYanteng Si
18409d4466dSYanteng Si一旦测试用例执行完,selftest_data_remove被调用,以移除最初连接的设备节点(首先是
18509d4466dSYanteng Si叶子节点被分离,然后向上移动父节点被移除,最后是整个树)。selftest_data_remove()
18609d4466dSYanteng Si调用detach_node_and_children(),使用of_detach_node()将节点从实时设备树上分离。
18709d4466dSYanteng Si
18809d4466dSYanteng Si为了分离一个节点,of_detach_node()要么将给定节点的父节点的子节点指针更新为其同级节
18909d4466dSYanteng Si点,要么根据情况将前一个同级节点附在给定节点的同级节点上。就这样吧。 :)
190