设备树覆盖层说明

本文档描述了位于 drivers/of/overlay.c 中的内核设备树覆盖层功能的实现,并且是 设备树动态解析器说明[1] 的配套文档。

覆盖层的工作原理

设备树覆盖层的目的是修改内核的实时树,并使修改影响内核的状态,从而反映这些更改。由于内核主要处理设备,因此任何产生活动设备的新设备节点都应在创建时创建,而如果设备节点被禁用或完全删除,则应注销受影响的设备。

让我们举例说明,我们有一个 foo 板,其基本树如下:

---- foo.dts ---------------------------------------------------------------
    /* FOO platform */
    /dts-v1/;
    / {
            compatible = "corp,foo";

            /* shared resources */
            res: res {
            };

            /* On chip peripherals */
            ocp: ocp {
                    /* peripherals that are always instantiated */
                    peripheral1 { ... };
            };
    };
---- foo.dts ---------------------------------------------------------------

覆盖层 bar.dtso,

---- bar.dtso - overlay target location by label ---------------------------
    /dts-v1/;
    /plugin/;
    &ocp {
            /* bar peripheral */
            bar {
                    compatible = "corp,bar";
                    ... /* various properties and child nodes */
            };
    };
---- bar.dtso --------------------------------------------------------------

加载时(并按照 [1] 中描述的方式解析)应产生 foo+bar.dts

---- foo+bar.dts -----------------------------------------------------------
    /* FOO platform + bar peripheral */
    / {
            compatible = "corp,foo";

            /* shared resources */
            res: res {
            };

            /* On chip peripherals */
            ocp: ocp {
                    /* peripherals that are always instantiated */
                    peripheral1 { ... };

                    /* bar peripheral */
                    bar {
                            compatible = "corp,bar";
                            ... /* various properties and child nodes */
                    };
            };
    };
---- foo+bar.dts -----------------------------------------------------------

由于覆盖层的存在,已创建了一个新的设备节点 (bar),因此将注册一个 bar 平台设备,如果加载了匹配的设备驱动程序,则将按预期创建该设备。

如果基本 DT 在编译时没有使用 -@ 选项,则“&ocp”标签将不可用于将覆盖节点解析到基本 DT 中的正确位置。在这种情况下,可以提供目标路径。 首选按标签语法指定目标位置,因为无论标签在 DT 中的哪个位置,覆盖层都可以应用于包含该标签的任何基本 DT。

以上 bar.dtso 示例修改为使用目标路径语法:

---- bar.dtso - overlay target location by explicit path -------------------
    /dts-v1/;
    /plugin/;
    &{/ocp} {
            /* bar peripheral */
            bar {
                    compatible = "corp,bar";
                    ... /* various properties and child nodes */
            }
    };
---- bar.dtso --------------------------------------------------------------

内核中的覆盖层 API

该 API 非常容易使用。

  1. 调用 of_overlay_fdt_apply() 以创建和应用覆盖层变更集。返回值是一个错误或用于标识此覆盖层的 Cookie。

  2. 调用 of_overlay_remove() 以删除和清理先前通过调用 of_overlay_fdt_apply() 创建的覆盖层变更集。 不允许删除由另一个覆盖层堆叠的覆盖层变更集。

最后,如果您需要一次性删除所有覆盖层,只需调用 of_overlay_remove_all(),它将按正确的顺序删除每一个覆盖层。

可以选择注册在覆盖层操作上调用的通知程序。 有关详细信息,请参阅 of_overlay_notifier_register/unregister 和枚举 of_overlay_notify_action。

OF_OVERLAY_PRE_APPLY、OF_OVERLAY_POST_APPLY 或 OF_OVERLAY_PRE_REMOVE 的通知程序回调可能会在覆盖层或其内容中存储指向设备树节点的指针,但这些指针不得在 OF_OVERLAY_POST_REMOVE 的通知程序回调之后继续存在。包含覆盖层的内存将在调用 OF_OVERLAY_POST_REMOVE 通知程序后 kfree()ed。请注意,即使 OF_OVERLAY_POST_REMOVE 的通知程序返回错误,也会 kfree()ed 内存。

drivers/of/dynamic.c 中的变更集通知程序是另一种可能由应用或删除覆盖层触发的通知程序。 不允许这些通知程序在覆盖层或其内容中存储指向设备树节点的指针。 当由于删除覆盖层而释放包含覆盖层的内存时,覆盖层代码不会防止此类指针保持活动状态。

任何保留指向覆盖节点或数据的指针的其他代码都被认为是错误,因为删除覆盖层后,该指针将引用已释放的内存。

覆盖层的用户必须特别注意系统上发生的整体操作,以确保其他内核代码不会保留指向覆盖节点或数据的任何指针。 如果在应用覆盖层后加载了驱动程序或子系统模块,并且该驱动程序或子系统扫描了整个设备树或其大部分,包括覆盖节点,则可能会无意中使用此类指针。