Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GPL-2.0
0002 .. include:: ../disclaimer-zh_CN.rst
0003 
0004 :Original: Documentation/devicetree/of_unittest.rst
0005 
0006 :翻译:
0007 
0008  司延腾 Yanteng Si <siyanteng@loongson.cn>
0009 
0010 :校译:
0011 
0012 =================================
0013 Open Firmware Devicetree 单元测试
0014 =================================
0015 
0016 作者: Gaurav Minocha <gaurav.minocha.os@gmail.com>
0017 
0018 1. 概述
0019 =======
0020 
0021 本文档解释了执行 OF 单元测试所需的测试数据是如何动态地附加到实时树上的,与机器的架构无关。
0022 
0023 建议在继续读下去之前,先阅读以下文件。
0024 
0025 (1) Documentation/devicetree/usage-model.rst
0026 (2) http://www.devicetree.org/Device_Tree_Usage
0027 
0028 OF Selftest被设计用来测试提供给设备驱动开发者的接口(include/linux/of.h),以从未扁平
0029 化的设备树数据结构中获取设备信息等。这个接口被大多数设备驱动在各种使用情况下使用。
0030 
0031 
0032 2. 测试数据
0033 ===========
0034 
0035 设备树源文件(drivers/of/unittest-data/testcases.dts)包含执行drivers/of/unittest.c
0036 中自动化单元测试所需的测试数据。目前,以下设备树源包含文件(.dtsi)被包含在testcases.dt中::
0037 
0038     drivers/of/unittest-data/tests-interrupts.dtsi
0039     drivers/of/unittest-data/tests-platform.dtsi
0040     drivers/of/unittest-data/tests-phandle.dtsi
0041     drivers/of/unittest-data/tests-match.dtsi
0042 
0043 当内核在启用OF_SELFTEST的情况下被构建时,那么下面的make规则::
0044 
0045     $(obj)/%.dtb: $(src)/%.dts FORCE
0046             $(call if_changed_dep, dtc)
0047 
0048 用于将DT源文件(testcases.dts)编译成二进制blob(testcases.dtb),也被称为扁平化的DT。
0049 
0050 之后,使用以下规则将上述二进制blob包装成一个汇编文件(testcases.dtb.S)::
0051 
0052     $(obj)/%.dtb.S: $(obj)/%.dtb
0053             $(call cmd, dt_S_dtb)
0054 
0055 汇编文件被编译成一个对象文件(testcases.dtb.o),并被链接到内核镜像中。
0056 
0057 
0058 2.1. 添加测试数据
0059 -----------------
0060 
0061 未扁平化的设备树结构体:
0062 
0063 未扁平化的设备树由连接的设备节点组成,其树状结构形式如下所述::
0064 
0065     // following struct members are used to construct the tree
0066     struct device_node {
0067         ...
0068         struct  device_node *parent;
0069         struct  device_node *child;
0070         struct  device_node *sibling;
0071         ...
0072     };
0073 
0074 图1描述了一个机器的未扁平化设备树的通用结构,只考虑了子节点和同级指针。存在另一个指针,
0075 ``*parent`` ,用于反向遍历该树。因此,在一个特定的层次上,子节点和所有的兄弟姐妹节点将
0076 有一个指向共同节点的父指针(例如,child1、sibling2、sibling3、sibling4的父指针指向
0077 根节点)::
0078 
0079     root ('/')
0080     |
0081     child1 -> sibling2 -> sibling3 -> sibling4 -> null
0082     |         |           |           |
0083     |         |           |          null
0084     |         |           |
0085     |         |        child31 -> sibling32 -> null
0086     |         |           |          |
0087     |         |          null       null
0088     |         |
0089     |      child21 -> sibling22 -> sibling23 -> null
0090     |         |          |            |
0091     |        null       null         null
0092     |
0093     child11 -> sibling12 -> sibling13 -> sibling14 -> null
0094     |           |           |            |
0095     |           |           |           null
0096     |           |           |
0097     null        null       child131 -> null
0098                             |
0099                             null
0100 
0101 Figure 1: 未扁平化的设备树的通用结构
0102 
0103 
0104 在执行OF单元测试之前,需要将测试数据附加到机器的设备树上(如果存在)。因此,当调用
0105 selftest_data_add()时,首先会读取通过以下内核符号链接到内核镜像中的扁平化设备树
0106 数据::
0107 
0108     __dtb_testcases_begin - address marking the start of test data blob
0109     __dtb_testcases_end   - address marking the end of test data blob
0110 
0111 其次,它调用of_fdt_unflatten_tree()来解除扁平化的blob。最后,如果机器的设备树
0112 (即实时树)是存在的,那么它将未扁平化的测试数据树附加到实时树上,否则它将自己作为
0113 实时设备树附加。
0114 
0115 attach_node_and_children()使用of_attach_node()将节点附加到实时树上,如下所
0116 述。为了解释这一点,图2中描述的测试数据树被附加到图1中描述的实时树上::
0117 
0118     root ('/')
0119         |
0120     testcase-data
0121         |
0122     test-child0 -> test-sibling1 -> test-sibling2 -> test-sibling3 -> null
0123         |               |                |                |
0124     test-child01      null             null             null
0125 
0126 
0127 Figure 2: 将测试数据树附在实时树上的例子。
0128 
0129 根据上面的方案,实时树已经存在,所以不需要附加根('/')节点。所有其他节点都是通过在
0130 每个节点上调用of_attach_node()来附加的。
0131 
0132 在函数of_attach_node()中,新的节点被附在实时树中给定的父节点的子节点上。但是,如
0133 果父节点已经有了一个孩子,那么新节点就会取代当前的孩子,并将其变成其兄弟姐妹。因此,
0134 当测试案例的数据节点被连接到上面的实时树(图1)时,最终的结构如图3所示::
0135 
0136     root ('/')
0137     |
0138     testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
0139     |               |          |           |           |
0140     (...)             |          |           |          null
0141                     |          |         child31 -> sibling32 -> null
0142                     |          |           |           |
0143                     |          |          null        null
0144                     |          |
0145                     |        child21 -> sibling22 -> sibling23 -> null
0146                     |          |           |            |
0147                     |         null        null         null
0148                     |
0149                     child11 -> sibling12 -> sibling13 -> sibling14 -> null
0150                     |          |            |            |
0151                     null       null          |           null
0152                                             |
0153                                             child131 -> null
0154                                             |
0155                                             null
0156     -----------------------------------------------------------------------
0157 
0158     root ('/')
0159     |
0160     testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null
0161     |               |          |           |           |
0162     |             (...)      (...)       (...)        null
0163     |
0164     test-sibling3 -> test-sibling2 -> test-sibling1 -> test-child0 -> null
0165     |                |                   |                |
0166     null             null                null         test-child01
0167 
0168 
0169 Figure 3: 附加测试案例数据后的实时设备树结构。
0170 
0171 
0172 聪明的读者会注意到,与先前的结构相比,test-child0节点成为最后一个兄弟姐妹(图2)。
0173 在连接了第一个test-child0节点之后,又连接了test-sibling1节点,该节点推动子节点
0174 (即test-child0)成为兄弟姐妹,并使自己成为子节点,如上所述。
0175 
0176 如果发现一个重复的节点(即如果一个具有相同full_name属性的节点已经存在于实时树中),
0177 那么该节点不会被附加,而是通过调用函数update_node_properties()将其属性更新到活
0178 树的节点中。
0179 
0180 
0181 2.2. 删除测试数据
0182 -----------------
0183 
0184 一旦测试用例执行完,selftest_data_remove被调用,以移除最初连接的设备节点(首先是
0185 叶子节点被分离,然后向上移动父节点被移除,最后是整个树)。selftest_data_remove()
0186 调用detach_node_and_children(),使用of_detach_node()将节点从实时设备树上分离。
0187 
0188 为了分离一个节点,of_detach_node()要么将给定节点的父节点的子节点指针更新为其同级节
0189 点,要么根据情况将前一个同级节点附在给定节点的同级节点上。就这样吧。 :)