裝置樹覆蓋層說明

本文件描述了位於 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 中的變更集通知程式是另一種可能由應用或刪除覆蓋層觸發的通知程式。 不允許這些通知程式在覆蓋層或其內容中儲存指向裝置樹節點的指標。 當由於刪除覆蓋層而釋放包含覆蓋層的記憶體時,覆蓋層程式碼不會防止此類指標保持活動狀態。

任何保留指向覆蓋節點或資料的指標的其他程式碼都被認為是錯誤,因為刪除覆蓋層後,該指標將引用已釋放的記憶體。

覆蓋層的使用者必須特別注意系統上發生的整體操作,以確保其他核心程式碼不會保留指向覆蓋節點或資料的任何指標。 如果在應用覆蓋層後加載了驅動程式或子系統模組,並且該驅動程式或子系統掃描了整個裝置樹或其大部分,包括覆蓋節點,則可能會無意中使用此類指標。